diff --git a/AUTHORS b/AUTHORS
index a448fc9..92071bd8 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -406,6 +406,7 @@
 Jitendra Kumar Sahoo <jitendra.ks@samsung.com>
 Joachim Bauch <jbauch@webrtc.org>
 Joachim Bauch <mail@joachim-bauch.de>
+Joanmarie Diggs <joanmarie.diggs@gmail.com>
 Joe Knoll <joe.knoll@workday.com>
 Joe Thomas <mhx348@motorola.com>
 Joel Stanley <joel@jms.id.au>
diff --git a/DEPS b/DEPS
index 6f15e20c..4bb68764 100644
--- a/DEPS
+++ b/DEPS
@@ -105,7 +105,7 @@
   # 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': 'a78b6dcb82d2f6c940e9c0a6bc14853f846344d0',
+  'skia_revision': '9f7d4cd62a0bf201c65aa11498594b8c1dc17107',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # 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': 'e452382a61a185577d561cc7807b437f4db32d90',
+  'angle_revision': '67c388e6c04ec35da3c72dd5fb3275a189c99fd1',
   # 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': '8584902d81ffabc06bb4895f558e375e5429fe72',
+  'pdfium_revision': 'b53ef1e52d40f586c401a7e3948259f8ebbfd3cc',
   # 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.
@@ -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': '0f2c4fec12728f0ebf98a6afa4f8a18f2a9b2a0b',
+  'catapult_revision': '65f883bb77390e3208346e653f3a518c3a63ded7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -564,7 +564,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'd795ab891c157bcda542f9cab5375805a19af7b0',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'b0e855a33353ca30a2ecb1c0e9084ca3ef26836a',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1034,7 +1034,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '21dbf06b5aa6c7dc8cf56314d4a3f96f57956c53',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '1bd66642c37083156c625578130dbed13f5fb32c',
+    Var('webrtc_git') + '/src.git' + '@' + '1899c1270f0ce4264c6a579c3d86f81ac0e98aea',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 5e71b48..6a72e23 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -2895,6 +2895,7 @@
   results.extend(_CheckWATCHLISTS(input_api, output_api))
   results.extend(input_api.RunTests(
     input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
+  results.extend(_CheckTranslationScreenshots(input_api, output_api))
 
   for f in input_api.AffectedFiles():
     path, name = input_api.os_path.split(f.LocalPath())
@@ -3344,3 +3345,178 @@
   results.extend(input_api.canned_checks.CheckChangeHasDescription(
       input_api, output_api))
   return results
+
+
+def _CheckTranslationScreenshots(input_api, output_api):
+  PART_FILE_TAG = "part"
+  import os
+  import sys
+  from io import StringIO
+
+  try:
+    old_sys_path = sys.path
+    sys.path = sys.path + [input_api.os_path.join(
+          input_api.PresubmitLocalPath(), 'tools', 'grit')]
+    import grit.grd_reader
+    import grit.node.message
+    import grit.util
+  finally:
+    sys.path = old_sys_path
+
+  def _GetGrdMessages(grd_path_or_string, dir_path='.'):
+    """Load the grd file and return a dict of message ids to messages.
+
+    Ignores any nested grdp files pointed by <part> tag.
+    """
+    doc = grit.grd_reader.Parse(grd_path_or_string, dir_path,
+        stop_after=None, first_ids_file=None,
+        debug=False, defines=None,
+        tags_to_ignore=set([PART_FILE_TAG]))
+    return {
+      msg.attrs['name']:msg for msg in doc.GetChildrenOfType(
+        grit.node.message.MessageNode)
+    }
+
+  def _GetGrdpMessagesFromString(grdp_string):
+    """Parses the contents of a grdp file given in grdp_string.
+
+    grd_reader can't parse grdp files directly. Instead, this creates a
+    temporary directory with a grd file pointing to the grdp file, and loads the
+    grd from there. Any nested grdp files (pointed by <part> tag) are ignored.
+    """
+    WRAPPER = """<?xml version="1.0" encoding="utf-8"?>
+    <grit latest_public_release="1" current_release="1">
+      <release seq="1">
+        <messages>
+          <part file="sub.grdp" />
+        </messages>
+      </release>
+    </grit>
+    """
+    with grit.util.TempDir({'main.grd': WRAPPER,
+                            'sub.grdp': grdp_string}) as temp_dir:
+      return _GetGrdMessages(temp_dir.GetPath('main.grd'), temp_dir.GetPath())
+
+  new_or_added_paths = set(f.LocalPath()
+      for f in input_api.AffectedFiles()
+      if (f.Action() == 'A' or f.Action() == 'M'))
+  removed_paths = set(f.LocalPath()
+      for f in input_api.AffectedFiles(include_deletes=True)
+      if f.Action() == 'D')
+
+  affected_grds = [f for f in input_api.AffectedFiles()
+      if (f.LocalPath().endswith('.grd') or
+          f.LocalPath().endswith('.grdp'))]
+  affected_png_paths = [f.AbsoluteLocalPath()
+      for f in input_api.AffectedFiles()
+      if (f.LocalPath().endswith('.png'))]
+
+  # Check for screenshots. Developers can upload screenshots using
+  # tools/translation/upload_screenshots.py which finds and uploads
+  # images associated with .grd files (e.g. test_grd/IDS_STRING.png for the
+  # message named IDS_STRING in test.grd) and produces a .sha1 file (e.g.
+  # test_grd/IDS_STRING.png.sha1) for each png when the upload is successful.
+  #
+  # The logic here is as follows:
+  #
+  # - If the CL has a .png file under the screenshots directory for a grd
+  #   file, warn the developer. Actual images should never be checked into the
+  #   Chrome repo.
+  #
+  # - If the CL contains modified or new messages in grd files and doesn't
+  #   contain the corresponding .sha1 files, warn the developer to add images
+  #   and upload them via tools/translation/upload_screenshots.py.
+  #
+  # - If the CL contains modified or new messages in grd files and the
+  #   corresponding .sha1 files, everything looks good.
+  #
+  # - If the CL contains removed messages in grd files but the corresponding
+  #   .sha1 files aren't removed, warn the developer to remove them.
+  unnecessary_screenshots = []
+  missing_sha1 = []
+  unnecessary_sha1_files = []
+
+
+  def _CheckScreenshotAdded(screenshots_dir, message_id):
+    sha1_path = input_api.os_path.join(
+        screenshots_dir, message_id + '.png.sha1')
+    if sha1_path not in new_or_added_paths:
+      missing_sha1.append(sha1_path)
+
+
+  def _CheckScreenshotRemoved(screenshots_dir, message_id):
+    sha1_path = input_api.os_path.join(
+        screenshots_dir, message_id + '.png.sha1')
+    if sha1_path not in removed_paths:
+      unnecessary_sha1_files.append(sha1_path)
+
+
+  for f in affected_grds:
+    file_path = f.LocalPath()
+    old_id_to_msg_map = {}
+    new_id_to_msg_map = {}
+    if file_path.endswith('.grdp'):
+      if f.OldContents():
+        old_id_to_msg_map = _GetGrdpMessagesFromString(
+          unicode('\n'.join(f.OldContents())))
+      if f.NewContents():
+        new_id_to_msg_map = _GetGrdpMessagesFromString(
+          unicode('\n'.join(f.NewContents())))
+    else:
+      if f.OldContents():
+        old_id_to_msg_map = _GetGrdMessages(
+          StringIO(unicode('\n'.join(f.OldContents()))))
+      if f.NewContents():
+        new_id_to_msg_map = _GetGrdMessages(
+          StringIO(unicode('\n'.join(f.NewContents()))))
+
+    # Compute added, removed and modified message IDs.
+    old_ids = set(old_id_to_msg_map)
+    new_ids = set(new_id_to_msg_map)
+    added_ids = new_ids - old_ids
+    removed_ids = old_ids - new_ids
+    modified_ids = set([])
+    for key in old_ids.intersection(new_ids):
+      if (old_id_to_msg_map[key].FormatXml()
+          != new_id_to_msg_map[key].FormatXml()):
+        modified_ids.add(key)
+
+    grd_name, ext = input_api.os_path.splitext(
+        input_api.os_path.basename(file_path))
+    screenshots_dir = input_api.os_path.join(
+        input_api.os_path.dirname(file_path), grd_name + ext.replace('.', '_'))
+
+    # Check the screenshot directory for .png files. Warn if there is any.
+    for png_path in affected_png_paths:
+      if png_path.startswith(screenshots_dir):
+        unnecessary_screenshots.append(png_path)
+
+    for added_id in added_ids:
+      _CheckScreenshotAdded(screenshots_dir, added_id)
+
+    for modified_id in modified_ids:
+      _CheckScreenshotAdded(screenshots_dir, modified_id)
+
+    for removed_id in removed_ids:
+      _CheckScreenshotRemoved(screenshots_dir, removed_id)
+
+  results = []
+  if unnecessary_screenshots:
+    results.append(output_api.PresubmitNotifyResult(
+      'Do not include actual screenshots in the changelist. Run '
+      'tools/translate/upload_screenshots.py to upload them instead:',
+      sorted(unnecessary_screenshots)))
+
+  if missing_sha1:
+    results.append(output_api.PresubmitNotifyResult(
+      'You are adding or modifying UI strings.\n'
+      'To ensure the best translations, take screenshots of the relevant UI '
+      '(https://g.co/chrome/translation) and add these files to your '
+      'changelist:', sorted(missing_sha1)))
+
+  if unnecessary_sha1_files:
+    results.append(output_api.PresubmitNotifyResult(
+      'You removed strings associated with these files. Remove:',
+      sorted(unnecessary_sha1_files)))
+
+  return results
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py
index e5eb2ec..f1be4edea 100755
--- a/PRESUBMIT_test.py
+++ b/PRESUBMIT_test.py
@@ -1844,5 +1844,162 @@
     self.assertEqual(0, len(results))
 
 
+class TranslationScreenshotsTest(unittest.TestCase):
+  # An empty grd file.
+  OLD_GRD_CONTENTS = """<?xml version="1.0" encoding="UTF-8"?>
+           <grit latest_public_release="1" current_release="1">
+             <release seq="1">
+               <messages></messages>
+             </release>
+           </grit>
+        """.splitlines()
+  # A grd file with a single message.
+  NEW_GRD_CONTENTS1 = """<?xml version="1.0" encoding="UTF-8"?>
+           <grit latest_public_release="1" current_release="1">
+             <release seq="1">
+               <messages>
+                 <message name="IDS_TEST1">
+                   Test string 1
+                 </message>
+               </messages>
+             </release>
+           </grit>
+        """.splitlines()
+  # A grd file with two messages.
+  NEW_GRD_CONTENTS2 = """<?xml version="1.0" encoding="UTF-8"?>
+           <grit latest_public_release="1" current_release="1">
+             <release seq="1">
+               <messages>
+                 <message name="IDS_TEST1">
+                   Test string 1
+                 </message>
+                 <message name="IDS_TEST2">
+                   Test string 2
+                 </message>
+               </messages>
+             </release>
+           </grit>
+        """.splitlines()
+
+  DO_NOT_UPLOAD_PNG_MESSAGE = ('Do not include actual screenshots in the '
+                               'changelist. Run '
+                               'tools/translate/upload_screenshots.py to '
+                               'upload them instead:')
+  GENERATE_SIGNATURES_MESSAGE = ('You are adding or modifying UI strings.\n'
+                                 'To ensure the best translations, take '
+                                 'screenshots of the relevant UI '
+                                 '(https://g.co/chrome/translation) and add '
+                                 'these files to your changelist:')
+  REMOVE_SIGNATURES_MESSAGE = ('You removed strings associated with these '
+                               'files. Remove:')
+
+  def makeInputApi(self, files):
+    input_api = MockInputApi()
+    input_api.files = files
+    return input_api
+
+  def testNoScreenshots(self):
+    # CL modified and added messages, but didn't add any screenshots.
+    input_api = self.makeInputApi([
+      MockAffectedFile('test.grd', self.NEW_GRD_CONTENTS2,
+                       self.OLD_GRD_CONTENTS, action='M')])
+    warnings = PRESUBMIT._CheckTranslationScreenshots(input_api,
+                                                      MockOutputApi())
+    self.assertEqual(1, len(warnings))
+    self.assertEqual(self.GENERATE_SIGNATURES_MESSAGE, warnings[0].message)
+    self.assertEqual(
+      ['test_grd/IDS_TEST1.png.sha1', 'test_grd/IDS_TEST2.png.sha1'],
+      warnings[0].items)
+
+    input_api = self.makeInputApi([
+      MockAffectedFile('test.grd', self.NEW_GRD_CONTENTS2,
+                       self.NEW_GRD_CONTENTS1, action='M')])
+    warnings = PRESUBMIT._CheckTranslationScreenshots(input_api,
+                                                      MockOutputApi())
+    self.assertEqual(1, len(warnings))
+    self.assertEqual(self.GENERATE_SIGNATURES_MESSAGE, warnings[0].message)
+    self.assertEqual(['test_grd/IDS_TEST2.png.sha1'], warnings[0].items)
+
+
+  def testUnnecessaryScreenshots(self):
+    # CL added a single message and added the png file, but not the sha1 file.
+    input_api = self.makeInputApi([
+      MockAffectedFile('test.grd', self.NEW_GRD_CONTENTS1,
+                       self.OLD_GRD_CONTENTS, action='M'),
+      MockAffectedFile('test_grd/IDS_TEST1.png', 'binary', action='A')])
+    warnings = PRESUBMIT._CheckTranslationScreenshots(input_api,
+                                                      MockOutputApi())
+    self.assertEqual(2, len(warnings))
+    self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
+    self.assertEqual(['test_grd/IDS_TEST1.png'], warnings[0].items)
+    self.assertEqual(self.GENERATE_SIGNATURES_MESSAGE, warnings[1].message)
+    self.assertEqual(['test_grd/IDS_TEST1.png.sha1'], warnings[1].items)
+
+    # CL added two messages, one has a png. Expect two messages:
+    # - One for the unnecessary png.
+    # - Another one for missing .sha1 files.
+    input_api = self.makeInputApi([
+      MockAffectedFile('test.grd', self.NEW_GRD_CONTENTS2,
+                       self.OLD_GRD_CONTENTS, action='M'),
+      MockAffectedFile('test_grd/IDS_TEST1.png', 'binary', action='A')])
+    warnings = PRESUBMIT._CheckTranslationScreenshots(input_api,
+                                                      MockOutputApi())
+    self.assertEqual(2, len(warnings))
+    self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
+    self.assertEqual(['test_grd/IDS_TEST1.png'], warnings[0].items)
+    self.assertEqual(self.GENERATE_SIGNATURES_MESSAGE, warnings[1].message)
+    self.assertEqual(['test_grd/IDS_TEST1.png.sha1',
+                      'test_grd/IDS_TEST2.png.sha1'], warnings[1].items)
+
+  def testScreenshotsWithSha1(self):
+    # CL added two messages and their corresponding .sha1 files. No warnings.
+    input_api = self.makeInputApi([
+      MockAffectedFile('test.grd', self.NEW_GRD_CONTENTS2,
+                       self.OLD_GRD_CONTENTS, action='M'),
+      MockFile('test_grd/IDS_TEST1.png.sha1', 'binary', action='A'),
+      MockFile('test_grd/IDS_TEST2.png.sha1', 'binary', action='A')])
+    warnings = PRESUBMIT._CheckTranslationScreenshots(input_api,
+                                                      MockOutputApi())
+    self.assertEqual([], warnings)
+
+  def testScreenshotsRemovedWithSha1(self):
+    # Swap old contents with new contents, remove IDS_TEST1 and IDS_TEST2. The
+    # sha1 files associated with the messages should also be removed by the CL.
+    input_api = self.makeInputApi([
+      MockAffectedFile('test.grd', self.OLD_GRD_CONTENTS,
+                       self.NEW_GRD_CONTENTS2, action='M'),
+      MockFile('test_grd/IDS_TEST1.png.sha1', 'binary', ""),
+      MockFile('test_grd/IDS_TEST2.png.sha1', 'binary', "")])
+    warnings = PRESUBMIT._CheckTranslationScreenshots(input_api,
+                                                      MockOutputApi())
+    self.assertEqual(1, len(warnings))
+    self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
+    self.assertEqual(['test_grd/IDS_TEST1.png.sha1',
+                      'test_grd/IDS_TEST2.png.sha1'], warnings[0].items)
+
+    # Same as above, but this time one of the .sha1 files is removed.
+    input_api = self.makeInputApi([
+      MockAffectedFile('test.grd', self.OLD_GRD_CONTENTS,
+                       self.NEW_GRD_CONTENTS2, action='M'),
+      MockFile('test_grd/IDS_TEST1.png.sha1', 'binary', ''),
+      MockAffectedFile('test_grd/IDS_TEST2.png.sha1',
+                       '', 'old_contents', action='D')])
+    warnings = PRESUBMIT._CheckTranslationScreenshots(input_api,
+                                                      MockOutputApi())
+    self.assertEqual(1, len(warnings))
+    self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
+    self.assertEqual(['test_grd/IDS_TEST1.png.sha1'], warnings[0].items)
+
+    # Remove both sha1 files. No presubmit warnings.
+    input_api = self.makeInputApi([
+      MockAffectedFile('test.grd', self.OLD_GRD_CONTENTS,
+                       self.NEW_GRD_CONTENTS2, action='M'),
+      MockFile('test_grd/IDS_TEST1.png.sha1', 'binary', action='D'),
+      MockFile('test_grd/IDS_TEST2.png.sha1', 'binary', action='D')])
+    warnings = PRESUBMIT._CheckTranslationScreenshots(input_api,
+                                                      MockOutputApi())
+    self.assertEqual([], warnings)
+
+
 if __name__ == '__main__':
   unittest.main()
diff --git a/WATCHLISTS b/WATCHLISTS
index d46b0af..2963302c5 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1989,8 +1989,7 @@
     'chrome_cleaner': ['csharp+watch@chromium.org',
                        'ftirelo+watch@chromium.org',
                        'joenotcharles+watch@chromium.org'],
-    'chrome_elf': ['caitkp+watch@chromium.org',
-                   'pennymac+watch@chromium.org'],
+    'chrome_elf': ['caitkp+watch@chromium.org'],
     'chrome_grc': ['chrome-grc-reviews@chromium.org'],
     'chrome_views': ['tfarina@chromium.org'],
     'chromecast': ['alokp+watch@chromium.org',
@@ -2119,7 +2118,6 @@
     'installer_linux': ['mmoss@chromium.org',
                         'raphael.kubo.da.costa@intel.com'],
     'installer_win': ['grt+watch@chromium.org',
-                      'pennymac+watch@chromium.org',
                       'wfh+watch@chromium.org'],
     'instant': ['dcblack@chromium.org',
                 'donnd+watch@chromium.org',
@@ -2374,8 +2372,7 @@
                          'markusheintz@chromium.org',
                          'msramek+watch@chromium.org',
                          'raymes+watch@chromium.org'],
-    'windows_sandboxing': ['pennymac+watch@chromium.org',
-                           'wfh+watch@chromium.org'],
+    'windows_sandboxing': ['wfh+watch@chromium.org'],
     'x11': ['derat+watch@chromium.org',
             'sadrul@chromium.org',
             'yusukes+watch@chromium.org'],
diff --git a/ash/ash_service.cc b/ash/ash_service.cc
index 5d01683..98a398ad 100644
--- a/ash/ash_service.cc
+++ b/ash/ash_service.cc
@@ -173,8 +173,7 @@
 
   ShellInitParams shell_init_params;
   shell_init_params.shell_port = std::make_unique<ash::ShellPortClassic>();
-  shell_init_params.delegate =
-      std::make_unique<ShellDelegateMash>(context()->connector());
+  shell_init_params.delegate = std::make_unique<ShellDelegateMash>();
   shell_init_params.context_factory = context_factory_.get();
   shell_init_params.context_factory_private =
       context_factory_->GetContextFactoryPrivate();
diff --git a/ash/dbus/display_service_provider.cc b/ash/dbus/display_service_provider.cc
index 6f63026..52a0955b 100644
--- a/ash/dbus/display_service_provider.cc
+++ b/ash/dbus/display_service_provider.cc
@@ -9,7 +9,6 @@
 #include "ash/public/interfaces/ash_display_controller.mojom.h"
 #include "ash/public/interfaces/constants.mojom.h"
 #include "ash/shell.h"
-#include "ash/shell_delegate.h"
 #include "ash/wm/screen_dimmer.h"
 #include "base/bind.h"
 #include "base/callback.h"
@@ -56,8 +55,8 @@
 bool DisplayServiceProvider::Impl::Connect() {
   if (ash_display_controller_)
     return true;
-  Shell::Get()->shell_delegate()->GetShellConnector()->BindInterface(
-      mojom::kServiceName, &ash_display_controller_);
+  Shell::Get()->connector()->BindInterface(mojom::kServiceName,
+                                           &ash_display_controller_);
   return !!ash_display_controller_;
 }
 
diff --git a/ash/login/login_screen_controller.cc b/ash/login/login_screen_controller.cc
index 44c719a..7f52f9a 100644
--- a/ash/login/login_screen_controller.cc
+++ b/ash/login/login_screen_controller.cc
@@ -315,11 +315,16 @@
   }
 }
 
-void LoginScreenController::SetUserList(
-    std::vector<mojom::LoginUserInfoPtr> users) {
+void LoginScreenController::LoadUsers(
+    std::vector<mojom::LoginUserInfoPtr> users,
+    bool show_guest) {
   DCHECK(DataDispatcher());
 
   DataDispatcher()->NotifyUsers(users);
+  Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
+      ->shelf_widget()
+      ->login_shelf_view()
+      ->SetAllowLoginAsGuest(show_guest);
 }
 
 void LoginScreenController::SetPinEnabledForUser(const AccountId& account_id,
@@ -409,19 +414,11 @@
       ->SetKioskApps(std::move(kiosk_apps));
 }
 
-void LoginScreenController::NotifyOobeDialogState(
-    mojom::OobeDialogState state) {
+void LoginScreenController::NotifyOobeDialogVisibility(bool visible) {
   Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
       ->shelf_widget()
       ->login_shelf_view()
-      ->SetLoginDialogState(state);
-}
-
-void LoginScreenController::SetAllowLoginAsGuest(bool allow_guest) {
-  Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
-      ->shelf_widget()
-      ->login_shelf_view()
-      ->SetAllowLoginAsGuest(allow_guest);
+      ->SetLoginDialogVisible(visible);
 }
 
 void LoginScreenController::SetAddUserButtonEnabled(bool enable) {
diff --git a/ash/login/login_screen_controller.h b/ash/login/login_screen_controller.h
index dff21e0..3aa7d02 100644
--- a/ash/login/login_screen_controller.h
+++ b/ash/login/login_screen_controller.h
@@ -111,7 +111,8 @@
   void SetAuthType(const AccountId& account_id,
                    proximity_auth::mojom::AuthType auth_type,
                    const base::string16& initial_value) override;
-  void SetUserList(std::vector<mojom::LoginUserInfoPtr> users) override;
+  void LoadUsers(std::vector<mojom::LoginUserInfoPtr> users,
+                 bool show_guest) override;
   void SetPinEnabledForUser(const AccountId& account_id,
                             bool is_enabled) override;
   void SetAvatarForUser(const AccountId& account_id,
@@ -138,9 +139,8 @@
   void SetFingerprintUnlockState(const AccountId& account_id,
                                  mojom::FingerprintUnlockState state) override;
   void SetKioskApps(std::vector<mojom::KioskAppInfoPtr> kiosk_apps) override;
-  void NotifyOobeDialogState(mojom::OobeDialogState state) override;
+  void NotifyOobeDialogVisibility(bool is_visible) override;
   void SetAddUserButtonEnabled(bool enable) override;
-  void SetAllowLoginAsGuest(bool allow_guest) override;
 
   // Flushes the mojo pipes - to be used in tests.
   void FlushForTesting();
diff --git a/ash/login/ui/image_parser.cc b/ash/login/ui/image_parser.cc
index 9ddfc9d..9377654 100644
--- a/ash/login/ui/image_parser.cc
+++ b/ash/login/ui/image_parser.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "ash/shell.h"
-#include "ash/shell_delegate.h"
 #include "ipc/ipc_channel.h"
 #include "services/data_decoder/public/cpp/decode_image.h"
 
@@ -40,9 +39,9 @@
   // also goes through libpng, but APNG support is handled specifically by
   // blink's PNGImageReader.cpp.
   data_decoder::DecodeAnimation(
-      Shell::Get()->shell_delegate()->GetShellConnector(), image_data,
-      true /*shrink_to_fit*/, kMaxImageSizeInBytes,
+      Shell::Get()->connector(), image_data, true /*shrink_to_fit*/,
+      kMaxImageSizeInBytes,
       base::Bind(&ConvertToAnimationFrame, Passed(&on_decoded)));
 }
 
-}  // namespace ash
\ No newline at end of file
+}  // namespace ash
diff --git a/ash/public/interfaces/login_screen.mojom b/ash/public/interfaces/login_screen.mojom
index 08df062..2b9c593 100644
--- a/ash/public/interfaces/login_screen.mojom
+++ b/ash/public/interfaces/login_screen.mojom
@@ -12,33 +12,6 @@
 import "mojo/public/mojom/base/string16.mojom";
 import "mojo/public/mojom/base/time.mojom";
 
-// State of the Oobe UI dialog.
-enum OobeDialogState {
-  // Oobe UI dialog is currently hidden.
-  HIDDEN,
-
-  // Showing gaia signin screen.
-  GAIA_SIGNIN,
-
-  // Showing wrong hardware identification screen.
-  WRONG_HWID_WARNING,
-
-  // Showing supervised user creation screen.
-  SUPERVISED_USER_CREATION_FLOW,
-
-  // Showing SAML password confirmation screen.
-  SAML_PASSWORD_CONFIRM,
-
-  // Showing password changed screen.
-  PASSWORD_CHANGED,
-
-  // Showing device enrollment screen.
-  ENROLLMENT,
-
-  // Showing error screen.
-  ERROR,
-};
-
 // Allows clients (e.g. Chrome browser) to control the ash login/lock/user-add
 // screens.
 interface LoginScreen {
@@ -86,9 +59,10 @@
               proximity_auth.mojom.AuthType auth_type,
               mojo_base.mojom.String16 initial_value);
 
-  // Set the users who are displayed on the login UI. |users| is filtered
-  // and does not correspond to every user on the device.
-  SetUserList(array<LoginUserInfo> users);
+  // Requests to load users in the lock screen.
+  // |users|:      A list of users who can unlock the device.
+  // |show_guest|: Whether to show guest session button.
+  LoadUsers(array<LoginUserInfo> users, bool show_guest);
 
   // Notification if pin is enabled or disabled for the given user.
   // |account_id|:   The account id of the user in the user pod.
@@ -156,17 +130,13 @@
   // Update the kiosk app data for the login screen.
   SetKioskApps(array<KioskAppInfo> kiosk_apps);
 
-  // Called when the dialog hosting oobe has changed state. The oobe dialog
+  // Called when the dialog hosting oobe has changed visibility. The oobe dialog
   // provides support for any part of login that is implemented in JS/HTML, such
   // as add user or powerwash.
-  NotifyOobeDialogState(OobeDialogState state);
+  NotifyOobeDialogVisibility(bool is_visible);
 
   // Sets whether users can be added from the login screen.
   SetAddUserButtonEnabled(bool enable);
-
-  // Sets if the guest button on the login shelf can be shown. Even if set to
-  // true the button may still not be visible.
-  SetAllowLoginAsGuest(bool allow_guest);
 };
 
 // Allows ash lock screen to control a client (e.g. Chrome browser). Requests
diff --git a/ash/shelf/login_shelf_view.cc b/ash/shelf/login_shelf_view.cc
index cfa2f6e..1cab347b 100644
--- a/ash/shelf/login_shelf_view.cc
+++ b/ash/shelf/login_shelf_view.cc
@@ -410,8 +410,8 @@
   UpdateUi();
 }
 
-void LoginShelfView::SetLoginDialogState(mojom::OobeDialogState state) {
-  dialog_state_ = state;
+void LoginShelfView::SetLoginDialogVisible(bool visible) {
+  dialog_visible_ = visible;
   UpdateUi();
 }
 
@@ -478,33 +478,12 @@
   // TODO(agawronska): Implement full list of conditions for buttons visibility,
   // when views based shelf if enabled during OOBE. https://crbug.com/798869
   bool is_login_primary = (session_state == SessionState::LOGIN_PRIMARY);
-  bool dialog_visible = dialog_state_ != mojom::OobeDialogState::HIDDEN;
-
-  // Show guest button if:
-  // 1. It's in login screen.
-  // 2. Guest login is allowed.
-  // 3. OOBE UI dialog is not currently showing wrong HWID warning screen or
-  // SAML password confirmation screen.
   GetViewByID(kBrowseAsGuest)
-      ->SetVisible(
-          allow_guest_ &&
-          dialog_state_ != mojom::OobeDialogState::WRONG_HWID_WARNING &&
-          dialog_state_ != mojom::OobeDialogState::SAML_PASSWORD_CONFIRM &&
-          is_login_primary);
-
-  // Show add user button when it's in login screen and OobeUI dialog is not
-  // visible.
-  GetViewByID(kAddUser)->SetVisible(!dialog_visible && is_login_primary);
-
-  // Show kiosk apps button if:
-  // 1. It's in login screen.
-  // 2. There're Kiosk apps availble.
-  // 3. Oobe UI dialog is not visible or is currently showing gaia signin
-  // screen.
+      ->SetVisible(allow_guest_ && !dialog_visible_ && is_login_primary);
+  GetViewByID(kAddUser)->SetVisible(!dialog_visible_ && is_login_primary);
   kiosk_apps_button_->SetVisible(
-      (!dialog_visible ||
-       dialog_state_ == mojom::OobeDialogState::GAIA_SIGNIN) &&
-      kiosk_apps_button_->HasApps() && is_login_primary);
+      !dialog_visible_ && kiosk_apps_button_->HasApps() && is_login_primary);
+
   Layout();
 }
 
diff --git a/ash/shelf/login_shelf_view.h b/ash/shelf/login_shelf_view.h
index 68e92bd..5e7ddbe 100644
--- a/ash/shelf/login_shelf_view.h
+++ b/ash/shelf/login_shelf_view.h
@@ -10,7 +10,6 @@
 #include "ash/ash_export.h"
 #include "ash/lock_screen_action/lock_screen_action_background_observer.h"
 #include "ash/public/interfaces/kiosk_app_info.mojom.h"
-#include "ash/public/interfaces/login_screen.mojom.h"
 #include "ash/shutdown_controller.h"
 #include "ash/tray_action/tray_action_observer.h"
 #include "base/scoped_observer.h"
@@ -64,8 +63,9 @@
   // Sets the list of kiosk apps that can be launched from the login shelf.
   void SetKioskApps(std::vector<mojom::KioskAppInfoPtr> kiosk_apps);
 
-  // Sets the state of the login dialog.
-  void SetLoginDialogState(mojom::OobeDialogState state);
+  // Sets if the login dialog is visible. This hides some of the buttons on the
+  // LoginShelf.
+  void SetLoginDialogVisible(bool visible);
 
   // Sets if the guest button on the login shelf can be shown. Even if set to
   // true the button may still not be visible.
@@ -101,7 +101,7 @@
   // policy updates, session state changes etc.
   void UpdateUi();
 
-  mojom::OobeDialogState dialog_state_ = mojom::OobeDialogState::HIDDEN;
+  bool dialog_visible_ = false;
   bool allow_guest_ = true;
 
   LockScreenActionBackgroundController* lock_screen_action_background_;
diff --git a/ash/shelf/login_shelf_view_unittest.cc b/ash/shelf/login_shelf_view_unittest.cc
index 0b71fd8e..a15cdea 100644
--- a/ash/shelf/login_shelf_view_unittest.cc
+++ b/ash/shelf/login_shelf_view_unittest.cc
@@ -291,68 +291,23 @@
 
   // However, SetAllowLoginAsGuest(true) does not mean that the guest button is
   // always visible.
-  login_shelf_view_->SetLoginDialogState(
-      mojom::OobeDialogState::SAML_PASSWORD_CONFIRM);
+  login_shelf_view_->SetLoginDialogVisible(true);
   EXPECT_TRUE(ShowsShelfButtons({LoginShelfView::kShutdown}));
 }
 
-TEST_F(LoginShelfViewTest, ShouldUpdateUiAfterDialogStateChange) {
+TEST_F(LoginShelfViewTest, ShouldUpdateUiAfterDialogVisibilityChange) {
   NotifySessionStateChanged(SessionState::LOGIN_PRIMARY);
   EXPECT_TRUE(ShowsShelfButtons({LoginShelfView::kShutdown,
                                  LoginShelfView::kBrowseAsGuest,
                                  LoginShelfView::kAddUser}));
 
-  // Add user button is always hidden if dialog state !=
-  // OobeDialogState::HIDDEN.
-  login_shelf_view_->SetLoginDialogState(mojom::OobeDialogState::GAIA_SIGNIN);
-  EXPECT_TRUE(ShowsShelfButtons(
-      {LoginShelfView::kShutdown, LoginShelfView::kBrowseAsGuest}));
+  login_shelf_view_->SetLoginDialogVisible(true);
+  EXPECT_TRUE(ShowsShelfButtons({LoginShelfView::kShutdown}));
 
-  login_shelf_view_->SetLoginDialogState(mojom::OobeDialogState::HIDDEN);
+  login_shelf_view_->SetLoginDialogVisible(false);
   EXPECT_TRUE(ShowsShelfButtons({LoginShelfView::kShutdown,
                                  LoginShelfView::kBrowseAsGuest,
                                  LoginShelfView::kAddUser}));
-
-  // Guest button is hidden if dialog state ==
-  // OobeDialogState::WRONG_HWID_WARNING or SAML_PASSWORD_CONFIRM.
-  login_shelf_view_->SetLoginDialogState(
-      mojom::OobeDialogState::WRONG_HWID_WARNING);
-  EXPECT_TRUE(ShowsShelfButtons({LoginShelfView::kShutdown}));
-
-  login_shelf_view_->SetLoginDialogState(
-      mojom::OobeDialogState::SAML_PASSWORD_CONFIRM);
-  EXPECT_TRUE(ShowsShelfButtons({LoginShelfView::kShutdown}));
-
-  login_shelf_view_->SetLoginDialogState(mojom::OobeDialogState::GAIA_SIGNIN);
-  EXPECT_TRUE(ShowsShelfButtons(
-      {LoginShelfView::kShutdown, LoginShelfView::kBrowseAsGuest}));
-
-  // Guest button is hidden if SetAllowLoginAsGuest(false).
-  login_shelf_view_->SetAllowLoginAsGuest(false /*allow_guest*/);
-  EXPECT_TRUE(ShowsShelfButtons({LoginShelfView::kShutdown}));
-
-  // Kiosk app button is visible when dialog state == OobeDialogState::HIDDEN
-  // or GAIA_SIGNIN.
-  login_shelf_view_->SetLoginDialogState(mojom::OobeDialogState::GAIA_SIGNIN);
-  std::vector<mojom::KioskAppInfoPtr> kiosk_apps;
-  kiosk_apps.push_back(mojom::KioskAppInfo::New());
-  login_shelf_view_->SetKioskApps(std::move(kiosk_apps));
-  EXPECT_TRUE(
-      ShowsShelfButtons({LoginShelfView::kShutdown, LoginShelfView::kApps}));
-
-  login_shelf_view_->SetLoginDialogState(
-      mojom::OobeDialogState::SAML_PASSWORD_CONFIRM);
-  EXPECT_TRUE(ShowsShelfButtons({LoginShelfView::kShutdown}));
-
-  login_shelf_view_->SetLoginDialogState(mojom::OobeDialogState::HIDDEN);
-  EXPECT_TRUE(
-      ShowsShelfButtons({LoginShelfView::kShutdown, LoginShelfView::kAddUser,
-                         LoginShelfView::kApps}));
-
-  // Kiosk app button is hidden when no app exists.
-  login_shelf_view_->SetKioskApps(std::vector<mojom::KioskAppInfoPtr>());
-  EXPECT_TRUE(
-      ShowsShelfButtons({LoginShelfView::kShutdown, LoginShelfView::kAddUser}));
 }
 
 TEST_F(LoginShelfViewTest, ClickShutdownButton) {
diff --git a/ash/shell.cc b/ash/shell.cc
index 612cda9..1cc23be7 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -270,12 +270,13 @@
 // static
 Shell* Shell::CreateInstance(ShellInitParams init_params) {
   CHECK(!instance_);
-  instance_ = new Shell(std::move(init_params.delegate),
-                        std::move(init_params.shell_port));
-  instance_->Init(
-      init_params.context_factory, init_params.context_factory_private,
-      std::move(init_params.initial_display_prefs),
-      std::move(init_params.gpu_interface_provider), init_params.connector);
+  instance_ =
+      new Shell(std::move(init_params.delegate),
+                std::move(init_params.shell_port), init_params.connector);
+  instance_->Init(init_params.context_factory,
+                  init_params.context_factory_private,
+                  std::move(init_params.initial_display_prefs),
+                  std::move(init_params.gpu_interface_provider));
   return instance_;
 }
 
@@ -666,12 +667,14 @@
 // Shell, private:
 
 Shell::Shell(std::unique_ptr<ShellDelegate> shell_delegate,
-             std::unique_ptr<ShellPort> shell_port)
+             std::unique_ptr<ShellPort> shell_port,
+             service_manager::Connector* connector)
     : shell_port_(std::move(shell_port)),
       ash_display_controller_(std::make_unique<AshDisplayController>()),
       brightness_control_delegate_(
           std::make_unique<system::BrightnessControllerChromeos>()),
       cast_config_(std::make_unique<CastConfigController>()),
+      connector_(connector),
       first_run_helper_(std::make_unique<FirstRunHelper>()),
       focus_cycler_(std::make_unique<FocusCycler>()),
       ime_controller_(std::make_unique<ImeController>()),
@@ -684,8 +687,7 @@
       login_screen_controller_(std::make_unique<LoginScreenController>()),
       media_controller_(std::make_unique<MediaController>()),
       new_window_controller_(std::make_unique<NewWindowController>()),
-      session_controller_(std::make_unique<SessionController>(
-          shell_delegate->GetShellConnector())),
+      session_controller_(std::make_unique<SessionController>(connector)),
       note_taking_controller_(std::make_unique<NoteTakingController>()),
       shell_delegate_(std::move(shell_delegate)),
       shell_state_(std::make_unique<ShellState>()),
@@ -947,12 +949,9 @@
     ui::ContextFactory* context_factory,
     ui::ContextFactoryPrivate* context_factory_private,
     std::unique_ptr<base::Value> initial_display_prefs,
-    std::unique_ptr<ui::ws2::GpuInterfaceProvider> gpu_interface_provider,
-    service_manager::Connector* connector) {
+    std::unique_ptr<ui::ws2::GpuInterfaceProvider> gpu_interface_provider) {
   const Config config = shell_port_->GetAshConfig();
 
-  connector_ = connector;
-
   // 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>();
@@ -971,24 +970,22 @@
   screen_switch_check_controller_ =
       std::make_unique<ScreenSwitchCheckController>();
   // Connector can be null in tests.
-  if (shell_delegate_->GetShellConnector() &&
-      base::FeatureList::IsEnabled(
-          chromeos::features::kEnableUnifiedMultiDeviceSetup)) {
+  if (connector_ && base::FeatureList::IsEnabled(
+                        chromeos::features::kEnableUnifiedMultiDeviceSetup)) {
     multidevice_notification_presenter_ =
         std::make_unique<MultiDeviceNotificationPresenter>(
-            message_center::MessageCenter::Get(),
-            shell_delegate_->GetShellConnector());
+            message_center::MessageCenter::Get(), connector_);
   }
 
   // Connector can be null in tests.
-  if (shell_delegate_->GetShellConnector()) {
+  if (connector_) {
     // Connect to local state prefs now, but wait for an active user before
     // connecting to the profile pref service. The login screen has a temporary
     // user profile that is not associated with a real user.
     auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
     RegisterLocalStatePrefs(pref_registry.get(), false);
     prefs::ConnectToPrefService(
-        shell_delegate_->GetShellConnector(), std::move(pref_registry),
+        connector_, std::move(pref_registry),
         base::Bind(&Shell::OnLocalStatePrefServiceInitialized,
                    weak_factory_.GetWeakPtr()),
         prefs::mojom::kLocalStateServiceName);
@@ -1001,8 +998,8 @@
   accessibility_focus_ring_controller_ =
       std::make_unique<AccessibilityFocusRingController>();
   accessibility_delegate_.reset(shell_delegate_->CreateAccessibilityDelegate());
-  accessibility_controller_ = std::make_unique<AccessibilityController>(
-      shell_delegate_->GetShellConnector());
+  accessibility_controller_ =
+      std::make_unique<AccessibilityController>(connector_);
   toast_manager_ = std::make_unique<ToastManager>();
 
   // Install the custom factory early on so that views::FocusManagers for Tray,
@@ -1137,11 +1134,10 @@
 
   // Forward user activity from the window server to |user_activity_detector_|.
   // The connector is unavailable in some tests.
-  if (aura::Env::GetInstance()->mode() == aura::Env::Mode::MUS &&
-      shell_delegate_->GetShellConnector()) {
+  // TODO(sky): this is dead code, clean up.
+  if (aura::Env::GetInstance()->mode() == aura::Env::Mode::MUS && connector_) {
     ui::mojom::UserActivityMonitorPtr user_activity_monitor;
-    shell_delegate_->GetShellConnector()->BindInterface(ui::mojom::kServiceName,
-                                                        &user_activity_monitor);
+    connector_->BindInterface(ui::mojom::kServiceName, &user_activity_monitor);
     user_activity_forwarder_ = std::make_unique<aura::UserActivityForwarder>(
         std::move(user_activity_monitor), user_activity_detector_.get());
   }
@@ -1266,13 +1262,12 @@
   display_manager_->CreateMirrorWindowAsyncIfAny();
 
   // The show taps feature can be implemented with a separate mojo app.
-  // GetShellConnector() is null in unit tests.
+  // |connector_| is null in unit tests.
   // TODO(jamescook): Make this work in ash_shell_with_content.
-  if (shell_delegate_->GetShellConnector() &&
+  if (connector_ &&
       base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kShowTaps) &&
       base::FeatureList::IsEnabled(features::kTapVisualizerApp)) {
-    shell_delegate_->GetShellConnector()->StartService(
-        tap_visualizer::mojom::kServiceName);
+    connector_->StartService(tap_visualizer::mojom::kServiceName);
   }
 
   window_service_owner_ =
@@ -1326,10 +1321,10 @@
       std::make_unique<ProjectingObserver>(display_configurator_.get());
 
   if (!display_initialized) {
+    // TODO(sky): this is dead code, cleanup.
     if (config != Config::CLASSIC && !chromeos::IsRunningAsSystemCompositor()) {
       display::mojom::DevDisplayControllerPtr controller;
-      shell_delegate_->GetShellConnector()->BindInterface(
-          ui::mojom::kServiceName, &controller);
+      connector_->BindInterface(ui::mojom::kServiceName, &controller);
       display_manager_->SetDevDisplayController(std::move(controller));
     }
 
diff --git a/ash/shell.h b/ash/shell.h
index d9635dc3..7a67c84 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -648,15 +648,15 @@
   friend class SmsObserverTest;
 
   Shell(std::unique_ptr<ShellDelegate> shell_delegate,
-        std::unique_ptr<ShellPort> shell_port);
+        std::unique_ptr<ShellPort> shell_port,
+        service_manager::Connector* connector);
   ~Shell() override;
 
   void Init(
       ui::ContextFactory* context_factory,
       ui::ContextFactoryPrivate* context_factory_private,
       std::unique_ptr<base::Value> initial_display_prefs,
-      std::unique_ptr<ui::ws2::GpuInterfaceProvider> gpu_interface_provider,
-      service_manager::Connector* connector);
+      std::unique_ptr<ui::ws2::GpuInterfaceProvider> gpu_interface_provider);
 
   // Initializes the display manager and related components.
   void InitializeDisplayManager();
@@ -717,7 +717,7 @@
   std::unique_ptr<CastConfigController> cast_config_;
   std::unique_ptr<ClientImageRegistry> client_image_registry_;
   std::unique_ptr<CrosDisplayConfig> cros_display_config_;
-  service_manager::Connector* connector_ = nullptr;
+  service_manager::Connector* const connector_;
   std::unique_ptr<DetachableBaseHandler> detachable_base_handler_;
   std::unique_ptr<DetachableBaseNotificationController>
       detachable_base_notification_controller_;
diff --git a/ash/shell/content/client/shell_browser_main_parts.cc b/ash/shell/content/client/shell_browser_main_parts.cc
index 2959913..28cce01 100644
--- a/ash/shell/content/client/shell_browser_main_parts.cc
+++ b/ash/shell/content/client/shell_browser_main_parts.cc
@@ -95,6 +95,8 @@
   init_params.context_factory_private = content::GetContextFactoryPrivate();
   init_params.gpu_interface_provider =
       std::make_unique<ContentGpuInterfaceProvider>();
+  init_params.connector =
+      content::ServiceManagerConnection::GetForProcess()->GetConnector();
   ash::Shell::CreateInstance(std::move(init_params));
 
   // Initialize session controller client and create fake user sessions. The
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc
index e08334d..427f3c5 100644
--- a/ash/shell/shell_delegate_impl.cc
+++ b/ash/shell/shell_delegate_impl.cc
@@ -17,10 +17,6 @@
 
 ShellDelegateImpl::~ShellDelegateImpl() = default;
 
-::service_manager::Connector* ShellDelegateImpl::GetShellConnector() const {
-  return nullptr;
-}
-
 bool ShellDelegateImpl::CanShowWindowForUser(aura::Window* window) const {
   return true;
 }
diff --git a/ash/shell/shell_delegate_impl.h b/ash/shell/shell_delegate_impl.h
index 43a10bb5..00b94a479 100644
--- a/ash/shell/shell_delegate_impl.h
+++ b/ash/shell/shell_delegate_impl.h
@@ -24,7 +24,6 @@
   ~ShellDelegateImpl() override;
 
   // ShellDelegate:
-  ::service_manager::Connector* GetShellConnector() const override;
   bool CanShowWindowForUser(aura::Window* window) const override;
   void PreInit() override;
   std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override;
diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h
index 4c884765..8e0dfc23 100644
--- a/ash/shell_delegate.h
+++ b/ash/shell_delegate.h
@@ -20,10 +20,6 @@
 class KeyboardUI;
 }
 
-namespace service_manager {
-class Connector;
-}
-
 namespace ui {
 class InputDeviceControllerClient;
 }
@@ -39,9 +35,6 @@
   // The Shell owns the delegate.
   virtual ~ShellDelegate() {}
 
-  // Returns the connector for the mojo service manager. Returns null in tests.
-  virtual service_manager::Connector* GetShellConnector() const = 0;
-
   // Returns true if |window| can be shown for the delegate's concept of current
   // user.
   virtual bool CanShowWindowForUser(aura::Window* window) const = 0;
diff --git a/ash/shell_delegate_mash.cc b/ash/shell_delegate_mash.cc
index bcd5ea4e..a686ac9 100644
--- a/ash/shell_delegate_mash.cc
+++ b/ash/shell_delegate_mash.cc
@@ -9,6 +9,7 @@
 
 #include "ash/accessibility/default_accessibility_delegate.h"
 #include "ash/screenshot_delegate.h"
+#include "ash/shell.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "components/user_manager/user_info_impl.h"
@@ -42,15 +43,10 @@
 
 }  // namespace
 
-ShellDelegateMash::ShellDelegateMash(service_manager::Connector* connector)
-    : connector_(connector) {}
+ShellDelegateMash::ShellDelegateMash() = default;
 
 ShellDelegateMash::~ShellDelegateMash() = default;
 
-service_manager::Connector* ShellDelegateMash::GetShellConnector() const {
-  return connector_;
-}
-
 bool ShellDelegateMash::CanShowWindowForUser(aura::Window* window) const {
   NOTIMPLEMENTED_LOG_ONCE();
   return true;
@@ -76,12 +72,13 @@
 
 ui::InputDeviceControllerClient*
 ShellDelegateMash::GetInputDeviceControllerClient() {
-  if (!connector_)
+  if (!Shell::Get()->connector())
     return nullptr;  // Happens in tests.
 
   if (!input_device_controller_client_) {
     input_device_controller_client_ =
-        std::make_unique<ui::InputDeviceControllerClient>(connector_);
+        std::make_unique<ui::InputDeviceControllerClient>(
+            Shell::Get()->connector());
   }
   return input_device_controller_client_.get();
 }
diff --git a/ash/shell_delegate_mash.h b/ash/shell_delegate_mash.h
index 2ae8231..2b06e77 100644
--- a/ash/shell_delegate_mash.h
+++ b/ash/shell_delegate_mash.h
@@ -10,19 +10,14 @@
 #include "ash/shell_delegate.h"
 #include "base/macros.h"
 
-namespace service_manager {
-class Connector;
-}
-
 namespace ash {
 
 class ShellDelegateMash : public ShellDelegate {
  public:
-  explicit ShellDelegateMash(service_manager::Connector* connector);
+  ShellDelegateMash();
   ~ShellDelegateMash() override;
 
   // ShellDelegate:
-  service_manager::Connector* GetShellConnector() const override;
   bool CanShowWindowForUser(aura::Window* window) const override;
   void PreInit() override;
   std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override;
@@ -31,9 +26,6 @@
   ui::InputDeviceControllerClient* GetInputDeviceControllerClient() override;
 
  private:
-  // |connector_| may be null in tests.
-  service_manager::Connector* connector_;
-
   std::unique_ptr<ui::InputDeviceControllerClient>
       input_device_controller_client_;
 
diff --git a/ash/system/flag_warning/flag_warning_tray.cc b/ash/system/flag_warning/flag_warning_tray.cc
index e5edde6..2945633 100644
--- a/ash/system/flag_warning/flag_warning_tray.cc
+++ b/ash/system/flag_warning/flag_warning_tray.cc
@@ -12,7 +12,6 @@
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
-#include "ash/shell_delegate.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_container.h"
 #include "base/logging.h"
@@ -69,8 +68,8 @@
 
   // Open the quick launch mojo mini-app to demonstrate that mini-apps work.
   mash::mojom::LaunchablePtr launchable;
-  Shell::Get()->shell_delegate()->GetShellConnector()->BindInterface(
-      quick_launch::mojom::kServiceName, &launchable);
+  Shell::Get()->connector()->BindInterface(quick_launch::mojom::kServiceName,
+                                           &launchable);
   launchable->Launch(mash::mojom::kWindow, mash::mojom::LaunchMode::DEFAULT);
 }
 
diff --git a/ash/test_shell_delegate.cc b/ash/test_shell_delegate.cc
index 720a706f..595a0c1 100644
--- a/ash/test_shell_delegate.cc
+++ b/ash/test_shell_delegate.cc
@@ -17,10 +17,6 @@
 
 TestShellDelegate::~TestShellDelegate() = default;
 
-::service_manager::Connector* TestShellDelegate::GetShellConnector() const {
-  return nullptr;
-}
-
 bool TestShellDelegate::CanShowWindowForUser(aura::Window* window) const {
   return true;
 }
diff --git a/ash/test_shell_delegate.h b/ash/test_shell_delegate.h
index ab05b16..f40ee11 100644
--- a/ash/test_shell_delegate.h
+++ b/ash/test_shell_delegate.h
@@ -18,7 +18,6 @@
   ~TestShellDelegate() override;
 
   // Overridden from ShellDelegate:
-  ::service_manager::Connector* GetShellConnector() const override;
   bool CanShowWindowForUser(aura::Window* window) const override;
   void PreInit() override;
   std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override;
diff --git a/ash/wallpaper/wallpaper_utils/wallpaper_decoder.cc b/ash/wallpaper/wallpaper_utils/wallpaper_decoder.cc
index 98f37c5..f4831b4 100644
--- a/ash/wallpaper/wallpaper_utils/wallpaper_decoder.cc
+++ b/ash/wallpaper/wallpaper_utils/wallpaper_decoder.cc
@@ -5,7 +5,6 @@
 #include "ash/wallpaper/wallpaper_utils/wallpaper_decoder.h"
 
 #include "ash/shell.h"
-#include "ash/shell_delegate.h"
 #include "ipc/ipc_channel.h"
 
 namespace ash {
@@ -33,16 +32,16 @@
                      const data_decoder::mojom::ImageCodec& image_codec,
                      OnWallpaperDecoded callback) {
   // The connector for the mojo service manager is null in unit tests.
-  if (!Shell::Get()->shell_delegate()->GetShellConnector()) {
+  if (!Shell::Get()->connector()) {
     std::move(callback).Run(gfx::ImageSkia());
     return;
   }
   std::vector<uint8_t> image_bytes(image_data.begin(), image_data.end());
   data_decoder::DecodeImage(
-      Shell::Get()->shell_delegate()->GetShellConnector(),
-      std::move(image_bytes), image_codec, /*shrink_to_fit=*/true,
-      kMaxImageSizeInBytes, /*desired_image_frame_size=*/gfx::Size(),
+      Shell::Get()->connector(), std::move(image_bytes), image_codec,
+      /*shrink_to_fit=*/true, kMaxImageSizeInBytes,
+      /*desired_image_frame_size=*/gfx::Size(),
       base::BindOnce(&ConvertToImageSkia, std::move(callback)));
 }
 
-}  // namespace ash
\ No newline at end of file
+}  // namespace ash
diff --git a/build/android/gradle/generate_gradle.py b/build/android/gradle/generate_gradle.py
index 302f0a67..fe9b7a5 100755
--- a/build/android/gradle/generate_gradle.py
+++ b/build/android/gradle/generate_gradle.py
@@ -334,7 +334,7 @@
       return _DEFAULT_ANDROID_MANIFEST_PATH
 
     variables = {}
-    variables['compile_sdk_version'] = self.build_vars['android_sdk_version']
+    variables['compile_sdk_version'] = self.build_vars['compile_sdk_version']
     variables['package'] = resource_packages[0]
 
     output_file = os.path.join(
@@ -550,7 +550,7 @@
   variables = {}
   variables['build_tools_version'] = source_properties['Pkg.Revision']
   variables['compile_sdk_version'] = (
-      'android-%s' % build_vars['android_sdk_version'])
+      'android-%s' % build_vars['compile_sdk_version'])
   target_sdk_version = build_vars['android_sdk_version']
   if target_sdk_version.isalpha():
     target_sdk_version = '"{}"'.format(target_sdk_version)
@@ -820,6 +820,12 @@
                       action='append',
                       help='GN native targets to generate for. May be '
                            'repeated.')
+  parser.add_argument('--compile-sdk-version',
+                      type=int,
+                      default=0,
+                      help='Override compileSdkVersion for android sdk docs. '
+                           'Useful when sources for android_sdk_version is '
+                           'not available in Android Studio.')
   version_group = parser.add_mutually_exclusive_group()
   version_group.add_argument('--beta',
                       action='store_true',
@@ -895,6 +901,10 @@
     channel = 'canary'
   else:
     channel = 'stable'
+  if args.compile_sdk_version:
+    build_vars['compile_sdk_version'] = args.compile_sdk_version
+  else:
+    build_vars['compile_sdk_version'] = build_vars['android_sdk_version']
   generator = _ProjectContextGenerator(_gradle_output_dir, build_vars,
       args.use_gradle_process_resources, jinja_processor, args.split_projects,
       channel)
diff --git a/build/android/gradle/root.jinja b/build/android/gradle/root.jinja
index 76ffa8f6..bf76bde 100644
--- a/build/android/gradle/root.jinja
+++ b/build/android/gradle/root.jinja
@@ -10,7 +10,7 @@
     }
     dependencies {
 {% if channel == 'canary' %}
-        classpath "com.android.tools.build:gradle:3.2.0-alpha16"
+        classpath "com.android.tools.build:gradle:3.3.0-alpha03"
 {% elif channel == 'beta' %}
         classpath "com.android.tools.build:gradle:3.1.0-beta4"
 {% else %}
diff --git a/build/android/gyp/generate_proguarded_module_jar.py b/build/android/gyp/generate_proguarded_module_jar.py
new file mode 100755
index 0000000..97b3027a
--- /dev/null
+++ b/build/android/gyp/generate_proguarded_module_jar.py
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 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.
+
+"""Extracts a bundle module's classes from jar created in the synchronized
+proguarding step and packages them into a new jar.
+
+Synchronized proguarding means that, when several app modules are combined into
+an app bundle, all un-optimized jars for all modules are grouped and sent to a
+single proguard command, which generates a single, common, intermediate
+optimized jar, and its mapping file.
+
+This script is used to extract, from this synchronized proguard jar, all the
+optimized classes corresponding to a single module, into a new .jar file. The
+latter will be compiled later into the module's dex file.
+
+For this, the script reads the module's un-obfuscated class names from the
+module's unoptimized jars. Then, it maps those to obfuscated class names using
+the proguard mapping file. Finally, it extracts the module's class files from
+the proguarded jar and zips them into a new module jar. """
+
+import argparse
+import os
+import sys
+import zipfile
+
+from util import build_utils
+
+MANIFEST = """Manifest-Version: 1.0
+Created-By: generate_proguarded_module_jar.py
+"""
+
+
+# TODO(tiborg): Share with merge_jar_info_files.py.
+def _FullJavaNameFromClassFilePath(path):
+  if not path.endswith('.class'):
+    return ''
+  path = os.path.splitext(path)[0]
+  parts = []
+  while path:
+    # Use split to be platform independent.
+    head, tail = os.path.split(path)
+    path = head
+    parts.append(tail)
+  parts.reverse()  # Package comes first
+  return '.'.join(parts)
+
+
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+  parser = argparse.ArgumentParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_argument(
+      '--proguarded-jar',
+      required=True,
+      help='Path to input jar produced by synchronized proguarding')
+  parser.add_argument(
+      '--proguard-mapping',
+      required=True,
+      help='Path to input proguard mapping produced by synchronized '
+      'proguarding')
+  parser.add_argument(
+      '--module-input-jars',
+      required=True,
+      help='GN-list of input paths to un-optimized jar files for the current '
+      'module. The optimized versions of their .class files will go into '
+      'the output jar.')
+  parser.add_argument(
+      '--output-jar',
+      required=True,
+      help='Path to output jar file containing the module\'s optimized class '
+      'files')
+  parser.add_argument(
+      '--is-base-module',
+      action='store_true',
+      help='Inidcates to extract class files for a base module')
+  options = parser.parse_args(args)
+  options.module_input_jars = build_utils.ParseGnList(options.module_input_jars)
+
+  # Read class names of the currently processed module.
+  classes = set()
+  for module_jar in options.module_input_jars:
+    with zipfile.ZipFile(module_jar) as zip_info:
+      for path in zip_info.namelist():
+        fully_qualified_name = _FullJavaNameFromClassFilePath(path)
+        if fully_qualified_name:
+          classes.add(fully_qualified_name)
+
+  # Parse the proguarding mapping to be able to map un-obfuscated to obfuscated
+  # names.
+  # Proguard mapping files have the following format:
+  #
+  # {un-obfuscated class name 1} -> {obfuscated class name 1}:
+  #     {un-obfuscated member name 1} -> {obfuscated member name 1}
+  #     ...
+  # {un-obfuscated class name 2} -> {obfuscated class name 2}:
+  #     ...
+  # ...
+  obfuscation_map = {}
+  with open(options.proguard_mapping, 'r') as proguard_mapping_file:
+    for line in proguard_mapping_file:
+      # Skip indented lines since they map member names and not class names.
+      if line.startswith(' '):
+        continue
+      line = line.strip()
+      # Skip empty lines.
+      if not line:
+        continue
+      assert line.endswith(':')
+      full, obfuscated = line.strip(':').split(' -> ')
+      assert full
+      assert obfuscated
+      obfuscation_map[full] = obfuscated
+
+  # Collect the obfuscated names of classes, which should go into the currently
+  # processed module.
+  obfuscated_module_classes = set(
+      obfuscation_map[c] for c in classes if c in obfuscation_map)
+
+  # Collect horizontally merged classes to later make sure that those only go
+  # into the base module. Merging classes horizontally means that proguard took
+  # two classes that don't inherit from each other and merged them into one.
+  horiz_merged_classes = set()
+  obfuscated_classes = sorted(obfuscation_map.values())
+  prev_obfuscated_class = None
+  for obfuscated_class in obfuscated_classes:
+    if prev_obfuscated_class and obfuscated_class == prev_obfuscated_class:
+      horiz_merged_classes.add(obfuscated_class)
+    prev_obfuscated_class = obfuscated_class
+
+  # Move horizontally merged classes into the base module.
+  if options.is_base_module:
+    obfuscated_module_classes |= horiz_merged_classes
+  else:
+    obfuscated_module_classes -= horiz_merged_classes
+
+  # Extract module class files from proguarded jar and store them in a module
+  # split jar.
+  with zipfile.ZipFile(
+      os.path.abspath(options.output_jar), 'w',
+      zipfile.ZIP_DEFLATED) as output_jar:
+    with zipfile.ZipFile(os.path.abspath(options.proguarded_jar),
+                         'r') as proguarded_jar:
+      for obfuscated_class in obfuscated_module_classes:
+        class_path = obfuscated_class.replace('.', '/') + '.class'
+        class_file_content = proguarded_jar.read(class_path)
+        output_jar.writestr(class_path, class_file_content)
+    output_jar.writestr('META-INF/MANIFEST.MF', MANIFEST)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile, options.output_jar, options.module_input_jars +
+        [options.proguard_mapping, options.proguarded_jar], add_pydeps=False)
+
+
+if __name__ == '__main__':
+  main(sys.argv[1:])
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index 57edacc..a4519b2 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -495,6 +495,16 @@
 The list of annotation processor main classes. I.e. sent as `-processor' when
 invoking `javac`.
 
+## <a name="android_app_bundle">Target type `android_app_bundle`</a>:
+
+This type corresponds to an Android app bundle (`.aab` file).
+
+* `deps_info['synchronized_proguard_enabled"]`:
+True to indicate that the app modules of this bundle should be proguarded in a
+single synchronized proguarding step. Synchronized proguarding means that all
+un-optimized jars for all modules are sent to a single proguard command. The
+resulting optimized jar is then split into optimized app module jars after.
+
 --------------- END_MARKDOWN ---------------------------------------------------
 """
 
@@ -851,7 +861,9 @@
       help='Path to the build config of the tested apk (for an instrumentation '
       'test apk).')
   parser.add_option('--proguard-enabled', action='store_true',
-      help='Whether proguard is enabled for this apk.')
+      help='Whether proguard is enabled for this apk or bundle module.')
+  parser.add_option('--synchronized-proguard-enabled', action='store_true',
+      help='Whether synchronized proguarding is enabled for this bundle.')
   parser.add_option('--proguard-configs',
       help='GN-list of proguard flag files to use in final apk.')
   parser.add_option('--proguard-output-jar-path',
@@ -1187,6 +1199,11 @@
     if is_java_target and options.jar_path:
       java_full_classpath.append(options.jar_path)
     java_full_classpath.extend(c['jar_path'] for c in all_library_deps)
+    if options.type == 'android_app_bundle':
+      for d in deps.Direct('android_app_bundle_module'):
+        java_full_classpath.extend(
+            c for c in d.get('java_runtime_classpath', [])
+            if c not in java_full_classpath)
 
   system_jars = [c['jar_path'] for c in system_library_deps]
   system_interface_jars = [c['interface_jar_path'] for c in system_library_deps]
@@ -1209,7 +1226,16 @@
           p for p in c.get('proguard_configs', []) if p not in all_configs)
       extra_jars.extend(
           p for p in c.get('extra_classpath_jars', []) if p not in extra_jars)
+    if options.type == 'android_app_bundle':
+      for c in deps.Direct('android_app_bundle_module'):
+        all_configs.extend(
+            p for p in c.get('proguard_configs', []) if p not in all_configs)
     deps_info['proguard_all_configs'] = all_configs
+    if options.type == 'android_app_bundle':
+      for d in deps.Direct('android_app_bundle_module'):
+        extra_jars.extend(
+            c for c in d.get('proguard_classpath_jars', [])
+            if c not in extra_jars)
     deps_info['proguard_classpath_jars'] = extra_jars
 
     if options.type == 'android_app_bundle':
@@ -1227,7 +1253,16 @@
         raise Exception('Deps %s have proguard enabled while deps %s have '
                         'proguard disabled' % (deps_proguard_enabled,
                                                deps_proguard_disabled))
-      deps_info['sync_proguard_enabled'] = bool(deps_proguard_enabled)
+      if (bool(deps_proguard_enabled) !=
+              bool(options.synchronized_proguard_enabled) or
+          bool(deps_proguard_disabled) ==
+              bool(options.synchronized_proguard_enabled)):
+        raise Exception('Modules %s of bundle %s have opposite proguard '
+                        'enabling flags than bundle' % (deps_proguard_enabled +
+                            deps_proguard_disabled, config['deps_info']['name'])
+                        )
+      deps_info['synchronized_proguard_enabled'] = bool(
+          options.synchronized_proguard_enabled)
     else:
       deps_info['proguard_enabled'] = bool(options.proguard_enabled)
       if options.proguard_output_jar_path:
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 345b77c9..379efef 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -376,6 +376,10 @@
     if (defined(invoker.proguard_enabled) && invoker.proguard_enabled) {
       args += [ "--proguard-enabled" ]
     }
+    if (defined(invoker.synchronized_proguard_enabled) &&
+        invoker.synchronized_proguard_enabled) {
+      args += [ "--synchronized-proguard-enabled" ]
+    }
     if (defined(invoker.proguard_output_jar_path)) {
       _rebased_proguard_output_jar_path =
           rebase_path(invoker.proguard_output_jar_path, root_build_dir)
@@ -3267,6 +3271,9 @@
 #
 #   build_config: Path to build_config of the android_apk_or_module() target.
 #
+#   dex_path_file_arg: Path to the module's dex file passed directly to the
+#     creation script. Must be a rebased path or @FileArg expression.
+#
 template("create_android_app_bundle_module") {
   _build_config = invoker.build_config
   _rebased_build_config = rebase_path(_build_config, root_build_dir)
@@ -3298,7 +3305,7 @@
       "--format=bundle-module",
       "--output-apk",
       rebase_path(invoker.module_zip_path, root_build_dir),
-      "--dex-file=@FileArg($_rebased_build_config:final_dex:path)",
+      "--dex-file=${invoker.dex_path_file_arg}",
       "--resource-apk=@FileArg(" +
           "$_rebased_build_config:deps_info:proto_resources_path)",
       "--assets=@FileArg($_rebased_build_config:assets)",
@@ -3319,3 +3326,42 @@
     }
   }
 }
+
+# Extracts a bundle module's classes from jar created in the synchronized
+# proguarding step and packages them into a new jar.
+#
+# Variables:
+#   proguarded_jar: Path to input jar produced by synchronized proguarding.
+#   proguard_mapping: Path to input proguard mapping produced by synchronized
+#     proguarding
+#   output_jar: Path to output jar file containing the module's optimized class
+#     files.
+#   build_config: Path to build config of module.
+#   is_base_module: True if this is processing a base module.
+template("generate_proguarded_module_jar") {
+  _rebased_build_config = rebase_path(invoker.build_config, root_build_dir)
+
+  action(target_name) {
+    forward_variables_from(invoker, [ "deps" ])
+    script = "//build/android/gyp/generate_proguarded_module_jar.py"
+    inputs = build_utils_py
+    outputs = [
+      invoker.output_jar,
+    ]
+    depfile = "${target_gen_dir}/${target_name}.d"
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--proguarded-jar",
+      rebase_path(invoker.proguarded_jar, root_build_dir),
+      "--proguard-mapping",
+      rebase_path(invoker.proguard_mapping, root_build_dir),
+      "--module-input-jars=@FileArg(${_rebased_build_config}:deps_info:java_runtime_classpath)",
+      "--output-jar",
+      rebase_path(invoker.output_jar, root_build_dir),
+    ]
+    if (defined(invoker.is_base_module) && invoker.is_base_module) {
+      args += [ "--is-base-module" ]
+    }
+  }
+}
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 356544b..2bf284a 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1932,7 +1932,6 @@
     } else {
       _final_dex_path = "$_gen_dir/classes.dex"
     }
-    _final_dex_target_name = "${_template_name}__final_dex"
 
     if (defined(invoker.final_apk_path)) {
       _final_apk_path = invoker.final_apk_path
@@ -2388,85 +2387,102 @@
       }
     }
 
-    if (_proguard_enabled) {
-      _proguard_target = "${_template_name}__proguard"
-      proguard(_proguard_target) {
-        forward_variables_from(invoker, [ "proguard_jar_path" ])
-        build_config = _build_config
-        deps = _deps + [
-                 ":$_build_config_target",
-                 ":$_compile_resources_target",
-                 ":$_java_target",
-               ]
-        inputs = [
-          _jar_path,
-        ]
+    # When using an app bundle that is made of several modules, it is crucial to
+    # ensure that the obfuscated class names used by each module are consistent.
+    #
+    # To achieve this, all modules belonging to the same app bundle must
+    # be grouped into a single .jar, that will be proguarded all at once. This
+    # is called "synchronized proguarding", and ensures that the obfuscated
+    # names of all classes remain consistent across modules.
+    #
+    # Later, this single optimized .jar is processed to generate module-specific
+    # .jar files that only contain the obfuscated classes needed by the module
+    # itself.
+    #
+    # This synchronized proguarding step is added by the bundle target.
+    if (!_is_bundle_module || !_proguard_enabled) {
+      if (_proguard_enabled) {
+        _proguard_target = "${_template_name}__proguard"
+        proguard(_proguard_target) {
+          forward_variables_from(invoker, [ "proguard_jar_path" ])
+          build_config = _build_config
+          deps = _deps + [
+                   ":$_build_config_target",
+                   ":$_compile_resources_target",
+                   ":$_java_target",
+                 ]
+          inputs = [
+            _jar_path,
+          ]
 
-        output_jar_path = _proguard_output_jar_path
-        args = [
-          "--proguard-configs=@FileArg($_rebased_build_config:deps_info:proguard_all_configs)",
-          "--input-paths=@FileArg($_rebased_build_config:deps_info:java_runtime_classpath)",
-        ]
-        if (defined(invoker.proguard_config_exclusions)) {
-          _rebased_proguard_config_exclusions =
-              rebase_path(invoker.proguard_config_exclusions, root_build_dir)
-          args += [
-            "--proguard-config-exclusions=$_rebased_proguard_config_exclusions",
+          output_jar_path = _proguard_output_jar_path
+          args = [
+            "--proguard-configs=@FileArg($_rebased_build_config:deps_info:proguard_all_configs)",
+            "--input-paths=@FileArg($_rebased_build_config:deps_info:java_runtime_classpath)",
+          ]
+          if (defined(invoker.proguard_config_exclusions)) {
+            _rebased_proguard_config_exclusions =
+                rebase_path(invoker.proguard_config_exclusions, root_build_dir)
+            args += [ "--proguard-config-exclusions=$_rebased_proguard_config_exclusions" ]
+          }
+        }
+        _dex_sources = [ _proguard_output_jar_path ]
+        _dex_deps = [ ":$_proguard_target" ]
+
+        _copy_proguard_mapping_target =
+            "${_template_name}__copy_proguard_mapping"
+        copy(_copy_proguard_mapping_target) {
+          sources = [
+            "$_proguard_output_jar_path.mapping",
+          ]
+          outputs = [
+            "$_final_apk_path.mapping",
+          ]
+          deps = [
+            ":$_proguard_target",
           ]
         }
+      } else {
+        if (_enable_multidex) {
+          # .jar already included in java_runtime_classpath.
+          _dex_sources = []
+        } else {
+          _dex_sources = [ _lib_dex_path ]
+        }
+        _dex_deps = [ ":$_java_target" ]
       }
-      _dex_sources = [ _proguard_output_jar_path ]
-      _dex_deps = [ ":$_proguard_target" ]
 
-      _copy_proguard_mapping_target = "${_template_name}__copy_proguard_mapping"
-      copy(_copy_proguard_mapping_target) {
-        sources = [
-          "$_proguard_output_jar_path.mapping",
-        ]
-        outputs = [
-          "$_final_apk_path.mapping",
-        ]
-        deps = [
-          ":$_proguard_target",
-        ]
+      _final_dex_target_name = "${_template_name}__final_dex"
+      dex("$_final_dex_target_name") {
+        deps = _dex_deps + [ ":$_build_config_target" ]
+        input_jars = _dex_sources
+        output = _final_dex_path
+        enable_multidex = _enable_multidex
+
+        if (_enable_multidex) {
+          forward_variables_from(invoker, [ "negative_main_dex_globs" ])
+          extra_main_dex_proguard_config = _generated_proguard_main_dex_config
+          deps += [ ":$_compile_resources_target" ]
+        }
+
+        # All deps are already included in _dex_sources when proguard is used.
+        if (!_proguard_enabled) {
+          if (_enable_multidex) {
+            _dex_arg_key =
+                "${_rebased_build_config}:deps_info:java_runtime_classpath"
+          } else {
+            _dex_arg_key =
+                "${_rebased_build_config}:final_dex:dependency_dex_files"
+          }
+          build_config = _build_config
+          input_jars_file_arg = "@FileArg($_dex_arg_key)"
+        }
+
+        # http://crbug.com/725224. Fix for bots running out of memory.
+        use_pool = true
       }
     } else {
-      if (_enable_multidex) {
-        # .jar already included in java_runtime_classpath.
-        _dex_sources = []
-      } else {
-        _dex_sources = [ _lib_dex_path ]
-      }
-      _dex_deps = [ ":$_java_target" ]
-    }
-
-    dex("$_final_dex_target_name") {
-      deps = _dex_deps + [ ":$_build_config_target" ]
-      input_jars = _dex_sources
-      output = _final_dex_path
-      enable_multidex = _enable_multidex
-
-      if (_enable_multidex) {
-        forward_variables_from(invoker, [ "negative_main_dex_globs" ])
-        extra_main_dex_proguard_config = _generated_proguard_main_dex_config
-        deps += [ ":$_compile_resources_target" ]
-      }
-
-      # All deps are already included in _dex_sources when proguard is used.
-      if (!_proguard_enabled) {
-        if (_enable_multidex) {
-          _dex_arg_key =
-              "${_rebased_build_config}:deps_info:java_runtime_classpath"
-        } else {
-          _dex_arg_key =
-              "${_rebased_build_config}:final_dex:dependency_dex_files"
-        }
-        build_config = _build_config
-        input_jars_file_arg = "@FileArg($_dex_arg_key)"
-      }
-
-      # http://crbug.com/725224. Fix for bots running out of memory.
-      use_pool = true
+      _final_deps += [ ":$_java_target" ]
     }
 
     _native_libs_file_arg_dep = ":$_build_config_target"
@@ -2598,7 +2614,7 @@
       _final_deps += [
                        ":$_merge_manifest_target",
                        ":$_build_config_target",
-                       ":$_final_dex_target_name",
+                       ":$_compile_resources_target",
                      ] + _all_native_libs_deps
     }
 
@@ -2711,7 +2727,7 @@
         public_deps += _apk_operations
 
         # Make the proguard .mapping file easy to find by putting it beside the .apk.
-        if (_proguard_enabled) {
+        if (_proguard_enabled && !_is_bundle_module) {
           deps = [
             ":$_copy_proguard_mapping_target",
           ]
@@ -3614,9 +3630,6 @@
   #      base module), and an 'apk_target' field that specified the
   #      corresponding android_apk target name the module is modeled on.
   #
-  #    extra_module_apk_targets: Optional list of android_apk target matching
-  #      the names listed in extra_module_names.
-  #
   #    enable_language_splits: Optional. If true, enable APK splits based
   #      on languages.
   #
@@ -3637,11 +3650,19 @@
   #      APKs use 'chrome-command-line', the WebView one uses
   #      'webview-command-line').
   #
+  #    synchronized_proguard_enabled: True if synchronized proguarding is
+  #      enabled for this bundle. WARNING: All modules that contain Java must
+  #      have proguarding enabled if this is true and disabled if this is false.
+  #
+  #    proguard_jar_path: Path to custom proguard jar used for synchronized
+  #      proguarding. WARNING: Can only be set if
+  #      |synchronized_proguard_enabled| is set to true.
+  #
   # Example:
   #   android_app_bundle("chrome_public_bundle") {
   #      base_module_target = "//chrome/android:chrome_public_apk"
   #      extra_modules = [
-  #        {  # NOTE: Scopes require one field per line, and no comma separators.
+  #        { # NOTE: Scopes require one field per line, and no comma separators.
   #          name = "my_module"
   #          module_target = ":my_module"
   #        },
@@ -3671,44 +3692,118 @@
       _all_modules += invoker.extra_modules
     }
 
+    _synchronized_proguard_enabled =
+        defined(invoker.synchronized_proguard_enabled) &&
+        invoker.synchronized_proguard_enabled
+
     # Make build config, which is required for synchronized proguarding.
     _module_targets = []
     foreach(_module, _all_modules) {
       _module_targets += [ _module.module_target ]
     }
     _build_config = "$target_gen_dir/${target_name}.build_config"
+    _rebased_build_config = rebase_path(_build_config, root_build_dir)
     _build_config_target = "${target_name}__build_config"
     write_build_config(_build_config_target) {
       type = "android_app_bundle"
       possible_config_deps = _module_targets
       build_config = _build_config
+      synchronized_proguard_enabled = _synchronized_proguard_enabled
     }
 
-    # Generate one module .zip file per APK.
+    if (_synchronized_proguard_enabled) {
+      # Proguard all modules together to keep binary size small while still
+      # maintaining compatibility between modules.
+      _proguard_output_jar_path =
+          "${target_gen_dir}/${target_name}/${target_name}.proguard.jar"
+      _sync_proguard_target = "${target_name}__sync_proguard"
+      proguard(_sync_proguard_target) {
+        build_config = _build_config
+        deps = _module_targets + [ ":$_build_config_target" ]
+
+        output_jar_path = _proguard_output_jar_path
+        args = [
+          "--proguard-configs=@FileArg($_rebased_build_config:deps_info:proguard_all_configs)",
+          "--input-paths=@FileArg($_rebased_build_config:deps_info:java_runtime_classpath)",
+        ]
+
+        if (defined(invoker.proguard_jar_path)) {
+          proguard_jar_path = invoker.proguard_jar_path
+        }
+      }
+    }
+
     _all_create_module_targets = []
     _all_module_zip_paths = []
     _all_module_build_configs = []
     foreach(_module, _all_modules) {
+      _module_target = _module.module_target
+      _module_target_name = get_label_info(_module_target, "name")
+      _module_target_gen_dir = get_label_info(_module_target, "target_gen_dir")
+      _module_build_config_target = "${_module_target}__build_config"
+      _module_build_config =
+          "$_module_target_gen_dir/${_module_target_name}.build_config"
+
+      if (_synchronized_proguard_enabled) {
+        # Extract optimized classes for each module and dex them.
+
+        _module_final_dex_target = "${target_name}__${_module.name}__dex"
+        _module_final_dex_target_dep = ":$_module_final_dex_target"
+        _module_final_dex_path =
+            "$target_gen_dir/$target_name/${_module.name}/classes.dex"
+        _module_final_dex_path_file_arg =
+            rebase_path(_module_final_dex_path, root_build_dir)
+
+        _module_jar_path =
+            "${target_gen_dir}/${target_name}/${_module.name}.optimized.jar"
+        _generate_proguarded_module_jar_target =
+            "${target_name}__${_module.name}__module_jar"
+        generate_proguarded_module_jar(_generate_proguarded_module_jar_target) {
+          proguarded_jar = _proguard_output_jar_path
+          build_config = _module_build_config
+          proguard_mapping = "${_proguard_output_jar_path}.mapping"
+          output_jar = _module_jar_path
+          is_base_module = _module.name == "base"
+          deps = [
+            ":${_sync_proguard_target}",
+            "$_module_build_config_target",
+            "${_module.module_target}",
+          ]
+        }
+
+        dex(_module_final_dex_target) {
+          deps = [
+            ":${_generate_proguarded_module_jar_target}",
+          ]
+          input_jars = [ _module_jar_path ]
+          output = _module_final_dex_path
+
+          # http://crbug.com/725224. Fix for bots running out of memory.
+          use_pool = true
+        }
+      } else {
+        _module_final_dex_target_dep = "${_module_target}__final_dex"
+        _rebased_module_build_config =
+            rebase_path(_module_build_config, root_build_dir)
+        _module_final_dex_path_file_arg =
+            "@FileArg($_rebased_module_build_config:final_dex:path)"
+      }
+
+      # Generate one module .zip file per bundle module.
+      #
       # Important: the bundle tool uses the module's zip filename as
       # the internal module name inside the final bundle, in other words,
       # this file *must* be named ${_module.name}.zip
       _create_module_target = "${target_name}__${_module.name}__create"
       _module_zip_path = "$target_gen_dir/$target_name/${_module.name}.zip"
-      _module_target = _module.module_target
-      _module_build_config_target = "${_module_target}__build_config"
-
-      # Determine the rebased path to the module's target .build_config
-      # In order to pass its list of uncompressed assets later.
-      _module_target_name = get_label_info(_module_target, "name")
-      _module_target_gen_dir = get_label_info(_module_target, "target_gen_dir")
-      _module_build_config =
-          "$_module_target_gen_dir/${_module_target_name}.build_config"
 
       create_android_app_bundle_module(_create_module_target) {
         build_config = _module_build_config
         module_zip_path = _module_zip_path
+        dex_path_file_arg = _module_final_dex_path_file_arg
         deps = [
           "$_module_build_config_target",
+          "$_module_final_dex_target_dep",
           "$_module_target",
         ]
       }
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 1f7de393..db2f45df 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -592,10 +592,7 @@
   # example by disabling the optimize configuration.
   # TODO(pcc): Make this conditional on is_official_build rather than on gn
   # flags for specific features.
-  if (!is_debug && use_thin_lto &&
-      (current_toolchain == default_toolchain ||
-       (is_android && defined(android_secondary_abi_toolchain) &&
-        current_toolchain == android_secondary_abi_toolchain))) {
+  if (!is_debug && use_thin_lto && current_toolchain == default_toolchain) {
     assert(use_lld || target_os == "chromeos",
            "gold plugin only supported with ChromeOS")
 
@@ -1473,9 +1470,6 @@
           # TODO(thakis): Only for no_chromium_code? http://crbug.com/505314
           "-Wno-ignored-pragma-optimize",
         ]
-        if (llvm_force_head_revision) {
-          cflags += [ "-Wno-memset-transposed-args" ]
-        }
       }
     }
   }
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index cb8630d6..0b13302 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -43,7 +43,7 @@
 
   # Enables support for ThinLTO, which links 3x-10x faster than full LTO. See
   # also http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html
-  use_thin_lto = is_cfi || (is_android && is_official_build)
+  use_thin_lto = is_cfi
 
   # Tell VS to create a PDB that references information in .obj files rather
   # than copying it all. This should improve linker performance. mspdbcmf.exe
diff --git a/build/config/coverage/BUILD.gn b/build/config/coverage/BUILD.gn
index fb37787..6fd4fd5f 100644
--- a/build/config/coverage/BUILD.gn
+++ b/build/config/coverage/BUILD.gn
@@ -17,10 +17,25 @@
       "-mllvm",
       "-limited-coverage-experimental=true",
     ]
-    ldflags = [ "-fprofile-instr-generate" ]
 
+    ldflags = []
     if (!is_win) {
+      ldflags += [ "-fprofile-instr-generate" ]
       cflags += [ "-fno-use-cxa-atexit" ]
+    } else {
+      # Windows directly calls link.exe instead of the compiler driver when
+      # linking.  Hence, pass the runtime libraries instead of
+      # -fsanitize=address.
+      # TODO(rnk): Come up with a more uniform approach for linking against
+      # compiler-rt for sanitizers and coverage.
+      if (target_cpu == "x64") {
+        ldflags += [ "clang_rt.profile-x86_64.lib" ]
+      } else if (target_cpu == "x86") {
+        ldflags += [ "clang_rt.profile-i386.lib" ]
+      } else {
+        assert(false &&
+               "use_clang_coverage=true not supported yet for this target_cpu")
+      }
     }
   }
 }
diff --git a/build/fuchsia/sdk.sha1 b/build/fuchsia/sdk.sha1
index e8b9ca0..b1cade3 100644
--- a/build/fuchsia/sdk.sha1
+++ b/build/fuchsia/sdk.sha1
@@ -1 +1 @@
-be1455d02b09799d1150be98feab598f91f00200
\ No newline at end of file
+0e8488b5f1c0c1cdb03f50b262f3d61cbbe9c96a
\ No newline at end of file
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 4909496..8b819ee 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1609,12 +1609,15 @@
   sign_bundle = is_official_build
 
   enable_language_splits = true
+  synchronized_proguard_enabled = !is_java_debug
 }
 
 android_app_bundle("chrome_modern_public_bundle") {
   base_module_target = ":chrome_modern_public_base_module"
+  synchronized_proguard_enabled = !is_java_debug
 }
 
 android_app_bundle("monochrome_public_bundle") {
   base_module_target = ":monochrome_public_base_module"
+  synchronized_proguard_enabled = !is_java_debug
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinder.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinder.java
index 4431679..6591a5b8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinder.java
@@ -158,6 +158,8 @@
         // https://w3c.github.io/webpayments-methods-credit-transfer-direct-debit/
         supportedNonUriPaymentMethods.add("payee-credit-transfer");
         supportedNonUriPaymentMethods.add("payer-credit-transfer");
+        // https://w3c.github.io/webpayments-methods-tokenization/
+        supportedNonUriPaymentMethods.add("tokenized-card");
 
         mNonUriPaymentMethods = new HashSet<>();
         mUriPaymentMethods = new HashSet<>();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java b/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java
index f2e3a465..f3e4ba7e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java
@@ -63,7 +63,8 @@
 
     /**
      * Reasons that the user was rejected from being selected for a survey
-     *  Note: these values must match the SurveyFilteringResult enum in enums.xml.
+     * Note: these values cannot change and must match the SurveyFilteringResult enum in enums.xml
+     * because they're written to logs.
      */
     @IntDef({FilteringResult.SURVEY_INFOBAR_ALREADY_DISPLAYED,
             FilteringResult.FORCE_SURVEY_ON_COMMAND_PRESENT,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java
index 7ed11b3..f0c7e60 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinderTest.java
@@ -1062,24 +1062,27 @@
         methods.add("interledger");
         methods.add("payee-credit-transfer");
         methods.add("payer-credit-transfer");
+        methods.add("tokenized-card");
         methods.add("not-supported");
         mPackageManager.installPaymentApp("AlicePay", "com.alicepay",
                 "" /* no default payment method name in metadata */, "AA");
         mPackageManager.setStringArrayMetaData("com.alicepay",
                 new String[] {"basic-card", "interledger", "payee-credit-transfer",
-                        "payer-credit-transfer", "not-supported"});
+                        "payer-credit-transfer", "tokenized-card", "not-supported"});
 
         findApps(methods);
 
         Assert.assertEquals("1 app should match the query", 1, mPaymentApps.size());
         Assert.assertEquals("com.alicepay", mPaymentApps.get(0).getAppIdentifier());
-        Assert.assertEquals(4, mPaymentApps.get(0).getAppMethodNames().size());
+        Assert.assertEquals(5, mPaymentApps.get(0).getAppMethodNames().size());
         Assert.assertTrue(mPaymentApps.get(0).getAppMethodNames().contains("basic-card"));
         Assert.assertTrue(mPaymentApps.get(0).getAppMethodNames().contains("interledger"));
         Assert.assertTrue(
                 mPaymentApps.get(0).getAppMethodNames().contains("payee-credit-transfer"));
         Assert.assertTrue(
                 mPaymentApps.get(0).getAppMethodNames().contains("payer-credit-transfer"));
+        Assert.assertTrue(
+                mPaymentApps.get(0).getAppMethodNames().contains("tokenized-card"));
 
         mPaymentApps.clear();
         mAllPaymentAppsCreated = false;
@@ -1088,13 +1091,15 @@
 
         Assert.assertEquals("1 app should still match the query", 1, mPaymentApps.size());
         Assert.assertEquals("com.alicepay", mPaymentApps.get(0).getAppIdentifier());
-        Assert.assertEquals(4, mPaymentApps.get(0).getAppMethodNames().size());
+        Assert.assertEquals(5, mPaymentApps.get(0).getAppMethodNames().size());
         Assert.assertTrue(mPaymentApps.get(0).getAppMethodNames().contains("basic-card"));
         Assert.assertTrue(mPaymentApps.get(0).getAppMethodNames().contains("interledger"));
         Assert.assertTrue(
                 mPaymentApps.get(0).getAppMethodNames().contains("payee-credit-transfer"));
         Assert.assertTrue(
                 mPaymentApps.get(0).getAppMethodNames().contains("payer-credit-transfer"));
+        Assert.assertTrue(
+                mPaymentApps.get(0).getAppMethodNames().contains("tokenized-card"));
     }
 
     private void findApps(final Set<String> methodNames) throws Throwable {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
index 0d91baf..c538317 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
@@ -327,13 +327,14 @@
         });
     }
 
+    @IntDef({MenuItemState.DISABLED, MenuItemState.ENABLED})
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({MENU_ITEM_STATE_DISABLED, MENU_ITEM_STATE_ENABLED})
-    private @interface MenuItemState {}
-    /** Represents the state of an enabled menu item. */
-    private static final int MENU_ITEM_STATE_DISABLED = 0;
-    /** Represents the state of a disabled menu item. */
-    private static final int MENU_ITEM_STATE_ENABLED = 1;
+    private @interface MenuItemState {
+        /** Represents the state of an enabled menu item. */
+        int DISABLED = 0;
+        /** Represents the state of a disabled menu item. */
+        int ENABLED = 1;
+    }
 
     /**
      * Checks that the menu item for exporting passwords is enabled or disabled as expected.
@@ -343,7 +344,7 @@
         openActionBarOverflowOrOptionsMenu(
                 InstrumentationRegistry.getInstrumentation().getTargetContext());
         final Matcher<View> stateMatcher =
-                expectedState == MENU_ITEM_STATE_ENABLED ? isEnabled() : not(isEnabled());
+                expectedState == MenuItemState.ENABLED ? isEnabled() : not(isEnabled());
         // The text matches a text view, but the disabled entity is some wrapper two levels up in
         // the view hierarchy, hence the two withParent matchers.
         Espresso.onView(allOf(withText(R.string.save_password_preferences_export_action_title),
@@ -552,7 +553,7 @@
                 PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
                         SavePasswordsPreferences.class.getName());
 
-        checkExportMenuItemState(MENU_ITEM_STATE_DISABLED);
+        checkExportMenuItemState(MenuItemState.DISABLED);
     }
 
     /**
@@ -571,7 +572,7 @@
                 PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
                         SavePasswordsPreferences.class.getName());
 
-        checkExportMenuItemState(MENU_ITEM_STATE_ENABLED);
+        checkExportMenuItemState(MenuItemState.ENABLED);
     }
 
     /**
@@ -717,7 +718,7 @@
                 .check(doesNotExist());
 
         // Check that the export menu item is enabled, because the current export was cancelled.
-        checkExportMenuItemState(MENU_ITEM_STATE_ENABLED);
+        checkExportMenuItemState(MenuItemState.ENABLED);
     }
 
     /**
@@ -774,7 +775,7 @@
                 .perform(click());
 
         // Check that for re-triggering, the export menu item is enabled.
-        checkExportMenuItemState(MENU_ITEM_STATE_ENABLED);
+        checkExportMenuItemState(MenuItemState.ENABLED);
     }
 
     /**
@@ -807,7 +808,7 @@
                 preferences.getFragmentForTest().onResume();
             }
         });
-        checkExportMenuItemState(MENU_ITEM_STATE_ENABLED);
+        checkExportMenuItemState(MenuItemState.ENABLED);
     }
 
     /**
@@ -994,7 +995,7 @@
 
         // Check that the cancellation succeeded by checking that the export menu is available and
         // enabled.
-        checkExportMenuItemState(MENU_ITEM_STATE_ENABLED);
+        checkExportMenuItemState(MenuItemState.ENABLED);
     }
 
     /**
@@ -1034,7 +1035,7 @@
 
         // Check that the cancellation succeeded by checking that the export menu is available and
         // enabled.
-        checkExportMenuItemState(MENU_ITEM_STATE_ENABLED);
+        checkExportMenuItemState(MenuItemState.ENABLED);
     }
 
     /**
@@ -1081,7 +1082,7 @@
 
         // Check that the export flow was cancelled automatically by checking that the export menu
         // is available and enabled.
-        checkExportMenuItemState(MENU_ITEM_STATE_ENABLED);
+        checkExportMenuItemState(MenuItemState.ENABLED);
     }
 
     /**
@@ -1114,7 +1115,7 @@
 
         // Check that the cancellation succeeded by checking that the export menu is available and
         // enabled.
-        checkExportMenuItemState(MENU_ITEM_STATE_ENABLED);
+        checkExportMenuItemState(MenuItemState.ENABLED);
     }
 
     /**
@@ -1279,7 +1280,7 @@
 
         // Check that the cancellation succeeded by checking that the export menu is available and
         // enabled.
-        checkExportMenuItemState(MENU_ITEM_STATE_ENABLED);
+        checkExportMenuItemState(MenuItemState.ENABLED);
 
         Assert.assertEquals(1, userAbortedDelta.getDelta());
     }
@@ -1322,7 +1323,7 @@
 
         // Check that the cancellation succeeded by checking that the export menu is available and
         // enabled.
-        checkExportMenuItemState(MENU_ITEM_STATE_ENABLED);
+        checkExportMenuItemState(MenuItemState.ENABLED);
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ssl/CaptivePortalTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ssl/CaptivePortalTest.java
index ff2df33..ebb7065 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ssl/CaptivePortalTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ssl/CaptivePortalTest.java
@@ -49,29 +49,30 @@
     private static final int INTERSTITIAL_TITLE_UPDATE_TIMEOUT_SECONDS = 5;
 
     // UMA events copied from ssl_error_handler.h.
-    @IntDef({
-            HANDLE_ALL, SHOW_CAPTIVE_PORTAL_INTERSTITIAL_NONOVERRIDABLE,
-            SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE, SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE,
-            SHOW_SSL_INTERSTITIAL_OVERRIDABLE, WWW_MISMATCH_FOUND, WWW_MISMATCH_URL_AVAILABLE,
-            WWW_MISMATCH_URL_NOT_AVAILABLE, SHOW_BAD_CLOCK, CAPTIVE_PORTAL_CERT_FOUND,
-            WWW_MISMATCH_FOUND_IN_SAN, SHOW_MITM_SOFTWARE_INTERSTITIAL, OS_REPORTS_CAPTIVE_PORTAL,
-    })
+    @IntDef({UMAEvent.HANDLE_ALL, UMAEvent.SHOW_CAPTIVE_PORTAL_INTERSTITIAL_NONOVERRIDABLE,
+            UMAEvent.SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE,
+            UMAEvent.SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE,
+            UMAEvent.SHOW_SSL_INTERSTITIAL_OVERRIDABLE, UMAEvent.WWW_MISMATCH_FOUND,
+            UMAEvent.WWW_MISMATCH_URL_AVAILABLE, UMAEvent.WWW_MISMATCH_URL_NOT_AVAILABLE,
+            UMAEvent.SHOW_BAD_CLOCK, UMAEvent.CAPTIVE_PORTAL_CERT_FOUND,
+            UMAEvent.WWW_MISMATCH_FOUND_IN_SAN, UMAEvent.SHOW_MITM_SOFTWARE_INTERSTITIAL,
+            UMAEvent.OS_REPORTS_CAPTIVE_PORTAL})
     @Retention(RetentionPolicy.SOURCE)
-    private @interface UMAEvent {}
-    private static final int HANDLE_ALL = 0;
-    private static final int SHOW_CAPTIVE_PORTAL_INTERSTITIAL_NONOVERRIDABLE = 1;
-    private static final int SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE = 2;
-    private static final int SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE = 3;
-    private static final int SHOW_SSL_INTERSTITIAL_OVERRIDABLE = 4;
-    private static final int WWW_MISMATCH_FOUND =
-            5; // Deprecated in M59 by WWW_MISMATCH_FOUND_IN_SAN.
-    private static final int WWW_MISMATCH_URL_AVAILABLE = 6;
-    private static final int WWW_MISMATCH_URL_NOT_AVAILABLE = 7;
-    private static final int SHOW_BAD_CLOCK = 8;
-    private static final int CAPTIVE_PORTAL_CERT_FOUND = 9;
-    private static final int WWW_MISMATCH_FOUND_IN_SAN = 10;
-    private static final int SHOW_MITM_SOFTWARE_INTERSTITIAL = 11;
-    private static final int OS_REPORTS_CAPTIVE_PORTAL = 12;
+    private @interface UMAEvent {
+        int HANDLE_ALL = 0;
+        int SHOW_CAPTIVE_PORTAL_INTERSTITIAL_NONOVERRIDABLE = 1;
+        int SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE = 2;
+        int SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE = 3;
+        int SHOW_SSL_INTERSTITIAL_OVERRIDABLE = 4;
+        int WWW_MISMATCH_FOUND = 5; // Deprecated in M59 by WWW_MISMATCH_FOUND_IN_SAN.
+        int WWW_MISMATCH_URL_AVAILABLE = 6;
+        int WWW_MISMATCH_URL_NOT_AVAILABLE = 7;
+        int SHOW_BAD_CLOCK = 8;
+        int CAPTIVE_PORTAL_CERT_FOUND = 9;
+        int WWW_MISMATCH_FOUND_IN_SAN = 10;
+        int SHOW_MITM_SOFTWARE_INTERSTITIAL = 11;
+        int OS_REPORTS_CAPTIVE_PORTAL = 12;
+    }
 
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
@@ -136,16 +137,16 @@
 
         Assert.assertEquals(1,
                 RecordHistogram.getHistogramValueCountForTesting(
-                        "interstitial.ssl_error_handler", HANDLE_ALL));
+                        "interstitial.ssl_error_handler", UMAEvent.HANDLE_ALL));
         Assert.assertEquals(1,
                 RecordHistogram.getHistogramValueCountForTesting("interstitial.ssl_error_handler",
-                        SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE));
+                        UMAEvent.SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE));
         Assert.assertEquals(1,
                 RecordHistogram.getHistogramValueCountForTesting(
-                        "interstitial.ssl_error_handler", CAPTIVE_PORTAL_CERT_FOUND));
+                        "interstitial.ssl_error_handler", UMAEvent.CAPTIVE_PORTAL_CERT_FOUND));
         Assert.assertEquals(0,
                 RecordHistogram.getHistogramValueCountForTesting(
-                        "interstitial.ssl_error_handler", OS_REPORTS_CAPTIVE_PORTAL));
+                        "interstitial.ssl_error_handler", UMAEvent.OS_REPORTS_CAPTIVE_PORTAL));
     }
 
     @Test
@@ -155,16 +156,16 @@
 
         Assert.assertEquals(1,
                 RecordHistogram.getHistogramValueCountForTesting(
-                        "interstitial.ssl_error_handler", HANDLE_ALL));
+                        "interstitial.ssl_error_handler", UMAEvent.HANDLE_ALL));
         Assert.assertEquals(1,
                 RecordHistogram.getHistogramValueCountForTesting("interstitial.ssl_error_handler",
-                        SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE));
+                        UMAEvent.SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE));
         Assert.assertEquals(0,
                 RecordHistogram.getHistogramValueCountForTesting(
-                        "interstitial.ssl_error_handler", CAPTIVE_PORTAL_CERT_FOUND));
+                        "interstitial.ssl_error_handler", UMAEvent.CAPTIVE_PORTAL_CERT_FOUND));
         Assert.assertEquals(1,
                 RecordHistogram.getHistogramValueCountForTesting(
-                        "interstitial.ssl_error_handler", OS_REPORTS_CAPTIVE_PORTAL));
+                        "interstitial.ssl_error_handler", UMAEvent.OS_REPORTS_CAPTIVE_PORTAL));
     }
 
     /** When CaptivePortalInterstitial feature is disabled, the result of OS captive portal
@@ -186,15 +187,15 @@
 
         Assert.assertEquals(1,
                 RecordHistogram.getHistogramValueCountForTesting(
-                        "interstitial.ssl_error_handler", HANDLE_ALL));
+                        "interstitial.ssl_error_handler", UMAEvent.HANDLE_ALL));
         Assert.assertEquals(1,
-                RecordHistogram.getHistogramValueCountForTesting(
-                        "interstitial.ssl_error_handler", SHOW_SSL_INTERSTITIAL_OVERRIDABLE));
+                RecordHistogram.getHistogramValueCountForTesting("interstitial.ssl_error_handler",
+                        UMAEvent.SHOW_SSL_INTERSTITIAL_OVERRIDABLE));
         Assert.assertEquals(0,
                 RecordHistogram.getHistogramValueCountForTesting(
-                        "interstitial.ssl_error_handler", CAPTIVE_PORTAL_CERT_FOUND));
+                        "interstitial.ssl_error_handler", UMAEvent.CAPTIVE_PORTAL_CERT_FOUND));
         Assert.assertEquals(0,
                 RecordHistogram.getHistogramValueCountForTesting(
-                        "interstitial.ssl_error_handler", OS_REPORTS_CAPTIVE_PORTAL));
+                        "interstitial.ssl_error_handler", UMAEvent.OS_REPORTS_CAPTIVE_PORTAL));
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/XrTestFramework.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/XrTestFramework.java
index 3396f50..0e8d337d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/XrTestFramework.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/XrTestFramework.java
@@ -62,12 +62,13 @@
     static final String TEST_DIR = "chrome/test/data/xr/e2e_test_files";
 
     // Test status enum
-    private static final int STATUS_RUNNING = 0;
-    private static final int STATUS_PASSED = 1;
-    private static final int STATUS_FAILED = 2;
+    @IntDef({TestStatus.RUNNING, TestStatus.PASSED, TestStatus.FAILED})
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({STATUS_RUNNING, STATUS_PASSED, STATUS_FAILED})
-    private @interface TestStatus {}
+    private @interface TestStatus {
+        int RUNNING = 0;
+        int PASSED = 1;
+        int FAILED = 2;
+    }
 
     private ChromeActivityTestRule mRule;
     protected WebContents mFirstTabWebContents;
@@ -188,8 +189,9 @@
 
         // Check what state we're in to make sure javascriptDone wasn't called because the test
         // failed.
+        @TestStatus
         int testStatus = checkTestStatus(webContents);
-        if (!success || testStatus == STATUS_FAILED) {
+        if (!success || testStatus == TestStatus.FAILED) {
             // Failure states: Either polling failed or polling succeeded, but because the test
             // failed.
             String reason;
@@ -225,12 +227,12 @@
         boolean testPassed = Boolean.parseBoolean(
                 runJavaScriptOrFail("testPassed", POLL_TIMEOUT_SHORT_MS, webContents));
         if (testPassed) {
-            return STATUS_PASSED;
+            return TestStatus.PASSED;
         } else if (!testPassed && resultString.equals("\"\"")) {
-            return STATUS_RUNNING;
+            return TestStatus.RUNNING;
         } else {
             // !testPassed && !resultString.equals("\"\"")
-            return STATUS_FAILED;
+            return TestStatus.FAILED;
         }
     }
 
@@ -242,14 +244,14 @@
      */
     public static void endTest(WebContents webContents) {
         switch (checkTestStatus(webContents)) {
-            case STATUS_PASSED:
+            case TestStatus.PASSED:
                 break;
-            case STATUS_FAILED:
+            case TestStatus.FAILED:
                 String resultString =
                         runJavaScriptOrFail("resultString", POLL_TIMEOUT_SHORT_MS, webContents);
                 Assert.fail("JavaScript testharness failed with result: " + resultString);
                 break;
-            case STATUS_RUNNING:
+            case TestStatus.RUNNING:
                 Assert.fail("Attempted to end test in Java without finishing in JavaScript.");
                 break;
             default:
@@ -267,7 +269,7 @@
      * @param webContents The Webcontents for the tab to check for failures in.
      */
     public static void assertNoJavaScriptErrors(WebContents webContents) {
-        Assert.assertNotEquals(checkTestStatus(webContents), STATUS_FAILED);
+        Assert.assertNotEquals(checkTestStatus(webContents), TestStatus.FAILED);
     }
 
     /**
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 759eb1e..1ceb8ced 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -183,8 +183,8 @@
   <message name="IDS_MULTIDEVICE_SETUP_START_SETUP_PAGE_INSTALL_APPS_DESCRIPTION" desc="Tell the user that Better Together can install apps on their Chromebook">
     Install apps on your Chromebook
   </message>
-  <message name="IDS_MULTIDEVICE_SETUP_START_SETUP_PAGE_ADD_FEATURES" desc="Tell the user that Better Together can add new features to that use their phone's connection to their Chromebook">
-    Add new features that use your phone's connection to your Chromebook
+  <message name="IDS_MULTIDEVICE_SETUP_START_SETUP_PAGE_ADD_FEATURES" desc="Tell the user that Better Together can offer to add new features to that use their phone's connection to their Chromebook">
+    Offer new features that use your phone's connection to your Chromebook
   </message>
 
   <!-- MultiDevice 'Forget device' dialog -->
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 2bc240e..e7efb90 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -3857,6 +3857,12 @@
     <message name="IDS_SETTINGS_KEYBOARD_KEY_DISABLED" desc="In Device Settings, the dropdown list item for a disabled key.">
       Disabled
     </message>
+    <message name="IDS_SETTINGS_KEYBOARD_KEY_EXTERNAL_COMMAND" desc="In Device Settings, the dropdown list item for the external Command key on Apple keyboards.">
+      External Command
+    </message>
+    <message name="IDS_SETTINGS_KEYBOARD_KEY_EXTERNAL_META" desc="In Device Settings, the dropdown list item for the external Meta key (Search key on ChromeOS keyboards, and Windows key on Windows keyboards).">
+      External Meta
+    </message>
     <message name="IDS_SETTINGS_KEYBOARD_SEND_FUNCTION_KEYS" desc="In Device Settings, the checkbox label for interpreting the top-row keys as function keys instead.">
       Treat top-row keys as function keys
     </message>
diff --git a/chrome/browser/chromeos/app_mode/kiosk_external_updater.cc b/chrome/browser/chromeos/app_mode/kiosk_external_updater.cc
index 68a34e79..5a39756 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_external_updater.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_external_updater.cc
@@ -105,19 +105,6 @@
     disks::DiskMountManager::GetInstance()->RemoveObserver(this);
 }
 
-void KioskExternalUpdater::OnAutoMountableDiskEvent(
-    disks::DiskMountManager::DiskEvent event,
-    const disks::DiskMountManager::Disk& disk) {}
-
-void KioskExternalUpdater::OnBootDeviceDiskEvent(
-    disks::DiskMountManager::DiskEvent event,
-    const disks::DiskMountManager::Disk& disk) {}
-
-void KioskExternalUpdater::OnDeviceEvent(
-    disks::DiskMountManager::DeviceEvent event,
-    const std::string& device_path) {
-}
-
 void KioskExternalUpdater::OnMountEvent(
     disks::DiskMountManager::MountEvent event,
     MountError error_code,
diff --git a/chrome/browser/chromeos/app_mode/kiosk_external_updater.h b/chrome/browser/chromeos/app_mode/kiosk_external_updater.h
index 22c72649..2f7e732 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_external_updater.h
+++ b/chrome/browser/chromeos/app_mode/kiosk_external_updater.h
@@ -57,14 +57,6 @@
   };
 
   // disks::DiskMountManager::Observer overrides.
-  void OnAutoMountableDiskEvent(
-      disks::DiskMountManager::DiskEvent event,
-      const disks::DiskMountManager::Disk& disk) override;
-  void OnBootDeviceDiskEvent(
-      disks::DiskMountManager::DiskEvent event,
-      const disks::DiskMountManager::Disk& disk) override;
-  void OnDeviceEvent(disks::DiskMountManager::DeviceEvent event,
-                     const std::string& device_path) override;
   void OnMountEvent(
       disks::DiskMountManager::MountEvent event,
       MountError error_code,
diff --git a/chrome/browser/chromeos/events/event_rewriter_unittest.cc b/chrome/browser/chromeos/events/event_rewriter_unittest.cc
index 5288171..a37e246 100644
--- a/chrome/browser/chromeos/events/event_rewriter_unittest.cc
+++ b/chrome/browser/chromeos/events/event_rewriter_unittest.cc
@@ -66,10 +66,11 @@
     ui::KeyboardCode ui_keycode,
     ui::DomCode code,
     int ui_flags,  // ui::EventFlags
-    ui::DomKey key) {
+    ui::DomKey key,
+    int device_id = kKeyboardDeviceId) {
   ui::KeyEvent event(ui_type, ui_keycode, code, ui_flags, key,
                      ui::EventTimeForNow());
-  event.set_source_device_id(kKeyboardDeviceId);
+  event.set_source_device_id(device_id);
   std::unique_ptr<ui::Event> new_event;
   rewriter->RewriteEvent(event, &new_event);
   if (new_event)
@@ -86,6 +87,7 @@
     int flags;  // ui::EventFlags
     ui::DomKey::Base key;
   } input, expected;
+  int device_id = kKeyboardDeviceId;
 };
 
 std::string GetTestCaseAsString(ui::EventType ui_type,
@@ -100,9 +102,10 @@
     const KeyTestCase& test) {
   SCOPED_TRACE("\nSource:    " + GetTestCaseAsString(test.type, test.input));
   std::string expected = GetTestCaseAsString(test.type, test.expected);
-  EXPECT_EQ(expected, GetRewrittenEventAsString(
-                          rewriter, test.type, test.input.key_code,
-                          test.input.code, test.input.flags, test.input.key));
+  EXPECT_EQ(expected,
+            GetRewrittenEventAsString(rewriter, test.type, test.input.key_code,
+                                      test.input.code, test.input.flags,
+                                      test.input.key, test.device_id));
 }
 
 }  // namespace
@@ -212,6 +215,10 @@
   rewriter_->KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "Apple Keyboard");
   rewriter_->set_last_keyboard_device_id_for_testing(kKeyboardDeviceId);
 
+  // Simulate the default initialization of the Apple Command key remap pref to
+  // Ctrl.
+  chromeos::Preferences::RegisterProfilePrefs(prefs()->registry());
+
   KeyTestCase apple_keyboard_tests[] = {
       // VKEY_A, Alt modifier.
       {ui::ET_KEY_PRESSED,
@@ -251,6 +258,226 @@
 
   for (const auto& test : apple_keyboard_tests)
     CheckKeyTestCase(rewriter_, test);
+
+  // Now simulate the user remapped the Command key back to Search.
+  IntegerPrefMember command;
+  InitModifierKeyPref(&command, prefs::kLanguageRemapExternalCommandKeyTo,
+                      ui::chromeos::ModifierKey::kSearchKey);
+
+  KeyTestCase command_remapped_to_search_tests[] = {
+      // VKEY_A, Win modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_COMMAND_DOWN,
+        ui::DomKey::UNIDENTIFIED},
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_COMMAND_DOWN,
+        ui::DomKey::UNIDENTIFIED}},
+
+      // VKEY_A, Alt+Win modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
+        ui::DomKey::UNIDENTIFIED},
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
+        ui::DomKey::UNIDENTIFIED}},
+
+      // VKEY_LWIN (left Windows key), Alt modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_LWIN, ui::DomCode::META_LEFT,
+        ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::DomKey::META},
+       {ui::VKEY_LWIN, ui::DomCode::META_LEFT,
+        ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::DomKey::META}},
+
+      // VKEY_RWIN (right Windows key), Alt modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_RWIN, ui::DomCode::META_RIGHT,
+        ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::DomKey::META},
+       {ui::VKEY_LWIN, ui::DomCode::META_RIGHT,
+        ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::DomKey::META}},
+  };
+
+  for (const auto& test : command_remapped_to_search_tests)
+    CheckKeyTestCase(rewriter_, test);
+}
+
+TEST_F(EventRewriterTest, TestRewriteExternalMetaKey) {
+  // Simulate the default initialization of the Meta key on external keyboards
+  // remap pref to Search.
+  chromeos::Preferences::RegisterProfilePrefs(prefs()->registry());
+
+  // Add an internal and external keyboards.
+  rewriter_->KeyboardDeviceAddedForTesting(
+      kKeyboardDeviceId, "Internal Keyboard",
+      ui::EventRewriterChromeOS::kKbdTopRowLayoutDefault,
+      ui::INPUT_DEVICE_INTERNAL);
+  rewriter_->KeyboardDeviceAddedForTesting(
+      kKeyboardDeviceId + 1, "External Keyboard",
+      ui::EventRewriterChromeOS::kKbdTopRowLayoutDefault,
+      ui::INPUT_DEVICE_EXTERNAL);
+
+  // The Meta key on both external and internal keyboards should produce Search.
+
+  // Test internal keyboard.
+  rewriter_->set_last_keyboard_device_id_for_testing(kKeyboardDeviceId);
+  KeyTestCase default_internal_search_tests[] = {
+      // VKEY_A, Win modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_COMMAND_DOWN,
+        ui::DomKey::UNIDENTIFIED},
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_COMMAND_DOWN,
+        ui::DomKey::UNIDENTIFIED},
+       kKeyboardDeviceId},
+
+      // VKEY_A, Alt+Win modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
+        ui::DomKey::UNIDENTIFIED},
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
+        ui::DomKey::UNIDENTIFIED},
+       kKeyboardDeviceId},
+
+      // VKEY_LWIN (left Windows key), Alt modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_LWIN, ui::DomCode::META_LEFT,
+        ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::DomKey::META},
+       {ui::VKEY_LWIN, ui::DomCode::META_LEFT,
+        ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::DomKey::META},
+       kKeyboardDeviceId},
+
+      // VKEY_RWIN (right Windows key), Alt modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_RWIN, ui::DomCode::META_RIGHT,
+        ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::DomKey::META},
+       {ui::VKEY_LWIN, ui::DomCode::META_RIGHT,
+        ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::DomKey::META},
+       kKeyboardDeviceId},
+  };
+  for (const auto& test : default_internal_search_tests)
+    CheckKeyTestCase(rewriter_, test);
+
+  // Test external Keyboard.
+  KeyTestCase default_external_meta_tests[] = {
+      // VKEY_A, Win modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_COMMAND_DOWN,
+        ui::DomKey::UNIDENTIFIED},
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_COMMAND_DOWN,
+        ui::DomKey::UNIDENTIFIED},
+       kKeyboardDeviceId + 1},
+
+      // VKEY_A, Alt+Win modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
+        ui::DomKey::UNIDENTIFIED},
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
+        ui::DomKey::UNIDENTIFIED},
+       kKeyboardDeviceId + 1},
+
+      // VKEY_LWIN (left Windows key), Alt modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_LWIN, ui::DomCode::META_LEFT,
+        ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::DomKey::META},
+       {ui::VKEY_LWIN, ui::DomCode::META_LEFT,
+        ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::DomKey::META},
+       kKeyboardDeviceId + 1},
+
+      // VKEY_RWIN (right Windows key), Alt modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_RWIN, ui::DomCode::META_RIGHT,
+        ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::DomKey::META},
+       {ui::VKEY_LWIN, ui::DomCode::META_RIGHT,
+        ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::DomKey::META},
+       kKeyboardDeviceId + 1},
+  };
+  rewriter_->set_last_keyboard_device_id_for_testing(kKeyboardDeviceId + 1);
+  for (const auto& test : default_external_meta_tests)
+    CheckKeyTestCase(rewriter_, test);
+
+  // Both preferences for internal Search and external Meta are independent,
+  // even if one or both are modified.
+
+  // Remap internal Search to Ctrl.
+  IntegerPrefMember internal_search;
+  InitModifierKeyPref(&internal_search, prefs::kLanguageRemapSearchKeyTo,
+                      ui::chromeos::ModifierKey::kControlKey);
+
+  // Remap external Search to Alt.
+  IntegerPrefMember meta;
+  InitModifierKeyPref(&meta, prefs::kLanguageRemapExternalMetaKeyTo,
+                      ui::chromeos::ModifierKey::kAltKey);
+
+  // Test internal keyboard.
+  KeyTestCase remapped_internal_search_tests[] = {
+      // VKEY_A, Win modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_COMMAND_DOWN,
+        ui::DomKey::UNIDENTIFIED},
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_CONTROL_DOWN,
+        ui::DomKey::Constant<'a'>::Character},
+       kKeyboardDeviceId},
+
+      // VKEY_A, Alt+Win modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
+        ui::DomKey::UNIDENTIFIED},
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
+        ui::DomKey::Constant<'a'>::Character},
+       kKeyboardDeviceId},
+
+      // VKEY_LWIN (left Windows key), Alt modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_LWIN, ui::DomCode::META_LEFT,
+        ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::DomKey::META},
+       {ui::VKEY_CONTROL, ui::DomCode::CONTROL_LEFT,
+        ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, ui::DomKey::CONTROL},
+       kKeyboardDeviceId},
+
+      // VKEY_RWIN (right Windows key), Alt modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_RWIN, ui::DomCode::META_RIGHT,
+        ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::DomKey::META},
+       {ui::VKEY_CONTROL, ui::DomCode::CONTROL_RIGHT,
+        ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, ui::DomKey::CONTROL},
+       kKeyboardDeviceId},
+  };
+  rewriter_->set_last_keyboard_device_id_for_testing(kKeyboardDeviceId);
+  for (const auto& test : remapped_internal_search_tests)
+    CheckKeyTestCase(rewriter_, test);
+
+  // Test external keyboard.
+  KeyTestCase remapped_external_search_tests[] = {
+      // VKEY_A, Win modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_COMMAND_DOWN,
+        ui::DomKey::UNIDENTIFIED},
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_ALT_DOWN,
+        ui::DomKey::Constant<'a'>::Character},
+       kKeyboardDeviceId + 1},
+
+      // VKEY_A, Alt+Win modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN,
+        ui::DomKey::UNIDENTIFIED},
+       {ui::VKEY_A, ui::DomCode::US_A, ui::EF_ALT_DOWN,
+        ui::DomKey::Constant<'a'>::Character},
+       kKeyboardDeviceId + 1},
+
+      // VKEY_LWIN (left Windows key), Alt modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_LWIN, ui::DomCode::META_LEFT,
+        ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::DomKey::META},
+       {ui::VKEY_MENU, ui::DomCode::ALT_LEFT, ui::EF_ALT_DOWN, ui::DomKey::ALT},
+       kKeyboardDeviceId + 1},
+
+      // VKEY_RWIN (right Windows key), Alt modifier.
+      {ui::ET_KEY_PRESSED,
+       {ui::VKEY_RWIN, ui::DomCode::META_RIGHT,
+        ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, ui::DomKey::META},
+       {ui::VKEY_MENU, ui::DomCode::ALT_RIGHT, ui::EF_ALT_DOWN,
+        ui::DomKey::ALT},
+       kKeyboardDeviceId + 1},
+  };
+  rewriter_->set_last_keyboard_device_id_for_testing(kKeyboardDeviceId + 1);
+  for (const auto& test : remapped_external_search_tests)
+    CheckKeyTestCase(rewriter_, test);
 }
 
 // For crbug.com/133896.
@@ -488,6 +715,10 @@
 
 // Tests if the rewriter can handle a Command + Num Pad event.
 void EventRewriterTest::TestRewriteNumPadKeysOnAppleKeyboard() {
+  // Simulate the default initialization of the Apple Command key remap pref to
+  // Ctrl.
+  chromeos::Preferences::RegisterProfilePrefs(prefs()->registry());
+
   rewriter_->KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "Apple Keyboard");
   rewriter_->set_last_keyboard_device_id_for_testing(kKeyboardDeviceId);
 
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.cc b/chrome/browser/chromeos/file_manager/volume_manager.cc
index 1ff1df2..57c3a4d 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager.cc
@@ -688,10 +688,6 @@
   NOTREACHED();
 }
 
-void VolumeManager::OnBootDeviceDiskEvent(
-    chromeos::disks::DiskMountManager::DiskEvent event,
-    const chromeos::disks::DiskMountManager::Disk& disk) {}
-
 void VolumeManager::OnDeviceEvent(
     chromeos::disks::DiskMountManager::DeviceEvent event,
     const std::string& device_path) {
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.h b/chrome/browser/chromeos/file_manager/volume_manager.h
index 1e126ff..1b1fa08 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager.h
+++ b/chrome/browser/chromeos/file_manager/volume_manager.h
@@ -317,9 +317,6 @@
   void OnAutoMountableDiskEvent(
       chromeos::disks::DiskMountManager::DiskEvent event,
       const chromeos::disks::DiskMountManager::Disk& disk) override;
-  void OnBootDeviceDiskEvent(
-      chromeos::disks::DiskMountManager::DiskEvent event,
-      const chromeos::disks::DiskMountManager::Disk& disk) override;
   void OnDeviceEvent(chromeos::disks::DiskMountManager::DeviceEvent event,
                      const std::string& device_path) override;
   void OnMountEvent(chromeos::disks::DiskMountManager::MountEvent event,
diff --git a/chrome/browser/chromeos/login/lock/views_screen_locker.cc b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
index 29b027b..400c1dc 100644
--- a/chrome/browser/chromeos/login/lock/views_screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
@@ -81,10 +81,9 @@
 void ViewsScreenLocker::Init() {
   lock_time_ = base::TimeTicks::Now();
   user_selection_screen_->Init(screen_locker_->users());
-  LoginScreenClient::Get()->login_screen()->SetUserList(
-      user_selection_screen_->UpdateAndReturnUserListForMojo());
-  LoginScreenClient::Get()->login_screen()->SetAllowLoginAsGuest(
-      false /*show_guest*/);
+  LoginScreenClient::Get()->login_screen()->LoadUsers(
+      user_selection_screen_->UpdateAndReturnUserListForMojo(),
+      false /* show_guests */);
   if (!ime_state_.get())
     ime_state_ = input_method::InputMethodManager::Get()->GetActiveIMEState();
 
diff --git a/chrome/browser/chromeos/login/ui/login_display_mojo.cc b/chrome/browser/chromeos/login/ui/login_display_mojo.cc
index 7d4249d1..e5097be 100644
--- a/chrome/browser/chromeos/login/ui/login_display_mojo.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_mojo.cc
@@ -74,9 +74,8 @@
 
   UserSelectionScreen* user_selection_screen = host_->user_selection_screen();
   user_selection_screen->Init(filtered_users);
-  client->login_screen()->SetUserList(
-      user_selection_screen->UpdateAndReturnUserListForMojo());
-  client->login_screen()->SetAllowLoginAsGuest(show_guest);
+  client->login_screen()->LoadUsers(
+      user_selection_screen->UpdateAndReturnUserListForMojo(), show_guest);
   user_selection_screen->SetUsersLoaded(true /*loaded*/);
 
   // Enable pin for any users who can use it.
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 1f842c4..bc94e4d 100644
--- a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
+++ b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.h"
 
 #include "ash/public/cpp/shell_window_ids.h"
-#include "ash/public/interfaces/login_screen.mojom.h"
 #include "chrome/browser/chromeos/login/screens/gaia_view.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host_mojo.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -95,8 +94,7 @@
 }
 
 void OobeUIDialogDelegate::Show() {
-  LoginScreenClient::Get()->login_screen()->NotifyOobeDialogState(
-      ash::mojom::OobeDialogState::GAIA_SIGNIN);
+  LoginScreenClient::Get()->login_screen()->NotifyOobeDialogVisibility(true);
   dialog_widget_->Show();
 }
 
@@ -113,16 +111,14 @@
 void OobeUIDialogDelegate::Hide() {
   if (!dialog_widget_)
     return;
-  LoginScreenClient::Get()->login_screen()->NotifyOobeDialogState(
-      ash::mojom::OobeDialogState::HIDDEN);
+  LoginScreenClient::Get()->login_screen()->NotifyOobeDialogVisibility(false);
   dialog_widget_->Hide();
 }
 
 void OobeUIDialogDelegate::Close() {
   if (!dialog_widget_)
     return;
-  LoginScreenClient::Get()->login_screen()->NotifyOobeDialogState(
-      ash::mojom::OobeDialogState::HIDDEN);
+  LoginScreenClient::Get()->login_screen()->NotifyOobeDialogVisibility(false);
   dialog_widget_->Close();
 }
 
diff --git a/chrome/browser/chromeos/policy/app_install_event_log_collector.cc b/chrome/browser/chromeos/policy/app_install_event_log_collector.cc
index a6fcbe2..7b00403 100644
--- a/chrome/browser/chromeos/policy/app_install_event_log_collector.cc
+++ b/chrome/browser/chromeos/policy/app_install_event_log_collector.cc
@@ -65,7 +65,8 @@
       pending_packages_(pending_packages) {
   chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(
       this);
-  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
+  g_browser_process->network_connection_tracker()->AddNetworkConnectionObserver(
+      this);
   // Might not be available in unit test.
   arc::ArcPolicyBridge* const policy_bridge =
       arc::ArcPolicyBridge::GetForBrowserContext(profile_);
@@ -85,7 +86,8 @@
   }
   chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(
       this);
-  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
+  g_browser_process->network_connection_tracker()
+      ->RemoveNetworkConnectionObserver(this);
   arc::ArcPolicyBridge* const policy_bridge =
       arc::ArcPolicyBridge::GetForBrowserContext(profile_);
   if (policy_bridge) {
@@ -133,8 +135,8 @@
       CreateSessionChangeEvent(em::AppInstallReportLogEvent::RESUME));
 }
 
-void AppInstallEventLogCollector::OnNetworkChanged(
-    net::NetworkChangeNotifier::ConnectionType type) {
+void AppInstallEventLogCollector::OnConnectionChanged(
+    network::mojom::ConnectionType type) {
   const bool currently_online = GetOnlineState();
   if (currently_online == online_) {
     return;
diff --git a/chrome/browser/chromeos/policy/app_install_event_log_collector.h b/chrome/browser/chromeos/policy/app_install_event_log_collector.h
index 7394f7e..6f7ac761 100644
--- a/chrome/browser/chromeos/policy/app_install_event_log_collector.h
+++ b/chrome/browser/chromeos/policy/app_install_event_log_collector.h
@@ -18,7 +18,7 @@
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chromeos/dbus/power_manager_client.h"
 #include "components/arc/common/policy.mojom.h"
-#include "net/base/network_change_notifier.h"
+#include "content/public/browser/network_connection_tracker.h"
 
 class Profile;
 
@@ -31,7 +31,7 @@
 class AppInstallEventLogCollector
     : public chromeos::PowerManagerClient::Observer,
       public arc::ArcPolicyBridge::Observer,
-      public net::NetworkChangeNotifier::NetworkChangeObserver,
+      public content::NetworkConnectionTracker::NetworkConnectionObserver,
       public ArcAppListPrefs::Observer {
  public:
   // The delegate that events are forwarded to for inclusion in the log.
@@ -76,9 +76,8 @@
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
   void SuspendDone(const base::TimeDelta& sleep_duration) override;
 
-  // net::NetworkChangeNotifier::NetworkChangeObserver:
-  void OnNetworkChanged(
-      net::NetworkChangeNotifier::ConnectionType type) override;
+  // content::NetworkConnectionTracker::NetworkConnectionObserver:
+  void OnConnectionChanged(network::mojom::ConnectionType type) override;
 
   // arc::ArcPolicyBridge::Observer:
   void OnCloudDpsRequested(base::Time time,
diff --git a/chrome/browser/chromeos/policy/app_install_event_log_collector_unittest.cc b/chrome/browser/chromeos/policy/app_install_event_log_collector_unittest.cc
index b6b6ed0..21f291f 100644
--- a/chrome/browser/chromeos/policy/app_install_event_log_collector_unittest.cc
+++ b/chrome/browser/chromeos/policy/app_install_event_log_collector_unittest.cc
@@ -120,8 +120,6 @@
     chromeos::DBusThreadManager::Initialize();
     chromeos::NetworkHandler::Initialize();
     profile_ = std::make_unique<TestingProfile>();
-    network_change_notifier_ =
-        base::WrapUnique(net::NetworkChangeNotifier::CreateMock());
 
     service_test_ = chromeos::DBusThreadManager::Get()
                         ->GetShillServiceClient()
@@ -146,27 +144,29 @@
     TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
   }
 
-  void SetNetworkState(const std::string& service_path,
-                       const std::string& state) {
+  void SetNetworkState(
+      content::NetworkConnectionTracker::NetworkConnectionObserver* observer,
+      const std::string& service_path,
+      const std::string& state) {
     service_test_->SetServiceProperty(service_path, shill::kStateProperty,
                                       base::Value(state));
     base::RunLoop().RunUntilIdle();
 
-    net::NetworkChangeNotifier::ConnectionType connection_type =
-        net::NetworkChangeNotifier::CONNECTION_NONE;
+    network::mojom::ConnectionType connection_type =
+        network::mojom::ConnectionType::CONNECTION_NONE;
     std::string network_state;
     service_test_->GetServiceProperties(kWifiServicePath)
         ->GetString(shill::kStateProperty, &network_state);
     if (network_state == shill::kStateOnline) {
-      connection_type = net::NetworkChangeNotifier::CONNECTION_WIFI;
+      connection_type = network::mojom::ConnectionType::CONNECTION_WIFI;
     }
     service_test_->GetServiceProperties(kEthernetServicePath)
         ->GetString(shill::kStateProperty, &network_state);
     if (network_state == shill::kStateOnline) {
-      connection_type = net::NetworkChangeNotifier::CONNECTION_ETHERNET;
+      connection_type = network::mojom::ConnectionType::CONNECTION_ETHERNET;
     }
-    net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
-        connection_type);
+    if (observer)
+      observer->OnConnectionChanged(connection_type);
     base::RunLoop().RunUntilIdle();
   }
 
@@ -179,7 +179,6 @@
 
   const std::set<std::string> packages_ = {kPackageName};
 
-  std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
   chromeos::ShillServiceClient::TestInterface* service_test_ = nullptr;
 
  private:
@@ -301,7 +300,7 @@
 // to WiFi with a pending captive portal. Verify that no event is recorded.
 // Then, pass the captive portal. Verify that a connectivity change is recorded.
 TEST_F(AppInstallEventLogCollectorTest, ConnectivityChanges) {
-  SetNetworkState(kEthernetServicePath, shill::kStateOnline);
+  SetNetworkState(nullptr, kEthernetServicePath, shill::kStateOnline);
 
   std::unique_ptr<AppInstallEventLogCollector> collector =
       std::make_unique<AppInstallEventLogCollector>(delegate(), profile(),
@@ -317,22 +316,22 @@
             delegate()->last_event().session_state_change_type());
   EXPECT_TRUE(delegate()->last_event().online());
 
-  SetNetworkState(kWifiServicePath, shill::kStateOnline);
+  SetNetworkState(collector.get(), kWifiServicePath, shill::kStateOnline);
   EXPECT_EQ(1, delegate()->add_for_all_count());
 
-  SetNetworkState(kEthernetServicePath, shill::kStateOffline);
+  SetNetworkState(collector.get(), kEthernetServicePath, shill::kStateOffline);
   EXPECT_EQ(1, delegate()->add_for_all_count());
 
-  SetNetworkState(kWifiServicePath, shill::kStateOffline);
+  SetNetworkState(collector.get(), kWifiServicePath, shill::kStateOffline);
   EXPECT_EQ(2, delegate()->add_for_all_count());
   EXPECT_EQ(em::AppInstallReportLogEvent::CONNECTIVITY_CHANGE,
             delegate()->last_event().event_type());
   EXPECT_FALSE(delegate()->last_event().online());
 
-  SetNetworkState(kWifiServicePath, shill::kStatePortal);
+  SetNetworkState(collector.get(), kWifiServicePath, shill::kStatePortal);
   EXPECT_EQ(2, delegate()->add_for_all_count());
 
-  SetNetworkState(kWifiServicePath, shill::kStateOnline);
+  SetNetworkState(collector.get(), kWifiServicePath, shill::kStateOnline);
   EXPECT_EQ(3, delegate()->add_for_all_count());
   EXPECT_EQ(em::AppInstallReportLogEvent::CONNECTIVITY_CHANGE,
             delegate()->last_event().event_type());
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client_impl.cc b/chrome/browser/chromeos/policy/auto_enrollment_client_impl.cc
index 9121532b..3bd6673 100644
--- a/chrome/browser/chromeos/policy/auto_enrollment_client_impl.cc
+++ b/chrome/browser/chromeos/policy/auto_enrollment_client_impl.cc
@@ -14,6 +14,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/optional.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/policy/server_backed_device_state.h"
 #include "chrome/common/chrome_content_client.h"
 #include "chrome/common/pref_names.h"
@@ -375,7 +376,8 @@
 }
 
 AutoEnrollmentClientImpl::~AutoEnrollmentClientImpl() {
-  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
+  g_browser_process->network_connection_tracker()
+      ->RemoveNetworkConnectionObserver(this);
 }
 
 // static
@@ -386,8 +388,10 @@
 
 void AutoEnrollmentClientImpl::Start() {
   // (Re-)register the network change observer.
-  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
-  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
+  g_browser_process->network_connection_tracker()
+      ->RemoveNetworkConnectionObserver(this);
+  g_browser_process->network_connection_tracker()->AddNetworkConnectionObserver(
+      this);
 
   // Drop the previous job and reset state.
   request_job_.reset();
@@ -425,9 +429,9 @@
   return state_;
 }
 
-void AutoEnrollmentClientImpl::OnNetworkChanged(
-    net::NetworkChangeNotifier::ConnectionType type) {
-  if (type != net::NetworkChangeNotifier::CONNECTION_NONE &&
+void AutoEnrollmentClientImpl::OnConnectionChanged(
+    network::mojom::ConnectionType type) {
+  if (type != network::mojom::ConnectionType::CONNECTION_NONE &&
       !progress_callback_.is_null()) {
     RetryStep();
   }
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client_impl.h b/chrome/browser/chromeos/policy/auto_enrollment_client_impl.h
index 56595c0..15742b72 100644
--- a/chrome/browser/chromeos/policy/auto_enrollment_client_impl.h
+++ b/chrome/browser/chromeos/policy/auto_enrollment_client_impl.h
@@ -15,7 +15,7 @@
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/policy/auto_enrollment_client.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
-#include "net/base/network_change_notifier.h"
+#include "content/public/browser/network_connection_tracker.h"
 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
 
 class PrefRegistrySimple;
@@ -35,7 +35,7 @@
 // OOBE.
 class AutoEnrollmentClientImpl
     : public AutoEnrollmentClient,
-      public net::NetworkChangeNotifier::NetworkChangeObserver {
+      public content::NetworkConnectionTracker::NetworkConnectionObserver {
  public:
   // Subclasses of this class provide an identifier and specify the identifier
   // set for the DeviceAutoEnrollmentRequest,
@@ -86,9 +86,8 @@
   std::string device_id() const override;
   AutoEnrollmentState state() const override;
 
-  // Implementation of net::NetworkChangeNotifier::NetworkChangeObserver:
-  void OnNetworkChanged(
-      net::NetworkChangeNotifier::ConnectionType type) override;
+  // content::NetworkConnectionTracker::NetworkConnectionObserver:
+  void OnConnectionChanged(network::mojom::ConnectionType type) override;
 
  private:
   typedef bool (AutoEnrollmentClientImpl::*RequestCompletionHandler)(
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client_impl_unittest.cc b/chrome/browser/chromeos/policy/auto_enrollment_client_impl_unittest.cc
index d07e02b..050a8cc 100644
--- a/chrome/browser/chromeos/policy/auto_enrollment_client_impl_unittest.cc
+++ b/chrome/browser/chromeos/policy/auto_enrollment_client_impl_unittest.cc
@@ -460,7 +460,8 @@
 
   // Network changes don't trigger retries after obtaining a response from
   // the server.
-  client()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+  client()->OnConnectionChanged(
+      network::mojom::ConnectionType::CONNECTION_ETHERNET);
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_);
 }
 
@@ -479,7 +480,8 @@
 
   // Network changes don't trigger retries after obtaining a response from
   // the server.
-  client()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+  client()->OnConnectionChanged(
+      network::mojom::ConnectionType::CONNECTION_ETHERNET);
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_);
 }
 
@@ -502,7 +504,8 @@
 
   // Network changes don't trigger retries after obtaining a response from
   // the server.
-  client()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+  client()->OnConnectionChanged(
+      network::mojom::ConnectionType::CONNECTION_ETHERNET);
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ZERO_TOUCH, state_);
 }
 
@@ -648,7 +651,8 @@
   EXPECT_FALSE(HasServerBackedState());
 
   // The client doesn't retry if no new connection became available.
-  client()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_NONE);
+  client()->OnConnectionChanged(
+      network::mojom::ConnectionType::CONNECTION_NONE);
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_SERVER_ERROR, state_);
   EXPECT_FALSE(HasCachedDecision());
   EXPECT_FALSE(HasServerBackedState());
@@ -659,7 +663,8 @@
       "example.com",
       em::DeviceStateRetrievalResponse::RESTORE_MODE_REENROLLMENT_ENFORCED,
       kDisabledMessage);
-  client()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+  client()->OnConnectionChanged(
+      network::mojom::ConnectionType::CONNECTION_ETHERNET);
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_);
   EXPECT_TRUE(HasCachedDecision());
   VerifyServerBackedState("example.com",
@@ -667,8 +672,10 @@
                           kDisabledMessage);
 
   // Subsequent network changes don't trigger retries.
-  client()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_NONE);
-  client()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+  client()->OnConnectionChanged(
+      network::mojom::ConnectionType::CONNECTION_NONE);
+  client()->OnConnectionChanged(
+      network::mojom::ConnectionType::CONNECTION_ETHERNET);
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_);
   EXPECT_TRUE(HasCachedDecision());
   VerifyServerBackedState("example.com",
@@ -712,7 +719,8 @@
   EXPECT_TRUE(base::MessageLoopCurrent::Get()->IsIdleForTesting());
 
   // Network change events are ignored while a request is pending.
-  client->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+  client->OnConnectionChanged(
+      network::mojom::ConnectionType::CONNECTION_ETHERNET);
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_PENDING, state_);
 
   // The client cleans itself up once a reply is received.
@@ -723,7 +731,8 @@
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_PENDING, state_);
 
   // Network changes that have been posted before are also ignored:
-  client->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+  client->OnConnectionChanged(
+      network::mojom::ConnectionType::CONNECTION_ETHERNET);
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_PENDING, state_);
 }
 
@@ -786,7 +795,8 @@
   EXPECT_CALL(*service_, StartJob(_, _, _, _, _, _));
 
   // Trigger a network change event.
-  client()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+  client()->OnConnectionChanged(
+      network::mojom::ConnectionType::CONNECTION_ETHERNET);
   EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_);
   EXPECT_TRUE(HasCachedDecision());
   VerifyServerBackedState("example.com",
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index a13c2ac..540f8f61 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -75,10 +75,15 @@
 // preferences will be saved in global user preferences dictionary so that they
 // can be used on signin screen.
 const char* const kLanguageRemapPrefs[] = {
-    prefs::kLanguageRemapSearchKeyTo, prefs::kLanguageRemapControlKeyTo,
-    prefs::kLanguageRemapAltKeyTo,    prefs::kLanguageRemapCapsLockKeyTo,
-    prefs::kLanguageRemapEscapeKeyTo, prefs::kLanguageRemapBackspaceKeyTo,
-    prefs::kLanguageRemapDiamondKeyTo};
+    prefs::kLanguageRemapSearchKeyTo,
+    prefs::kLanguageRemapControlKeyTo,
+    prefs::kLanguageRemapAltKeyTo,
+    prefs::kLanguageRemapCapsLockKeyTo,
+    prefs::kLanguageRemapEscapeKeyTo,
+    prefs::kLanguageRemapBackspaceKeyTo,
+    prefs::kLanguageRemapDiamondKeyTo,
+    prefs::kLanguageRemapExternalCommandKeyTo,
+    prefs::kLanguageRemapExternalMetaKeyTo};
 
 // Migrates kResolveTimezoneByGeolocation value to
 // kResolveTimezoneByGeolocationMethod.
@@ -352,6 +357,18 @@
       prefs::kLanguageRemapDiamondKeyTo,
       static_cast<int>(ui::chromeos::ModifierKey::kControlKey),
       user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
+  // The Command key on external Apple keyboards is remapped by default to Ctrl
+  // until the user changes it from the keyboard settings.
+  registry->RegisterIntegerPref(
+      prefs::kLanguageRemapExternalCommandKeyTo,
+      static_cast<int>(ui::chromeos::ModifierKey::kControlKey),
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
+  // The Meta key (Search or Windows keys) on external keyboards is remapped by
+  // default to Search until the user changes it from the keyboard settings.
+  registry->RegisterIntegerPref(
+      prefs::kLanguageRemapExternalMetaKeyTo,
+      static_cast<int>(ui::chromeos::ModifierKey::kSearchKey),
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
   // The following pref isn't synced since the user may desire a different value
   // depending on whether an external keyboard is attached to a particular
   // device.
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index a879491..509dce2 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -462,6 +462,10 @@
       settings_api::PrefType::PREF_TYPE_NUMBER;
   (*s_whitelist)[::prefs::kLanguageRemapDiamondKeyTo] =
       settings_api::PrefType::PREF_TYPE_NUMBER;
+  (*s_whitelist)[::prefs::kLanguageRemapExternalCommandKeyTo] =
+      settings_api::PrefType::PREF_TYPE_NUMBER;
+  (*s_whitelist)[::prefs::kLanguageRemapExternalMetaKeyTo] =
+      settings_api::PrefType::PREF_TYPE_NUMBER;
   (*s_whitelist)[::prefs::kLanguageSendFunctionKeys] =
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
   (*s_whitelist)[::prefs::kLanguageXkbAutoRepeatEnabled] =
@@ -472,8 +476,10 @@
       settings_api::PrefType::PREF_TYPE_NUMBER;
 
   // Multidevice settings.
+  (*s_whitelist)[chromeos::multidevice_setup::kSuiteEnabledPrefName] =
+      settings_api::PrefType::PREF_TYPE_BOOLEAN;
   (*s_whitelist)
-      [chromeos::multidevice_setup::kMultiDeviceSuiteEnabledPrefName] =
+      [chromeos::multidevice_setup::kAndroidMessagesFeatureEnabledPrefName] =
           settings_api::PrefType::PREF_TYPE_BOOLEAN;
 
   // Native Printing settings.
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
index 38fcd9a..45bae3a8 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
@@ -306,7 +306,14 @@
   ASSERT_TRUE(RunExtensionTest("webnavigation/simpleLoad")) << message_;
 }
 
-IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, Failures) {
+// Flaky on Windows, Mac and Linux. See http://crbug.com/477480 (Windows) and
+// https://crbug.com/746407 (Mac, Linux).
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
+#define MAYBE_Failures DISABLED_Failures
+#else
+#define MAYBE_Failures Failures
+#endif
+IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, MAYBE_Failures) {
   ASSERT_TRUE(RunExtensionTest("webnavigation/failures")) << message_;
 }
 
diff --git a/chrome/browser/media/DEPS b/chrome/browser/media/DEPS
index 6c2e8e0..4ba0b3c8 100644
--- a/chrome/browser/media/DEPS
+++ b/chrome/browser/media/DEPS
@@ -11,3 +11,9 @@
   "+services/data_decoder/public",
   "+services/device/public/mojom",
 ]
+
+specific_include_rules = {
+  "cast_remoting_connector\.cc": [
+    "+chrome/browser/ui/views/media_router/media_remoting_dialog_view.h",
+  ],
+}
diff --git a/chrome/browser/media/cast_remoting_connector.cc b/chrome/browser/media/cast_remoting_connector.cc
index 70b6cb7..3682fdf0 100644
--- a/chrome/browser/media/cast_remoting_connector.cc
+++ b/chrome/browser/media/cast_remoting_connector.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/media/cast_remoting_connector.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -24,6 +25,11 @@
 #include "content/public/browser/web_contents.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 
+#if defined(TOOLKIT_VIEWS) && \
+    (!defined(OS_MACOSX) || defined(MAC_VIEWS_BROWSER))
+#include "chrome/browser/ui/views/media_router/media_remoting_dialog_view.h"
+#endif
+
 using content::BrowserThread;
 using media::mojom::RemotingStartFailReason;
 using media::mojom::RemotingStopReason;
@@ -92,7 +98,7 @@
   }
   void Stop(RemotingStopReason reason) final {
     if (connector_)
-      connector_->StopRemoting(this, reason);
+      connector_->StopRemoting(this, reason, true);
   }
   void SendMessageToSink(const std::vector<uint8_t>& message) final {
     if (connector_)
@@ -137,7 +143,30 @@
     connector = new CastRemotingConnector(
         media_router::MediaRouterFactory::GetApiForBrowserContext(
             contents->GetBrowserContext()),
-        tab_id);
+        tab_id,
+#if defined(TOOLKIT_VIEWS) && \
+    (!defined(OS_MACOSX) || defined(MAC_VIEWS_BROWSER))
+        base::BindRepeating(
+            [](content::WebContents* contents,
+               PermissionResultCallback result_callback) {
+              if (media_router::ShouldUseViewsDialog()) {
+                media_router::MediaRemotingDialogView::GetPermission(
+                    contents, std::move(result_callback));
+                return base::BindOnce(
+                    &media_router::MediaRemotingDialogView::HideDialog);
+              } else {
+                std::move(result_callback).Run(true);
+                return CancelPermissionRequestCallback();
+              }
+            },
+            contents)
+#else
+        base::BindRepeating([](PermissionResultCallback result_callback) {
+          std::move(result_callback).Run(true);
+          return CancelPermissionRequestCallback();
+        })
+#endif
+            );
     contents->SetUserData(kUserDataKey, base::WrapUnique(connector));
   }
   return connector;
@@ -158,14 +187,18 @@
   connector->CreateBridge(std::move(source), std::move(request));
 }
 
-CastRemotingConnector::CastRemotingConnector(media_router::MediaRouter* router,
-                                             SessionID tab_id)
+CastRemotingConnector::CastRemotingConnector(
+    media_router::MediaRouter* router,
+    SessionID tab_id,
+    PermissionRequestCallback permission_request_callback)
     : media_router_(router),
       tab_id_(tab_id),
+      permission_request_callback_(std::move(permission_request_callback)),
       active_bridge_(nullptr),
       binding_(this),
       weak_factory_(this) {
   VLOG(2) << "Register CastRemotingConnector for tab_id = " << tab_id_;
+  DCHECK(permission_request_callback_);
   media_router_->RegisterRemotingSource(tab_id_, this);
 }
 
@@ -174,7 +207,7 @@
   // it's possible the owning WebContents will be destroyed before the Mojo
   // message pipes to the RemotingBridges have been closed.
   if (active_bridge_)
-    StopRemoting(active_bridge_, RemotingStopReason::ROUTE_TERMINATED);
+    StopRemoting(active_bridge_, RemotingStopReason::ROUTE_TERMINATED, false);
   for (RemotingBridge* notifyee : bridges_) {
     notifyee->OnSinkGone();
     notifyee->OnCastRemotingConnectorDestroyed();
@@ -213,7 +246,7 @@
 
   sink_metadata_ = RemotingSinkMetadata();
   if (active_bridge_)
-    StopRemoting(active_bridge_, RemotingStopReason::SERVICE_GONE);
+    StopRemoting(active_bridge_, RemotingStopReason::SERVICE_GONE, false);
   for (RemotingBridge* notifyee : bridges_)
     notifyee->OnSinkGone();
 }
@@ -239,9 +272,9 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(bridges_.find(bridge) != bridges_.end());
 
-  if (bridge == active_bridge_)
-    StopRemoting(bridge, reason);
   bridges_.erase(bridge);
+  if (bridge == active_bridge_)
+    StopRemoting(bridge, reason, true);
 }
 
 void CastRemotingConnector::StartRemoting(RemotingBridge* bridge) {
@@ -282,14 +315,15 @@
           DCHECK_CURRENTLY_ON(BrowserThread::UI);
           if (!connector)
             return;
+          connector->permission_request_cancel_callback_.Reset();
           connector->remoting_allowed_ = is_allowed;
           connector->StartRemotingIfPermitted();
         },
         weak_factory_.GetWeakPtr()));
 
-    // TODO(http://crbug.com/849020): Show the remoting dialog to get user's
-    // permission.
-    std::move(dialog_result_callback).Run(true);
+    DCHECK(!permission_request_cancel_callback_);
+    permission_request_cancel_callback_ =
+        permission_request_callback_.Run(std::move(dialog_result_callback));
   }
 }
 
@@ -331,7 +365,7 @@
   if ((!audio_pipe.is_valid() && !video_pipe.is_valid()) ||
       (audio_pipe.is_valid() && !audio_sender_request.is_pending()) ||
       (video_pipe.is_valid() && !video_sender_request.is_pending())) {
-    StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED);
+    StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED, false);
     return;
   }
 
@@ -377,7 +411,8 @@
 }
 
 void CastRemotingConnector::StopRemoting(RemotingBridge* bridge,
-                                         RemotingStopReason reason) {
+                                         RemotingStopReason reason,
+                                         bool is_initiated_by_source) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   VLOG(2) << __func__ << ": reason = " << reason;
 
@@ -389,6 +424,19 @@
   // Cancel all outstanding callbacks related to the remoting session.
   weak_factory_.InvalidateWeakPtrs();
 
+  if (permission_request_cancel_callback_) {
+    std::move(permission_request_cancel_callback_).Run();
+    if (is_initiated_by_source && remoter_) {
+      // The source requested remoting be stopped before the permission request
+      // was resolved. This means the |remoter_| was never started, and remains
+      // in the available state, still all ready to go. Thus, notify the sources
+      // that the sink is available once again.
+      for (RemotingBridge* notifyee : bridges_)
+        notifyee->OnSinkAvailable(sink_metadata_);
+    }
+    return;  // Early returns since the |remoter_| was never started.
+  }
+
   // Reset |sink_metadata_|. Remoting can only be started after
   // OnSinkAvailable() is called again.
   sink_metadata_ = RemotingSinkMetadata();
@@ -411,7 +459,7 @@
   if (active_bridge_) {
     // This call will reset |sink_metadata_| and notify the source that sink is
     // gone.
-    StopRemoting(active_bridge_, reason);
+    StopRemoting(active_bridge_, reason, false);
   } else if (reason == RemotingStopReason::USER_DISABLED) {
     // Notify all the sources that the sink is gone. Remoting can only be
     // started after OnSinkAvailable() is called again.
@@ -480,7 +528,7 @@
   VLOG(2) << __func__;
 
   if (active_bridge_)
-    StopRemoting(active_bridge_, RemotingStopReason::UNEXPECTED_FAILURE);
+    StopRemoting(active_bridge_, RemotingStopReason::UNEXPECTED_FAILURE, false);
 }
 
 void CastRemotingConnector::OnDataSendFailed() {
@@ -490,5 +538,5 @@
   // A single data send failure is treated as fatal to an active remoting
   // session.
   if (active_bridge_)
-    StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED);
+    StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED, false);
 }
diff --git a/chrome/browser/media/cast_remoting_connector.h b/chrome/browser/media/cast_remoting_connector.h
index 397c2be..1878779 100644
--- a/chrome/browser/media/cast_remoting_connector.h
+++ b/chrome/browser/media/cast_remoting_connector.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_MEDIA_CAST_REMOTING_CONNECTOR_H_
 
 #include <set>
+#include <vector>
 
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
@@ -112,7 +113,15 @@
 
   // Main constructor. |tab_id| refers to any remoted content managed
   // by this instance (i.e., any remoted content from one tab/WebContents).
-  CastRemotingConnector(media_router::MediaRouter* router, SessionID tab_id);
+  using CancelPermissionRequestCallback = base::OnceClosure;
+  // Called with true to mean "allowed", false to mean "not allowed".
+  using PermissionResultCallback = base::OnceCallback<void(bool)>;
+  using PermissionRequestCallback =
+      base::RepeatingCallback<CancelPermissionRequestCallback(
+          PermissionResultCallback)>;
+  CastRemotingConnector(media_router::MediaRouter* router,
+                        SessionID tab_id,
+                        PermissionRequestCallback request_callback);
 
   // Creates a RemotingBridge that implements the requested Remoter service, and
   // binds it to the interface |request|.
@@ -144,7 +153,8 @@
       media::mojom::RemotingDataStreamSenderRequest audio_sender_request,
       media::mojom::RemotingDataStreamSenderRequest video_sender_request);
   void StopRemoting(RemotingBridge* bridge,
-                    media::mojom::RemotingStopReason reason);
+                    media::mojom::RemotingStopReason reason,
+                    bool is_initiated_by_source);
   void SendMessageToSink(RemotingBridge* bridge,
                          const std::vector<uint8_t>& message);
   void EstimateTransmissionCapacity(
@@ -174,6 +184,9 @@
 
   const SessionID tab_id_;
 
+  // The callback to get permission.
+  const PermissionRequestCallback permission_request_callback_;
+
   // Describes the remoting sink's metadata and its enabled features. The sink's
   // metadata is updated by the mirror service calling OnSinkAvailable() and
   // cleared when remoting stops.
@@ -195,6 +208,10 @@
   // casting session.
   base::Optional<bool> remoting_allowed_;
 
+  // This callback is non-null when a dialog is showing to get user's
+  // permission, and is reset when the dialog closes.
+  CancelPermissionRequestCallback permission_request_cancel_callback_;
+
   // Produces weak pointers that are only valid for the current remoting
   // session. This is used to cancel any outstanding callbacks when a remoting
   // session is stopped.
diff --git a/chrome/browser/media/cast_remoting_connector_unittest.cc b/chrome/browser/media/cast_remoting_connector_unittest.cc
index 2e15e81..b129cc2 100644
--- a/chrome/browser/media/cast_remoting_connector_unittest.cc
+++ b/chrome/browser/media/cast_remoting_connector_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
+#include "build/build_config.h"
 #include "chrome/browser/media/router/test/mock_media_router.h"
 #include "chrome/common/media_router/media_route.h"
 #include "chrome/common/media_router/media_source.h"
@@ -164,9 +165,7 @@
 
 class CastRemotingConnectorTest : public ::testing::Test {
  public:
-  CastRemotingConnectorTest() : connector_(&media_router_, kRemotingTabId) {
-    EXPECT_EQ(kRemotingTabId, media_router_.tab_id());
-  }
+  CastRemotingConnectorTest() { CreateConnector(true); }
 
   void TearDown() final {
     // Allow any pending Mojo operations to complete before destruction. For
@@ -180,8 +179,8 @@
     RemotingSourcePtr source_ptr;
     source->Bind(mojo::MakeRequest(&source_ptr));
     RemoterPtr remoter_ptr;
-    connector_.CreateBridge(std::move(source_ptr),
-                            mojo::MakeRequest(&remoter_ptr));
+    connector_->CreateBridge(std::move(source_ptr),
+                             mojo::MakeRequest(&remoter_ptr));
     return remoter_ptr;
   }
 
@@ -190,14 +189,29 @@
   }
 
   void DisableRemoting() {
-    connector_.OnStopped(RemotingStopReason::USER_DISABLED);
+    connector_->OnStopped(RemotingStopReason::USER_DISABLED);
+  }
+
+  void CreateConnector(bool remoting_allowed) {
+    connector_.reset();  // Call dtor first if there is one created.
+    connector_.reset(new CastRemotingConnector(
+        &media_router_, kRemotingTabId,
+        base::BindRepeating(
+            [](bool remoting_allowed,
+               CastRemotingConnector::PermissionResultCallback
+                   result_callback) {
+              std::move(result_callback).Run(remoting_allowed);
+              return CastRemotingConnector::CancelPermissionRequestCallback();
+            },
+            remoting_allowed)));
+    EXPECT_EQ(kRemotingTabId, media_router_.tab_id());
   }
 
   FakeMediaRouter media_router_;
 
  private:
   content::TestBrowserThreadBundle browser_thread_bundle_;
-  CastRemotingConnector connector_;
+  std::unique_ptr<CastRemotingConnector> connector_;
 };
 
 TEST_F(CastRemotingConnectorTest, NeverNotifiesThatSinkIsAvailable) {
@@ -309,6 +323,20 @@
   RunUntilIdle();
 }
 
+TEST_F(CastRemotingConnectorTest, NoPermissionToStart) {
+  CreateConnector(false);
+  MockRemotingSource source;
+  RemoterPtr remoter = CreateRemoter(&source);
+  std::unique_ptr<MockMediaRemoter> media_remoter =
+      std::make_unique<MockMediaRemoter>(&media_router_);
+
+  EXPECT_CALL(source, OnStartFailed(RemotingStartFailReason::ROUTE_TERMINATED))
+      .Times(1);
+  EXPECT_CALL(source, OnSinkGone()).Times(AtLeast(1));
+  remoter->Start();
+  RunUntilIdle();
+}
+
 namespace {
 
 // The possible ways a remoting session may be terminated in the "full
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
index a3fa181..54aeb86 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
@@ -185,6 +185,16 @@
   return "cast:" + dial_sink_id.substr(5);
 }
 
+// static
+MediaSink::Id CastMediaSinkServiceImpl::GetDialSinkIdFromCast(
+    const MediaSink::Id& cast_sink_id) {
+  DCHECK_EQ("cast:", cast_sink_id.substr(0, 5))
+      << "unexpected Cast sink id " << cast_sink_id;
+
+  // Replace the "cast:" prefix with "dial:".
+  return "dial:" + cast_sink_id.substr(5);
+}
+
 CastMediaSinkServiceImpl::CastMediaSinkServiceImpl(
     const OnSinksDiscoveredCallback& callback,
     cast_channel::CastSocketService* cast_socket_service,
@@ -632,6 +642,13 @@
 
   if (old_sink_it != sinks.end())
     RemoveSink(old_sink_it->second);
+
+  // Certain classes of Cast sinks support advertising via SSDP but do not
+  // properly implement the rest of the DIAL protocol. If we successfully open
+  // a Cast channel to a device that came from DIAL, remove it from
+  // |dial_media_sink_service_|. This ensures the device shows up as a Cast sink
+  // only.
+  dial_media_sink_service_->RemoveSinkById(GetDialSinkIdFromCast(sink_id));
 }
 
 void CastMediaSinkServiceImpl::OnChannelOpenFailed(
@@ -674,6 +691,9 @@
     DVLOG(2) << "Sink discovered by mDNS, skip adding [name]: "
              << sink.sink().name();
     metrics_.RecordCastSinkDiscoverySource(SinkSource::kMdnsDial);
+    // Sink is a Cast device; remove from |dial_media_sink_service_| to prevent
+    // duplicates.
+    dial_media_sink_service_->RemoveSink(dial_sink);
     return;
   }
 
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
index 905161e..67c100d7 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
@@ -44,8 +44,9 @@
   // before we can say confidently that it is unlikely to be a Cast device.
   static constexpr int kMaxDialSinkFailureCount = 10;
 
-  // Returns a Cast MediaSink ID from a DIAL MediaSink ID |dial_sink_id|.
+  // Returns a Cast MediaSink ID from a DIAL MediaSink ID, and vice versa.
   static MediaSink::Id GetCastSinkIdFromDial(const MediaSink::Id& dial_sink_id);
+  static MediaSink::Id GetDialSinkIdFromCast(const MediaSink::Id& cast_sink_id);
 
   // |callback|: Callback passed to MediaSinkServiceBase.
   // |observer|: Observer to invoke on sink updates. Can be nullptr.
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
index 3a9aa68..d0fecea 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
@@ -587,11 +587,6 @@
   EXPECT_CALL(socket, ready_state())
       .WillOnce(Return(cast_channel::ReadyState::CLOSED));
 
-  // There is no existing cast sink.
-  /* XXX
-  media_sink_service_impl_.pending_for_open_ip_endpoints_.clear();
-  media_sink_service_impl_.current_sinks_.clear();
-  */
   media_sink_service_impl_.OnError(
       socket, cast_channel::ChannelError::CHANNEL_NOT_OPEN);
 
@@ -602,6 +597,10 @@
 }
 
 TEST_F(CastMediaSinkServiceImplTest, TestOnSinkAddedOrUpdated) {
+  // Make sure |media_sink_service_impl_| adds itself as an observer to
+  // |dial_media_sink_service_|.
+  media_sink_service_impl_.Start();
+
   MediaSinkInternal dial_sink1 = CreateDialSink(1);
   MediaSinkInternal dial_sink2 = CreateDialSink(2);
   net::IPEndPoint ip_endpoint1(dial_sink1.dial_data().ip_address,
@@ -618,22 +617,22 @@
   // Channel 1, 2 opened.
   EXPECT_CALL(*mock_cast_socket_service_,
               OpenSocketInternal(ip_endpoint1, _, _))
-      .WillOnce(WithArgs<2>(Invoke(
-          [&](const base::Callback<void(cast_channel::CastSocket * socket)>&
-                  callback) { std::move(callback).Run(&socket1); })));
+      .WillOnce(WithArgs<2>(
+          [&socket1](
+              const base::Callback<void(cast_channel::CastSocket * socket)>&
+                  callback) { callback.Run(&socket1); }));
   EXPECT_CALL(*mock_cast_socket_service_,
               OpenSocketInternal(ip_endpoint2, _, _))
-      .WillOnce(WithArgs<2>(Invoke(
-          [&](const base::Callback<void(cast_channel::CastSocket * socket)>&
-                  callback) { std::move(callback).Run(&socket2); })));
+      .WillOnce(WithArgs<2>(
+          [&socket2](
+              const base::Callback<void(cast_channel::CastSocket * socket)>&
+                  callback) { callback.Run(&socket2); }));
 
-  // Invoke CastSocketService::OpenSocket on the IO thread.
-  media_sink_service_impl_.OnSinkAddedOrUpdated(dial_sink1);
-  base::RunLoop().RunUntilIdle();
-
-  // Invoke CastSocketService::OpenSocket on the IO thread.
-  media_sink_service_impl_.OnSinkAddedOrUpdated(dial_sink2);
-  base::RunLoop().RunUntilIdle();
+  // Add DIAL sinks to |dial_media_sink_service_|, which in turn notifies
+  // |media_sink_service_impl_| via the Observer interface.
+  dial_media_sink_service_.AddOrUpdateSink(dial_sink1);
+  dial_media_sink_service_.AddOrUpdateSink(dial_sink2);
+  EXPECT_TRUE(dial_media_sink_service_.timer()->IsRunning());
 
   // Verify sink content.
   const auto& sinks = media_sink_service_impl_.GetSinks();
@@ -648,6 +647,9 @@
       CastMediaSinkServiceImpl::GetCastSinkIdFromDial(dial_sink2.sink().id()));
   ASSERT_TRUE(sink);
   EXPECT_EQ(SinkIconType::CAST_AUDIO, sink->sink().icon_type());
+
+  // The sinks are removed from |dial_media_sink_service_|.
+  EXPECT_TRUE(dial_media_sink_service_.GetSinks().empty());
 }
 
 TEST_F(CastMediaSinkServiceImplTest,
diff --git a/chrome/browser/navigation_predictor/navigation_predictor.cc b/chrome/browser/navigation_predictor/navigation_predictor.cc
index e654b62..28fc4a1 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor.cc
+++ b/chrome/browser/navigation_predictor/navigation_predictor.cc
@@ -4,10 +4,9 @@
 
 #include "chrome/browser/navigation_predictor/navigation_predictor.h"
 
-#include <unordered_map>
-
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/optional.h"
 #include "chrome/browser/engagement/site_engagement_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/render_frame_host.h"
@@ -16,24 +15,22 @@
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "url/gurl.h"
 
-struct NavigationPredictor::MetricsFromBrowser {
-  MetricsFromBrowser(const GURL& source_url,
-                     const GURL& target_url,
-                     const SiteEngagementService* engagement_service)
-      : source_engagement_score(engagement_service->GetScore(source_url)),
-        target_engagement_score(engagement_service->GetScore(target_url)) {
-    DCHECK(source_engagement_score >= 0 &&
-           source_engagement_score <= engagement_service->GetMaxPoints());
-    DCHECK(target_engagement_score >= 0 &&
-           target_engagement_score <= engagement_service->GetMaxPoints());
-  }
+struct NavigationPredictor::NavigationScore {
+  NavigationScore(const GURL& url, size_t area_rank, double score)
+      : url(url), area_rank(area_rank), score(score) {}
+  // URL of the target link.
+  const GURL url;
 
-  // The site engagement score of the url of the root document, and the target
-  // url (href) of the anchor element. The scores are retrieved from the site
-  // engagement service. The range of the scores are between 0 and
-  // SiteEngagementScore::kMaxPoints (both inclusive).
-  const double source_engagement_score;
-  const double target_engagement_score;
+  // Rank in terms of anchor element area. It starts at 0, a lower rank implies
+  // a larger area.
+  const size_t area_rank;
+
+  // Calculated navigation score, based on |area_rank| and other metrics.
+  const double score;
+
+  // Rank of the |score| in this document. It starts at 0, a lower rank implies
+  // a higher |score|.
+  base::Optional<size_t> score_rank;
 };
 
 NavigationPredictor::NavigationPredictor(
@@ -87,15 +84,14 @@
 
 SiteEngagementService* NavigationPredictor::GetEngagementService() const {
   Profile* profile = Profile::FromBrowserContext(browser_context_);
-  return SiteEngagementService::Get(profile);
+  SiteEngagementService* service = SiteEngagementService::Get(profile);
+  DCHECK(service);
+  return service;
 }
 
 void NavigationPredictor::ReportAnchorElementMetricsOnClick(
     blink::mojom::AnchorElementMetricsPtr metrics) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // TODO(chelu): https://crbug.com/850624/. Use |metrics| to aggregate metrics
-  // extracted from the browser process. Analyze and use them to take some
-  // actions accordingly.
   if (!IsValidMetricFromRenderer(*metrics)) {
     mojo::ReportBadMessage("Bad anchor element metrics: onClick.");
     return;
@@ -104,22 +100,81 @@
   RecordTimingOnClick();
 
   SiteEngagementService* engagement_service = GetEngagementService();
-  DCHECK(engagement_service);
+
+  UMA_HISTOGRAM_COUNTS_100(
+      "AnchorElementMetrics.Clicked.DocumentEngagementScore",
+      static_cast<int>(engagement_service->GetScore(metrics->source_url)));
 
   double target_score = engagement_service->GetScore(metrics->target_url);
-
   UMA_HISTOGRAM_COUNTS_100("AnchorElementMetrics.Clicked.HrefEngagementScore2",
                            static_cast<int>(target_score));
-
   if (target_score > 0) {
     UMA_HISTOGRAM_COUNTS_100(
         "AnchorElementMetrics.Clicked.HrefEngagementScorePositive",
         static_cast<int>(target_score));
   }
+
+  // Look up the clicked URL in |navigation_scores_map_|. Record if we find it.
+  auto iter = navigation_scores_map_.find(metrics->target_url.spec());
+  if (iter == navigation_scores_map_.end())
+    return;
+
+  UMA_HISTOGRAM_COUNTS_100("AnchorElementMetrics.Clicked.AreaRank",
+                           static_cast<int>(iter->second->area_rank));
+  UMA_HISTOGRAM_COUNTS_100("AnchorElementMetrics.Clicked.NavigationScore",
+                           static_cast<int>(iter->second->score));
+  UMA_HISTOGRAM_COUNTS_100("AnchorElementMetrics.Clicked.NavigationScoreRank",
+                           static_cast<int>(iter->second->score_rank.value()));
+
+  // Guaranteed to be non-zero since we have found the clicked link in
+  // |navigation_scores_map_|.
+  int number_of_anchors = static_cast<int>(navigation_scores_map_.size());
+  if (metrics->is_same_host) {
+    UMA_HISTOGRAM_PERCENTAGE(
+        "AnchorElementMetrics.Clicked.RatioSameHost_SameHost",
+        (number_of_anchors_same_host_ * 100) / number_of_anchors);
+  } else {
+    UMA_HISTOGRAM_PERCENTAGE(
+        "AnchorElementMetrics.Clicked.RatioSameHost_DiffHost",
+        (number_of_anchors_same_host_ * 100) / number_of_anchors);
+  }
+
+  if (metrics->contains_image) {
+    UMA_HISTOGRAM_PERCENTAGE(
+        "AnchorElementMetrics.Clicked.RatioContainsImage_ContainsImage",
+        (number_of_anchors_contains_image_ * 100) / number_of_anchors);
+  } else {
+    UMA_HISTOGRAM_PERCENTAGE(
+        "AnchorElementMetrics.Clicked.RatioContainsImage_NoImage",
+        (number_of_anchors_contains_image_ * 100) / number_of_anchors);
+  }
+
+  if (metrics->is_in_iframe) {
+    UMA_HISTOGRAM_PERCENTAGE(
+        "AnchorElementMetrics.Clicked.RatioInIframe_InIframe",
+        (number_of_anchors_in_iframe_ * 100) / number_of_anchors);
+  } else {
+    UMA_HISTOGRAM_PERCENTAGE(
+        "AnchorElementMetrics.Clicked.RatioInIframe_NotInIframe",
+        (number_of_anchors_in_iframe_ * 100) / number_of_anchors);
+  }
+
+  if (metrics->is_url_incremented_by_one) {
+    UMA_HISTOGRAM_PERCENTAGE(
+        "AnchorElementMetrics.Clicked.RatioUrlIncremented_UrlIncremented",
+        (number_of_anchors_url_incremented_ * 100) / number_of_anchors);
+  } else {
+    UMA_HISTOGRAM_PERCENTAGE(
+        "AnchorElementMetrics.Clicked.RatioUrlIncremented_NotIncremented",
+        (number_of_anchors_url_incremented_ * 100) / number_of_anchors);
+  }
 }
 
 void NavigationPredictor::MergeMetricsSameTargetUrl(
     std::vector<blink::mojom::AnchorElementMetricsPtr>* metrics) const {
+  UMA_HISTOGRAM_COUNTS_100(
+      "AnchorElementMetrics.Visible.NumberOfAnchorElements", metrics->size());
+
   // Maps from target url (href) to anchor element metrics from renderer.
   std::unordered_map<std::string, blink::mojom::AnchorElementMetricsPtr>
       metrics_map;
@@ -169,67 +224,124 @@
   }
 
   DCHECK(!metrics->empty());
+  UMA_HISTOGRAM_COUNTS_100(
+      "AnchorElementMetrics.Visible.NumberOfAnchorElementsAfterMerge",
+      metrics->size());
 }
 
 void NavigationPredictor::ReportAnchorElementMetricsOnLoad(
     std::vector<blink::mojom::AnchorElementMetricsPtr> metrics) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // Each document should only report metrics once when page is loaded.
+  DCHECK(navigation_scores_map_.empty());
+
   if (metrics.empty()) {
     mojo::ReportBadMessage("Bad anchor element metrics: empty.");
     return;
   }
 
-  document_loaded_timing_ = base::TimeTicks::Now();
-
-  UMA_HISTOGRAM_COUNTS_100(
-      "AnchorElementMetrics.Visible.NumberOfAnchorElements", metrics.size());
-
-  MergeMetricsSameTargetUrl(&metrics);
-
-  SiteEngagementService* engagement_service = GetEngagementService();
-  DCHECK(engagement_service);
-
-  std::vector<double> scores;
   for (const auto& metric : metrics) {
     if (!IsValidMetricFromRenderer(*metric)) {
       mojo::ReportBadMessage("Bad anchor element metrics: onLoad.");
       return;
     }
-
-    RecordMetricsOnLoad(*metric);
-
-    MetricsFromBrowser metrics_browser(metric->source_url, metric->target_url,
-                                       engagement_service);
-    double score = GetAnchorElementScore(*metric, metrics_browser);
-    scores.push_back(score);
   }
 
-  MaybeTakeActionOnLoad(scores);
+  document_loaded_timing_ = base::TimeTicks::Now();
+
+  MergeMetricsSameTargetUrl(&metrics);
+
+  // Count the number of anchors that have specific metrics.
+  for (const auto& metric : metrics) {
+    number_of_anchors_same_host_ += static_cast<int>(metric->is_same_host);
+    number_of_anchors_contains_image_ +=
+        static_cast<int>(metric->contains_image);
+    number_of_anchors_in_iframe_ += static_cast<int>(metric->is_in_iframe);
+    number_of_anchors_url_incremented_ +=
+        static_cast<int>(metric->is_url_incremented_by_one);
+  }
+
+  // Retrive site engagement score of the docuemnt. |metrics| is guaranteed to
+  // be non-empty. All |metrics| have the same source_url.
+  SiteEngagementService* engagement_service = GetEngagementService();
+  double document_engagement_score =
+      engagement_service->GetScore(metrics[0]->source_url);
+  DCHECK(document_engagement_score >= 0 &&
+         document_engagement_score <= engagement_service->GetMaxPoints());
+  UMA_HISTOGRAM_COUNTS_100(
+      "AnchorElementMetrics.Visible.DocumentEngagementScore",
+      static_cast<int>(document_engagement_score));
+
+  // Sort metric by area in descending order to get area rank, which is a
+  // derived feature to calculate navigation score.
+  std::sort(metrics.begin(), metrics.end(), [](const auto& a, const auto& b) {
+    return a->ratio_area > b->ratio_area;
+  });
+
+  // Loop |metrics| to compute navigation scores.
+  std::vector<std::unique_ptr<NavigationScore>> navigation_scores;
+  navigation_scores.reserve(metrics.size());
+  for (size_t i = 0; i != metrics.size(); ++i) {
+    const auto& metric = metrics[i];
+    RecordMetricsOnLoad(*metric);
+
+    const double target_engagement_score =
+        engagement_service->GetScore(metric->target_url);
+    DCHECK(target_engagement_score >= 0 &&
+           target_engagement_score <= engagement_service->GetMaxPoints());
+
+    // Anchor elements with the same area are assigned with the same rank.
+    size_t area_rank = i;
+    if (i > 0 && metric->ratio_area == metrics[i - 1]->ratio_area)
+      area_rank = navigation_scores[navigation_scores.size() - 1]->area_rank;
+
+    double score = CalculateAnchorNavigationScore(
+        *metric, document_engagement_score, target_engagement_score, area_rank);
+
+    navigation_scores.push_back(std::make_unique<NavigationScore>(
+        metric->target_url, area_rank, score));
+  }
+
+  // Sort scores by the calculated navigation score in descending order. This
+  // score rank is used by MaybeTakeActionOnLoad, and stored in
+  // |navigation_scores_map_|.
+  std::sort(navigation_scores.begin(), navigation_scores.end(),
+            [](const auto& a, const auto& b) { return a->score > b->score; });
+
+  MaybeTakeActionOnLoad(navigation_scores);
+
+  // Store navigation scores in |navigation_scores_map_| for fast look up upon
+  // clicks.
+  navigation_scores_map_.reserve(navigation_scores.size());
+  for (size_t i = 0; i != navigation_scores.size(); ++i) {
+    navigation_scores[i]->score_rank = base::make_optional(i);
+    navigation_scores_map_[navigation_scores[i]->url.spec()] =
+        std::move(navigation_scores[i]);
+  }
 }
 
-double NavigationPredictor::GetAnchorElementScore(
-    const blink::mojom::AnchorElementMetrics& metrics_renderer,
-    const MetricsFromBrowser& metrics_browser) const {
+double NavigationPredictor::CalculateAnchorNavigationScore(
+    const blink::mojom::AnchorElementMetrics& metrics,
+    double document_engagement_score,
+    double target_engagement_score,
+    int area_rank) const {
   // TODO(chelu): https://crbug.com/850624/. Experiment with other heuristic
   // algorithms for computing the anchor elements score.
-  return metrics_renderer.ratio_visible_area *
-         metrics_browser.target_engagement_score;
+  return metrics.ratio_visible_area;
 }
 
 void NavigationPredictor::MaybeTakeActionOnLoad(
-    const std::vector<double>& scores) const {
+    const std::vector<std::unique_ptr<NavigationScore>>&
+        sorted_navigation_scores) const {
   // TODO(chelu): https://crbug.com/850624/. Given the calculated navigation
   // scores, this function decides which action to take, or decides not to do
   // anything. Example actions including preresolve, preload, prerendering, etc.
-  // Other information (e.g., target urls) should also be passed in.
 
-  double highest_score = 0;
-  for (double score : scores)
-    highest_score = std::max(highest_score, score);
-
+  // |sorted_navigation_scores| are sorted in descending order, the first one
+  // has the highest navigation score.
   UMA_HISTOGRAM_COUNTS_100(
       "AnchorElementMetrics.Visible.HighestNavigationScore",
-      static_cast<int>(highest_score));
+      static_cast<int>(sorted_navigation_scores[0]->score));
 }
 
 void NavigationPredictor::RecordMetricsOnLoad(
diff --git a/chrome/browser/navigation_predictor/navigation_predictor.h b/chrome/browser/navigation_predictor/navigation_predictor.h
index 5d9ee992..da9555f7 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor.h
+++ b/chrome/browser/navigation_predictor/navigation_predictor.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_NAVIGATION_PREDICTOR_NAVIGATION_PREDICTOR_H_
 #define CHROME_BROWSER_NAVIGATION_PREDICTOR_NAVIGATION_PREDICTOR_H_
 
+#include <string>
+#include <unordered_map>
 #include <vector>
 
 #include "base/macros.h"
@@ -35,8 +37,9 @@
                      content::RenderFrameHost* render_frame_host);
 
  private:
-  // Struct holding features of an anchor element, extracted from the browser.
-  struct MetricsFromBrowser;
+  // Struct holding navigation score, rank and other info of the anchor element.
+  // Used for look up when an anchor element is clicked.
+  struct NavigationScore;
 
   // blink::mojom::AnchorElementMetricsHost:
   void ReportAnchorElementMetricsOnClick(
@@ -57,16 +60,25 @@
   void MergeMetricsSameTargetUrl(
       std::vector<blink::mojom::AnchorElementMetricsPtr>* metrics) const;
 
-  // Given metrics of an anchor element from both renderer and browser process,
-  // returns navigation score.
-  double GetAnchorElementScore(
-      const blink::mojom::AnchorElementMetrics& metrics_renderer,
-      const MetricsFromBrowser& metrics_browser) const;
+  // Computes and stores document level metrics, including |number_of_anchors_|,
+  // |document_engagement_score_|, etc.
+  void ComputeDocumentMetricsOnLoad(
+      const std::vector<blink::mojom::AnchorElementMetricsPtr>& metrics);
 
-  // Given a vector of navigation scores, decide what action to take, or decide
-  // not to do anything. Example actions including preresolve, preload,
-  // prerendering, etc.
-  void MaybeTakeActionOnLoad(const std::vector<double>& scores) const;
+  // Given metrics of an anchor element from both renderer and browser process,
+  // returns navigation score. Virtual for testing purposes.
+  virtual double CalculateAnchorNavigationScore(
+      const blink::mojom::AnchorElementMetrics& metrics,
+      double document_engagement_score,
+      double target_engagement_score,
+      int area_rank) const;
+
+  // Given a vector of navigation scores sorted in descending order, decide what
+  // action to take, or decide not to do anything. Example actions including
+  // preresolve, preload, prerendering, etc.
+  void MaybeTakeActionOnLoad(
+      const std::vector<std::unique_ptr<NavigationScore>>&
+          sorted_navigation_scores) const;
 
   // Record anchor element metrics on page load.
   void RecordMetricsOnLoad(
@@ -78,6 +90,17 @@
   // Used to get keyed services.
   content::BrowserContext* const browser_context_;
 
+  // Maps from target url (href) to navigation score.
+  std::unordered_map<std::string, std::unique_ptr<NavigationScore>>
+      navigation_scores_map_;
+
+  // Total number of anchors that: href has the same host as the document,
+  // contains image, inside an iframe, href incremented by 1 from document url.
+  int number_of_anchors_same_host_ = 0;
+  int number_of_anchors_contains_image_ = 0;
+  int number_of_anchors_in_iframe_ = 0;
+  int number_of_anchors_url_incremented_ = 0;
+
   // Timing of document loaded and last click.
   base::TimeTicks document_loaded_timing_;
   base::TimeTicks last_click_timing_;
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc b/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
index 05c1244..89c29a3 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
+++ b/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
@@ -91,6 +91,7 @@
 
 // Simulate a click at the anchor element.
 // Test that timing info (DurationLoadToFirstClick) can be recorded.
+// And that the navigation score can be looked up.
 IN_PROC_BROWSER_TEST_P(NavigationPredictorBrowserTest, ClickAnchorElement) {
   base::HistogramTester histogram_tester;
 
@@ -109,12 +110,39 @@
         "AnchorElementMetrics.Clicked.HrefEngagementScore2", 1);
     histogram_tester.ExpectTotalCount(
         "AnchorElementMetrics.Clicked.DurationLoadToFirstClick", 1);
+    histogram_tester.ExpectTotalCount(
+        "AnchorElementMetrics.Clicked.NavigationScore", 1);
+
   } else {
     histogram_tester.ExpectTotalCount(
         "AnchorElementMetrics.Clicked.HrefEngagementScore2", 0);
   }
 }
 
+// Simulate click at the anchor element.
+// Test that correct area ranks are recorded.
+IN_PROC_BROWSER_TEST_P(NavigationPredictorBrowserTest, AreaRank) {
+  base::HistogramTester histogram_tester;
+
+  // This test file contains 5 anchors with different size.
+  const GURL& url = GetTestURL("/anchors_different_area.html");
+  ui_test_utils::NavigateToURL(browser(), url);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(content::ExecuteScript(
+      browser()->tab_strip_model()->GetActiveWebContents(),
+      "document.getElementById('medium').click();"));
+  base::RunLoop().RunUntilIdle();
+
+  if (base::FeatureList::IsEnabled(
+          blink::features::kRecordAnchorMetricsClicked)) {
+    histogram_tester.ExpectUniqueSample("AnchorElementMetrics.Clicked.AreaRank",
+                                        2, 1);
+    histogram_tester.ExpectTotalCount("AnchorElementMetrics.Visible.RatioArea",
+                                      5);
+  }
+}
+
 // Test that MergeMetricsSameTargetUrl merges anchor elements having the same
 // href. The html file contains two anchor elements having the same href.
 IN_PROC_BROWSER_TEST_P(NavigationPredictorBrowserTest,
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_unittest.cc b/chrome/browser/navigation_predictor/navigation_predictor_unittest.cc
index be6ceaf7..798ac79 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor_unittest.cc
+++ b/chrome/browser/navigation_predictor/navigation_predictor_unittest.cc
@@ -4,14 +4,49 @@
 
 #include "chrome/browser/navigation_predictor/navigation_predictor.h"
 
+#include <map>
+
 #include "base/run_loop.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/mojom/loader/navigation_predictor.mojom.h"
 #include "url/gurl.h"
 
 namespace {
 
+class TestNavigationPredictor : public NavigationPredictor {
+ public:
+  explicit TestNavigationPredictor(
+      mojo::InterfaceRequest<AnchorElementMetricsHost> request,
+      content::RenderFrameHost* render_frame_host)
+      : NavigationPredictor(render_frame_host), binding_(this) {
+    binding_.Bind(std::move(request));
+  }
+
+  ~TestNavigationPredictor() override {}
+
+  const std::map<GURL, int>& GetAreaRankMap() const { return area_rank_map_; }
+
+ private:
+  double CalculateAnchorNavigationScore(
+      const blink::mojom::AnchorElementMetrics& metrics,
+      double document_engagement_score,
+      double target_engagement_score,
+      int area_rank) const override {
+    area_rank_map_.emplace(std::make_pair(metrics.target_url, area_rank));
+    return 100 * metrics.ratio_area;
+  }
+
+  // Maps from target URL to area rank of the anchor element.
+  mutable std::map<GURL, int> area_rank_map_;
+
+  // Used to bind Mojo interface
+  mojo::Binding<AnchorElementMetricsHost> binding_;
+};
+
 class NavigationPredictorTest : public ChromeRenderViewHostTestHarness {
  public:
   NavigationPredictorTest() = default;
@@ -19,8 +54,8 @@
 
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
-    NavigationPredictor::Create(mojo::MakeRequest(&predictor_service_),
-                                main_rfh());
+    predictor_service_helper_ = std::make_unique<TestNavigationPredictor>(
+        mojo::MakeRequest(&predictor_service_), main_rfh());
   }
 
   void TearDown() override { ChromeRenderViewHostTestHarness::TearDown(); }
@@ -28,10 +63,12 @@
   // Helper function to generate mojom metrics.
   blink::mojom::AnchorElementMetricsPtr CreateMetricsPtr(
       const std::string& source_url,
-      const std::string& target_url) const {
+      const std::string& target_url,
+      float ratio_area) const {
     auto metrics = blink::mojom::AnchorElementMetrics::New();
     metrics->source_url = GURL(source_url);
     metrics->target_url = GURL(target_url);
+    metrics->ratio_area = ratio_area;
     return metrics;
   }
 
@@ -39,8 +76,13 @@
     return predictor_service_.get();
   }
 
+  TestNavigationPredictor* predictor_service_helper() const {
+    return predictor_service_helper_.get();
+  }
+
  private:
   blink::mojom::AnchorElementMetricsHostPtr predictor_service_;
+  std::unique_ptr<TestNavigationPredictor> predictor_service_helper_;
 };
 
 }  // namespace
@@ -50,7 +92,8 @@
 TEST_F(NavigationPredictorTest, ReportAnchorElementMetricsOnClick) {
   base::HistogramTester histogram_tester;
 
-  auto metrics = CreateMetricsPtr("http://example.com", "https://google.com");
+  auto metrics =
+      CreateMetricsPtr("http://example.com", "https://google.com", 0.1);
   predictor_service()->ReportAnchorElementMetricsOnClick(std::move(metrics));
   base::RunLoop().RunUntilIdle();
 
@@ -62,7 +105,8 @@
 TEST_F(NavigationPredictorTest, ReportAnchorElementMetricsOnLoad) {
   base::HistogramTester histogram_tester;
 
-  auto metrics = CreateMetricsPtr("https://example.com", "http://google.com");
+  auto metrics =
+      CreateMetricsPtr("https://example.com", "http://google.com", 0.1);
   std::vector<blink::mojom::AnchorElementMetricsPtr> metrics_vector;
   metrics_vector.push_back(std::move(metrics));
   predictor_service()->ReportAnchorElementMetricsOnLoad(
@@ -78,7 +122,8 @@
 TEST_F(NavigationPredictorTest, BadUrlReportAnchorElementMetricsOnClick) {
   base::HistogramTester histogram_tester;
 
-  auto metrics = CreateMetricsPtr("ftp://example.com", "https://google.com");
+  auto metrics =
+      CreateMetricsPtr("ftp://example.com", "https://google.com", 0.1);
   predictor_service()->ReportAnchorElementMetricsOnClick(std::move(metrics));
   base::RunLoop().RunUntilIdle();
 
@@ -91,7 +136,8 @@
 TEST_F(NavigationPredictorTest, BadUrlReportAnchorElementMetricsOnLoad) {
   base::HistogramTester histogram_tester;
 
-  auto metrics = CreateMetricsPtr("https://example.com", "ftp://google.com");
+  auto metrics =
+      CreateMetricsPtr("https://example.com", "ftp://google.com", 0.1);
   std::vector<blink::mojom::AnchorElementMetricsPtr> metrics_vector;
   metrics_vector.push_back(std::move(metrics));
   predictor_service()->ReportAnchorElementMetricsOnLoad(
@@ -101,3 +147,43 @@
   histogram_tester.ExpectTotalCount(
       "AnchorElementMetrics.Visible.HighestNavigationScore", 0);
 }
+
+// In this test, multiple anchor element metrics are sent to
+// ReportAnchorElementMetricsOnLoad. Test that CalculateAnchorNavigationScore
+// works, and that highest navigation score can be recorded correctly.
+TEST_F(NavigationPredictorTest, MultipleAnchorElementMetricsOnLoad) {
+  base::HistogramTester histogram_tester;
+
+  const std::string source = "http://example.com";
+  const std::string href_xlarge = "http://example.com/xlarge";
+  const std::string href_large = "http://google.com/large";
+  const std::string href_medium = "http://google.com/medium";
+  const std::string href_small = "http://google.com/small";
+  const std::string href_xsmall = "http://google.com/xsmall";
+
+  std::vector<blink::mojom::AnchorElementMetricsPtr> metrics;
+  metrics.push_back(CreateMetricsPtr(source, href_xsmall, 0.01));
+  metrics.push_back(CreateMetricsPtr(source, href_large, 0.08));
+  metrics.push_back(CreateMetricsPtr(source, href_xlarge, 0.1));
+  metrics.push_back(CreateMetricsPtr(source, href_small, 0.02));
+  metrics.push_back(CreateMetricsPtr(source, href_medium, 0.05));
+
+  int number_of_mertics_sent = metrics.size();
+  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  base::RunLoop().RunUntilIdle();
+
+  const std::map<GURL, int>& area_rank_map =
+      predictor_service_helper()->GetAreaRankMap();
+  EXPECT_EQ(number_of_mertics_sent, static_cast<int>(area_rank_map.size()));
+  EXPECT_EQ(0, area_rank_map.find(GURL(href_xlarge))->second);
+  EXPECT_EQ(1, area_rank_map.find(GURL(href_large))->second);
+  EXPECT_EQ(2, area_rank_map.find(GURL(href_medium))->second);
+  EXPECT_EQ(3, area_rank_map.find(GURL(href_small))->second);
+  EXPECT_EQ(4, area_rank_map.find(GURL(href_xsmall))->second);
+
+  // The highest score is 100 (scale factor) * 0.1 (largest area) = 10.
+  histogram_tester.ExpectUniqueSample(
+      "AnchorElementMetrics.Visible.HighestNavigationScore", 10, 1);
+  histogram_tester.ExpectTotalCount("AnchorElementMetrics.Visible.RatioArea",
+                                    5);
+}
diff --git a/chrome/browser/chrome_network_service_browsertest.cc b/chrome/browser/net/chrome_network_service_browsertest.cc
similarity index 100%
rename from chrome/browser/chrome_network_service_browsertest.cc
rename to chrome/browser/net/chrome_network_service_browsertest.cc
diff --git a/chrome/browser/chrome_network_service_restart_browsertest.cc b/chrome/browser/net/chrome_network_service_restart_browsertest.cc
similarity index 100%
rename from chrome/browser/chrome_network_service_restart_browsertest.cc
rename to chrome/browser/net/chrome_network_service_restart_browsertest.cc
diff --git a/chrome/browser/payments/manifest_verifier_browsertest.cc b/chrome/browser/payments/manifest_verifier_browsertest.cc
index 02d91e9..3f1d2cf 100644
--- a/chrome/browser/payments/manifest_verifier_browsertest.cc
+++ b/chrome/browser/payments/manifest_verifier_browsertest.cc
@@ -532,6 +532,7 @@
     apps[0]->enabled_methods.push_back("interledger");
     apps[0]->enabled_methods.push_back("payee-credit-transfer");
     apps[0]->enabled_methods.push_back("payer-credit-transfer");
+    apps[0]->enabled_methods.push_back("tokenized-card");
     apps[0]->enabled_methods.push_back("not-supported");
 
     Verify(std::move(apps));
@@ -539,7 +540,7 @@
     EXPECT_EQ(1U, verified_apps().size());
     ExpectApp(0, "https://bobpay.com/webpay",
               {"basic-card", "interledger", "payee-credit-transfer",
-               "payer-credit-transfer"},
+               "payer-credit-transfer", "tokenized-card"},
               false);
   }
 
@@ -552,6 +553,7 @@
     apps[0]->enabled_methods.push_back("interledger");
     apps[0]->enabled_methods.push_back("payee-credit-transfer");
     apps[0]->enabled_methods.push_back("payer-credit-transfer");
+    apps[0]->enabled_methods.push_back("tokenized-card");
     apps[0]->enabled_methods.push_back("not-supported");
 
     Verify(std::move(apps));
@@ -559,7 +561,7 @@
     EXPECT_EQ(1U, verified_apps().size());
     ExpectApp(0, "https://bobpay.com/webpay",
               {"basic-card", "interledger", "payee-credit-transfer",
-               "payer-credit-transfer"},
+               "payer-credit-transfer", "tokenized-card"},
               false);
   }
 }
diff --git a/chrome/browser/prefs/pref_service_incognito_whitelist.cc b/chrome/browser/prefs/pref_service_incognito_whitelist.cc
index 7d8682c..370834b0 100644
--- a/chrome/browser/prefs/pref_service_incognito_whitelist.cc
+++ b/chrome/browser/prefs/pref_service_incognito_whitelist.cc
@@ -759,7 +759,7 @@
     arc::prefs::kArcSupervisionTransition,
     arc::prefs::kArcCompatibleFilesystemChosen,
     arc::prefs::kArcVoiceInteractionValuePropAccepted,
-    arc::prefs::kEcryptfsMigrationStrategy, arc::prefs::kSmsConnectEnabled,
+    arc::prefs::kEcryptfsMigrationStrategy,
     arc::prefs::kVoiceInteractionEnabled,
     arc::prefs::kVoiceInteractionContextEnabled,
     arc::prefs::kVoiceInteractionHotwordEnabled,
diff --git a/chrome/browser/profiling_host/background_profiling_triggers.cc b/chrome/browser/profiling_host/background_profiling_triggers.cc
index de96545..7a515bd 100644
--- a/chrome/browser/profiling_host/background_profiling_triggers.cc
+++ b/chrome/browser/profiling_host/background_profiling_triggers.cc
@@ -120,6 +120,12 @@
   }
 }
 
+bool BackgroundProfilingTriggers::ShouldTriggerControlReport(
+    int content_process_type) const {
+  return (content_process_type == content::ProcessType::PROCESS_TYPE_BROWSER) &&
+         base::RandGenerator(kControlPopulationSamplingRate) == 0;
+}
+
 void BackgroundProfilingTriggers::PerformMemoryUsageChecks() {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
@@ -150,37 +156,40 @@
     return;
   }
 
+  // Sample a control population.
+  for (const auto& proc : dump->process_dumps()) {
+    if (base::ContainsValue(profiled_pids, proc.pid()) &&
+        ShouldTriggerControlReport(
+            GetContentProcessType(proc.process_type()))) {
+      TriggerMemoryReport("MEMLOG_CONTROL_TRIGGER");
+      return;
+    }
+  }
+
+  // Detect whether memory footprint is too high and send a memlog report.
   bool should_send_report = false;
   std::string trigger_name;
+  for (const auto& proc : dump->process_dumps()) {
+    if (!base::ContainsValue(profiled_pids, proc.pid()))
+      continue;
 
-  if (base::RandGenerator(kControlPopulationSamplingRate) == 0) {
-    // Sample a control population.
-    trigger_name = "MEMLOG_CONTROL_TRIGGER";
-    should_send_report = true;
-  } else {
-    // Detect whether memory footprint is too high and send a memlog report.
-    for (const auto& proc : dump->process_dumps()) {
-      if (!base::ContainsValue(profiled_pids, proc.pid()))
-        continue;
-
-      uint32_t private_footprint_kb = proc.os_dump().private_footprint_kb;
-      auto it = pmf_at_last_upload_.find(proc.pid());
-      if (it != pmf_at_last_upload_.end()) {
-        if (private_footprint_kb > it->second + kHighWaterMarkThresholdKb) {
-          trigger_name = "MEMLOG_BACKGROUND_TRIGGER";
-          should_send_report = true;
-          it->second = private_footprint_kb;
-        }
-        continue;
-      }
-
-      // No high water mark exists yet, check the trigger threshold.
-      if (IsOverTriggerThreshold(GetContentProcessType(proc.process_type()),
-                                 private_footprint_kb)) {
+    uint32_t private_footprint_kb = proc.os_dump().private_footprint_kb;
+    auto it = pmf_at_last_upload_.find(proc.pid());
+    if (it != pmf_at_last_upload_.end()) {
+      if (private_footprint_kb > it->second + kHighWaterMarkThresholdKb) {
         trigger_name = "MEMLOG_BACKGROUND_TRIGGER";
         should_send_report = true;
-        pmf_at_last_upload_[proc.pid()] = private_footprint_kb;
+        it->second = private_footprint_kb;
       }
+      continue;
+    }
+
+    // No high water mark exists yet, check the trigger threshold.
+    if (IsOverTriggerThreshold(GetContentProcessType(proc.process_type()),
+                               private_footprint_kb)) {
+      trigger_name = "MEMLOG_BACKGROUND_TRIGGER";
+      should_send_report = true;
+      pmf_at_last_upload_[proc.pid()] = private_footprint_kb;
     }
   }
 
diff --git a/chrome/browser/profiling_host/background_profiling_triggers.h b/chrome/browser/profiling_host/background_profiling_triggers.h
index 2484e27..4f54ea8 100644
--- a/chrome/browser/profiling_host/background_profiling_triggers.h
+++ b/chrome/browser/profiling_host/background_profiling_triggers.h
@@ -47,6 +47,11 @@
   // Returns true if trace uploads are allowed.
   bool IsAllowedToUpload() const;
 
+  // Returns true if a control report should be sent for the given
+  // |content_process_type|.
+  // Virtual for testing.
+  virtual bool ShouldTriggerControlReport(int content_process_type) const;
+
   // Returns true if |private_footprint_kb| is large enough to trigger
   // a report for the given |content_process_type|.
   bool IsOverTriggerThreshold(int content_process_type,
diff --git a/chrome/browser/profiling_host/background_profiling_triggers_unittest.cc b/chrome/browser/profiling_host/background_profiling_triggers_unittest.cc
index 199203c..9c7e4680 100644
--- a/chrome/browser/profiling_host/background_profiling_triggers_unittest.cc
+++ b/chrome/browser/profiling_host/background_profiling_triggers_unittest.cc
@@ -66,22 +66,33 @@
 class FakeBackgroundProfilingTriggers : public BackgroundProfilingTriggers {
  public:
   explicit FakeBackgroundProfilingTriggers(ProfilingProcessHost* host)
-      : BackgroundProfilingTriggers(host), was_report_triggered_(false) {}
+      : BackgroundProfilingTriggers(host),
+        was_report_triggered_(false),
+        should_trigger_control_report_(false) {}
 
   using BackgroundProfilingTriggers::OnReceivedMemoryDump;
 
   void Reset() {
+    should_trigger_control_report_ = false;
     was_report_triggered_ = false;
     pmf_at_last_upload_.clear();
   }
   bool WasReportTriggered() const { return was_report_triggered_; }
 
+  bool ShouldTriggerControlReport(int content_process_type) const override {
+    return should_trigger_control_report_;
+  }
+  void SetControlTrigger(bool trigger_control_report) {
+    should_trigger_control_report_ = trigger_control_report;
+  }
+
  private:
   void TriggerMemoryReport(std::string trigger_name) override {
     was_report_triggered_ = true;
   }
 
   bool was_report_triggered_;
+  bool should_trigger_control_report_;
 };
 
 class BackgroundProfilingTriggersTest : public testing::Test {
@@ -200,6 +211,15 @@
   triggers_.OnReceivedMemoryDump(profiled_pids_, true,
                                  GlobalMemoryDump::MoveFrom(std::move(dump)));
   EXPECT_TRUE(triggers_.WasReportTriggered());
+
+  // Ensure control trigger work on browser process, no matter memory usage.
+  triggers_.Reset();
+  triggers_.SetControlTrigger(true);
+  dump = memory_instrumentation::mojom::GlobalMemoryDump::New();
+  PopulateMetrics(&dump, 1, ProcessType::BROWSER, 1, 1, 1);
+  triggers_.OnReceivedMemoryDump(profiled_pids_, true,
+                                 GlobalMemoryDump::MoveFrom(std::move(dump)));
+  EXPECT_TRUE(triggers_.WasReportTriggered());
 }
 
 TEST_F(BackgroundProfilingTriggersTest, HighWaterMark) {
diff --git a/chrome/browser/resources/chromeos/login/md_header_bar.js b/chrome/browser/resources/chromeos/login/md_header_bar.js
index f669c4bc..33f89d4d 100644
--- a/chrome/browser/resources/chromeos/login/md_header_bar.js
+++ b/chrome/browser/resources/chromeos/login/md_header_bar.js
@@ -301,9 +301,6 @@
     set signinUIState(state) {
       this.signinUIState_ = state;
       this.updateUI_();
-
-      if (Oobe.getInstance().showingViewsLogin)
-        chrome.send('updateSigninUIState', [state]);
     },
 
     /**
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
index 97463c89..c81aa886 100644
--- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
+++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
@@ -706,11 +706,6 @@
       $('login-header-bar').showCreateSupervisedButton =
           data.supervisedUsersCanCreate;
       $('login-header-bar').showGuestButton = data.guestSignin;
-      if (Oobe.getInstance().showingViewsLogin) {
-        chrome.send(
-            'showGuestButton',
-            [data.guestSignin && !this.closable && this.isAtTheBeginning()]);
-      }
 
       // Reset SAML
       this.classList.toggle('full-width', false);
diff --git a/chrome/browser/resources/local_ntp/custom_backgrounds.js b/chrome/browser/resources/local_ntp/custom_backgrounds.js
index 0f8839f..51575cf 100644
--- a/chrome/browser/resources/local_ntp/custom_backgrounds.js
+++ b/chrome/browser/resources/local_ntp/custom_backgrounds.js
@@ -110,7 +110,7 @@
 };
 
 customBackgrounds.CUSTOM_BACKGROUND_OVERLAY =
-    'linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2))';
+    'linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.3))';
 
 // These shound match the corresponding values in local_ntp.js, that control the
 // mv-notice element.
@@ -501,21 +501,24 @@
           'url(' + imageData[i].thumbnailImageUrl + ')'
         ].join(',').trim();
         tile.style.backgroundImage = imageWithOverlay;
+        tile.dataset.attributionLine1 = '';
+        tile.dataset.attributionLine2 = '';
+        tile.dataset.attributionActionUrl = '';
       } else {
         tile.style.backgroundImage =
             'url(' + imageData[i].thumbnailImageUrl + ')';
-      }
-      tile.dataset.url = imageData[i].imageUrl;
-      tile.dataset.attributionLine1 =
+        tile.dataset.attributionLine1 =
           (imageData[i].attributions[0] != undefined ?
                imageData[i].attributions[0] :
                '');
-      tile.dataset.attributionLine2 =
+        tile.dataset.attributionLine2 =
           (imageData[i].attributions[1] != undefined ?
                imageData[i].attributions[1] :
                '');
-      tile.dataset.attributionActionUrl = imageData[i].attributionActionUrl;
+        tile.dataset.attributionActionUrl = imageData[i].attributionActionUrl;
+      }
       tile.setAttribute('aria-label', imageData[i].attributions[0]);
+      tile.dataset.url = imageData[i].imageUrl;
     } else {
       tile.style.backgroundImage =
           'url(' + imageData[i].thumbnailPhotoUrl + ')';
@@ -957,7 +960,6 @@
              .classList.contains(customBackgrounds.CLASSES.DONE_AVAILABLE)) {
       return;
     }
-
     customBackgrounds.setBackground(
         customBackgrounds.selectedTile.dataset.url,
         customBackgrounds.selectedTile.dataset.attributionLine1,
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.js b/chrome/browser/resources/local_ntp/most_visited_single.js
index de79a61..a233668 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.js
+++ b/chrome/browser/resources/local_ntp/most_visited_single.js
@@ -8,6 +8,16 @@
 
 
 /**
+ * Enum for ids.
+ * @enum {string}
+ * @const
+ */
+const IDS = {
+  MV_TILES: 'mv-tiles',  // Most Visited tiles container.
+};
+
+
+/**
  * Enum for classnames.
  * @enum {string}
  * @const
@@ -85,6 +95,13 @@
 
 
 /**
+ * Number of tiles per row for Material Design.
+ * @const {number}
+ */
+const MD_MAX_TILES_PER_ROW = 5;
+
+
+/**
  * Number of lines to display in titles.
  * @type {number}
  */
@@ -315,6 +332,16 @@
   // Add new tileset.
   cur.id = 'mv-tiles';
   parent.appendChild(cur);
+
+  // If this is Material Design, re-balance the tiles if there are more than
+  // |MD_MAX_TILES_PER_ROW| in order to make even rows.
+  if (isMDEnabled) {
+    if (cur.childNodes.length > MD_MAX_TILES_PER_ROW) {
+      cur.style.maxWidth =
+          'calc(var(--md-tile-width) * ' + Math.ceil(cur.childNodes.length / 2);
+    }
+  }
+
   // getComputedStyle causes the initial style (opacity 0) to be applied, so
   // that when we then set it to 1, that triggers the CSS transition.
   if (fadeIn) {
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index a21d2781a..cd3da04a 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -124,7 +124,6 @@
 
 js_library("find_shortcut_behavior") {
   deps = [
-    "//third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior:iron-a11y-keys-behavior-extracted",
     "//ui/webui/resources/js:assert",
     "//ui/webui/resources/js:cr",
   ]
diff --git a/chrome/browser/resources/settings/device_page/keyboard.html b/chrome/browser/resources/settings/device_page/keyboard.html
index 6f88254..415d4d6 100644
--- a/chrome/browser/resources/settings/device_page/keyboard.html
+++ b/chrome/browser/resources/settings/device_page/keyboard.html
@@ -34,15 +34,6 @@
           menu-options="[[keyMapTargets_]]">
       </settings-dropdown-menu>
     </div>
-    <template is="dom-if" if="[[showCapsLock_]]">
-      <div class="settings-box" id="capsLockKey">
-        <div class="start">$i18n{keyboardKeyCapsLock}</div>
-        <settings-dropdown-menu label="$i18n{keyboardKeyCapsLock}"
-            pref="{{prefs.settings.language.remap_caps_lock_key_to}}"
-            menu-options="[[keyMapTargets_]]">
-        </settings-dropdown-menu>
-      </div>
-    </template>
     <template is="dom-if" if="[[showDiamondKey_]]">
       <div class="settings-box" id="diamondKey">
         <div class="start">$i18n{keyboardKeyDiamond}</div>
@@ -66,6 +57,34 @@
           menu-options="[[keyMapTargets_]]">
       </settings-dropdown-menu>
     </div>
+    <template is="dom-if" if="[[showCapsLock_]]">
+      <div class="settings-box" id="capsLockKey">
+        <div class="start">$i18n{keyboardKeyCapsLock}</div>
+        <settings-dropdown-menu label="$i18n{keyboardKeyCapsLock}"
+            pref="{{prefs.settings.language.remap_caps_lock_key_to}}"
+            menu-options="[[keyMapTargets_]]">
+        </settings-dropdown-menu>
+      </div>
+    </template>
+    <template is="dom-if" if="[[showExternalMetaKey_]]">
+      <div class="settings-box" id="externalMetaKey">
+        <div class="start">$i18n{keyboardKeyExternalMeta}</div>
+        <settings-dropdown-menu label="$i18n{keyboardKeyExternalMeta}"
+            pref="{{prefs.settings.language.remap_external_meta_key_to}}"
+            menu-options="[[keyMapTargets_]]">
+        </settings-dropdown-menu>
+      </div>
+    </template>
+    <template is="dom-if" if="[[showAppleCommandKey_]]">
+      <div class="settings-box" id="externalCommandKey">
+        <div class="start">$i18n{keyboardKeyExternalCommand}</div>
+        <settings-dropdown-menu
+            label="$i18n{keyboardKeyExternalCommand}"
+            pref="{{prefs.settings.language.remap_external_command_key_to}}"
+            menu-options="[[keyMapTargets_]]">
+        </settings-dropdown-menu>
+      </div>
+    </template>
     <settings-toggle-button
         pref="{{prefs.settings.language.send_function_keys}}"
         label="$i18n{keyboardSendFunctionKeys}"
diff --git a/chrome/browser/resources/settings/device_page/keyboard.js b/chrome/browser/resources/settings/device_page/keyboard.js
index e10766d..204013c2 100644
--- a/chrome/browser/resources/settings/device_page/keyboard.js
+++ b/chrome/browser/resources/settings/device_page/keyboard.js
@@ -39,6 +39,21 @@
     /** @private Whether to show diamond key options. */
     showDiamondKey_: Boolean,
 
+    /**
+     * Whether to show a remapping option for external keyboard's Meta key
+     * (Search/Windows keys). This is true only when there's an external
+     * keyboard connected that is a non-Apple keyboard.
+     * @private
+     */
+    showExternalMetaKey_: Boolean,
+
+    /**
+     * Whether to show a remapping option for the Command key. This is true when
+     * one of the connected keyboards is an Apple keyboard.
+     * @private
+     */
+    showAppleCommandKey_: Boolean,
+
     /** @private {!DropdownMenuOptionList} Menu items for key mapping. */
     keyMapTargets_: Object,
 
@@ -114,13 +129,14 @@
 
   /**
    * Handler for updating which keys to show.
-   * @param {boolean} showCapsLock
-   * @param {boolean} showDiamondKey
+   * @param {Object} keyboardParams
    * @private
    */
-  onShowKeysChange_: function(showCapsLock, showDiamondKey) {
-    this.showCapsLock_ = showCapsLock;
-    this.showDiamondKey_ = showDiamondKey;
+  onShowKeysChange_: function(keyboardParams) {
+    this.showCapsLock_ = keyboardParams['showCapsLock'];
+    this.showDiamondKey_ = keyboardParams['showDiamondKey'];
+    this.showExternalMetaKey_ = keyboardParams['showExternalMetaKey'];
+    this.showAppleCommandKey_ = keyboardParams['showAppleCommandKey'];
   },
 
   onShowKeyboardShortcutsOverlayTap_: function() {
diff --git a/chrome/browser/resources/settings/find_shortcut_behavior.html b/chrome/browser/resources/settings/find_shortcut_behavior.html
index 4fedd0e..f6440393 100644
--- a/chrome/browser/resources/settings/find_shortcut_behavior.html
+++ b/chrome/browser/resources/settings/find_shortcut_behavior.html
@@ -1,4 +1,3 @@
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-keys-behavior/iron-a11y-keys-behavior.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 51103e5b..63d51aa 100644
--- a/chrome/browser/resources/settings/find_shortcut_behavior.js
+++ b/chrome/browser/resources/settings/find_shortcut_behavior.js
@@ -3,49 +3,81 @@
 // found in the LICENSE file.
 
 /**
- * @fileoverview Listens for a find keyboard shortcut (i.e. Ctrl/Cmd+f) wherever
- * this behavior is applied and invokes canHandleFindShortcut(). If
- * canHandleFindShortcut() returns true, handleFindShortcut() will be called.
- * Override these methods in your element in order to use this behavior.
+ * @fileoverview Listens for a find keyboard shortcut (i.e. Ctrl/Cmd+f)
+ * and keeps track of an stack of potential listeners. Only the listener at the
+ * top of the stack will be notified that a find shortcut has been invoked.
  */
 
-cr.exportPath('settings');
-
-/** @polymerBehavior */
-settings.FindShortcutBehaviorImpl = {
-  keyBindings: {
-    // <if expr="is_macosx">
-    'meta+f': 'onFindShortcut_',
-    // </if>
-    // <if expr="not is_macosx">
-    'ctrl+f': 'onFindShortcut_',
-    // </if>
-  },
-
-  /** @private */
-  onFindShortcut_: function(e) {
-    if (!e.defaultPrevented && this.canHandleFindShortcut()) {
-      this.handleFindShortcut();
-      e.preventDefault();
-    }
-  },
+cr.define('settings', function() {
+  /**
+   * Stack of listeners. Only the top listener will handle the shortcut.
+   * @type {!Array<!HTMLElement>}
+   */
+  const listeners = [];
 
   /**
-   * @return {boolean}
-   * @protected
+   * Tracks if any modal context is open in settings. This assumes only one
+   * modal can be open at a time. The modals that are being tracked include
+   * cr-dialog and cr-drawer.
+   * @type {boolean}
    */
-  canHandleFindShortcut: function() {
-    assertNotReached();
-  },
+  let modalContextOpen = false;
 
-  /** @protected */
-  handleFindShortcut: function() {
-    assertNotReached();
-  },
-};
+  window.addEventListener('keydown', e => {
+    if (listeners.length == 0)
+      return;
 
-/** @polymerBehavior */
-settings.FindShortcutBehavior = [
-  Polymer.IronA11yKeysBehavior,
-  settings.FindShortcutBehaviorImpl,
-];
+    const modifierPressed = cr.isMac ? e.metaKey : e.ctrlKey;
+    if (modifierPressed && e.key == 'f') {
+      if (e.defaultPrevented)
+        return;
+
+      const listener = /** @type {!{handleFindShortcut: function(boolean)}} */ (
+          listeners[listeners.length - 1]);
+      if (listener.handleFindShortcut(modalContextOpen))
+        e.preventDefault();
+    }
+  });
+
+  window.addEventListener('cr-dialog-open', () => {
+    modalContextOpen = true;
+  });
+
+  window.addEventListener('cr-drawer-opened', () => {
+    modalContextOpen = true;
+  });
+
+  window.addEventListener('close', e => {
+    if (['CR-DIALOG', 'CR-DRAWER'].includes(e.composedPath()[0].nodeName))
+      modalContextOpen = false;
+  });
+
+  /**
+   * Used to determine how to handle find shortcut invocations.
+   * @polymerBehavior
+   */
+  const FindShortcutBehavior = {
+    /**
+     * If handled, return true.
+     * @param {boolean} modalContextOpen
+     * @return {boolean}
+     * @protected
+     */
+    handleFindShortcut(modalContextOpen) {
+      assertNotReached();
+    },
+
+    becomeActiveFindShortcutListener() {
+      assert(listeners.length == 0 || listeners[listeners.length - 1] != this);
+      listeners.push(this);
+    },
+
+    removeSelfAsFindShortcutListener() {
+      assert(listeners.pop() == this);
+    },
+  };
+
+  return {
+    FindShortcutBehavior,
+  };
+});
diff --git a/chrome/browser/resources/settings/languages_page/add_languages_dialog.js b/chrome/browser/resources/settings/languages_page/add_languages_dialog.js
index 4e38bc5f..77c6b94a 100644
--- a/chrome/browser/resources/settings/languages_page/add_languages_dialog.js
+++ b/chrome/browser/resources/settings/languages_page/add_languages_dialog.js
@@ -48,18 +48,25 @@
   /** @override */
   attached: function() {
     this.$.dialog.showModal();
+    this.becomeActiveFindShortcutListener();
+  },
+
+  /** @override */
+  detached: function() {
+    this.removeSelfAsFindShortcutListener();
   },
 
   // Override settings.FindShortcutBehavior methods.
-  canHandleFindShortcut: function() {
+  handleFindShortcut: function(modalContextOpen) {
+    // Assumes this is the only open modal.
+    const searchInput = this.$.search.getSearchInput();
+    if (searchInput != this.$.search.shadowRoot.activeElement) {
+      searchInput.scrollIntoViewIfNeeded();
+      searchInput.focus();
+    }
     return true;
   },
 
-  handleFindShortcut: function() {
-    this.$.search.getSearchInput().scrollIntoViewIfNeeded();
-    this.$.search.getSearchInput().focus();
-  },
-
   /**
    * @param {!CustomEvent} e
    * @private
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_page.html b/chrome/browser/resources/settings/multidevice_page/multidevice_page.html
index 68bbcfe..53b49fa 100644
--- a/chrome/browser/resources/settings/multidevice_page/multidevice_page.html
+++ b/chrome/browser/resources/settings/multidevice_page/multidevice_page.html
@@ -32,7 +32,7 @@
             <div id="multidevice-label">[[getLabelText_(pageContentData)]]</div>
             <div class="secondary" id="mutltideviceSubLabel" inner-h-t-m-l=
                 "[[getSubLabelInnerHtml_(pageContentData,
-                    prefs.multidevice_setup.enable_feature_suite.value)]]">
+                    prefs.multidevice_setup.suite_enabled.value)]]">
             </div>
           </div>
           <template is="dom-if"
@@ -51,7 +51,7 @@
           </template>
           <template is="dom-if" if="[[showToggle_(pageContentData)]]" restamp>
             <settings-multidevice-feature-toggle
-                pref="{{prefs.multidevice_setup.enable_feature_suite}}">
+                pref="{{prefs.multidevice_setup.suite_enabled}}">
             </settings-multidevice-feature-toggle>
           </template>
         </div>
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_page.js b/chrome/browser/resources/settings/multidevice_page/multidevice_page.js
index 500b562..9ccd097 100644
--- a/chrome/browser/resources/settings/multidevice_page/multidevice_page.js
+++ b/chrome/browser/resources/settings/multidevice_page/multidevice_page.js
@@ -73,7 +73,7 @@
       case settings.MultiDeviceSettingsMode.HOST_SET_WAITING_FOR_VERIFICATION:
         return this.i18nAdvanced('multideviceVerificationText');
       default:
-        return this.getPref('multidevice_setup.enable_feature_suite').value ?
+        return this.getPref('multidevice_setup.suite_enabled').value ?
             this.i18n('multideviceEnabled') :
             this.i18n('multideviceDisabled');
     }
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.html b/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.html
index 78d73c90..17b3615 100644
--- a/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.html
+++ b/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.html
@@ -25,12 +25,11 @@
     </style>
     <div class="settings-box first">
       <div id="status-text-container" class="start"
-          enabled$=
-              "[[prefs.multidevice_setup.enable_feature_suite.value]]">
-        [[getStatusText_(prefs.multidevice_setup.enable_feature_suite.value)]]
+          enabled$="[[prefs.multidevice_setup.suite_enabled.value]]">
+        [[getStatusText_(prefs.multidevice_setup.suite_enabled.value)]]
       </div>
       <settings-multidevice-feature-toggle
-          pref="{{prefs.multidevice_setup.enable_feature_suite}}">
+          pref="{{prefs.multidevice_setup.suite_enabled}}">
       </settings-multidevice-feature-toggle>
     </div>
     <template is="dom-if"
@@ -46,7 +45,7 @@
                  controlling Easy Unlock and make sure it's effectively
                  password protected. -->
             <settings-multidevice-feature-toggle
-                pref="{{prefs.multidevice_setup.enable_feature_suite}}">
+                pref="{{prefs.multidevice_setup.suite_enabled}}">
             </settings-multidevice-feature-toggle>
           </div>
         </settings-multidevice-feature-item>
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.js b/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.js
index d6f238b..5c2af21ff 100644
--- a/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.js
+++ b/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.js
@@ -45,7 +45,7 @@
    * @private
    */
   getStatusText_: function() {
-    return this.getPref('multidevice_setup.enable_feature_suite').value ?
+    return this.getPref('multidevice_setup.suite_enabled').value ?
         this.i18n('multideviceEnabled') :
         this.i18n('multideviceDisabled');
   },
diff --git a/chrome/browser/resources/settings/search_page/search_page.html b/chrome/browser/resources/settings/search_page/search_page.html
index 145c58d..0fa27b3f 100644
--- a/chrome/browser/resources/settings/search_page/search_page.html
+++ b/chrome/browser/resources/settings/search_page/search_page.html
@@ -47,9 +47,9 @@
         <!-- Omnibox search engine -->
         <div class="settings-box first block">
           <div id="search-wrapper">
-            <p id="searchExplanation" class="start">
+            <div id="searchExplanation" class="start">
               $i18nRaw{searchExplanation}
-            </p>
+            </div>
             <template is="dom-if" if="[[isDefaultSearchControlledByPolicy_(
                 prefs.default_search_provider_data.template_url_data)]]">
               <cr-policy-pref-indicator pref="[[
diff --git a/chrome/browser/resources/settings/settings_page/BUILD.gn b/chrome/browser/resources/settings/settings_page/BUILD.gn
index d354bfa..9114c55 100644
--- a/chrome/browser/resources/settings/settings_page/BUILD.gn
+++ b/chrome/browser/resources/settings/settings_page/BUILD.gn
@@ -46,6 +46,7 @@
 js_library("settings_subpage") {
   deps = [
     ":settings_subpage_search",
+    "..:find_shortcut_behavior",
     "..:route",
     "//third_party/polymer/v1_0/components-chromium/iron-resizable-behavior:iron-resizable-behavior-extracted",
     "//third_party/polymer/v1_0/components-chromium/neon-animation:neon-animatable-behavior-extracted",
diff --git a/chrome/browser/resources/settings/settings_page/settings_subpage.html b/chrome/browser/resources/settings/settings_page/settings_subpage.html
index 23206c9..b940d7f 100644
--- a/chrome/browser/resources/settings/settings_page/settings_subpage.html
+++ b/chrome/browser/resources/settings/settings_page/settings_subpage.html
@@ -7,6 +7,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-ripple/paper-ripple.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
+<link rel="import" href="../find_shortcut_behavior.html">
 <link rel="import" href="../icons.html">
 <link rel="import" href="../route.html">
 <link rel="import" href="settings_subpage_search.html">
diff --git a/chrome/browser/resources/settings/settings_page/settings_subpage.js b/chrome/browser/resources/settings/settings_page/settings_subpage.js
index 3288061..82fecc6 100644
--- a/chrome/browser/resources/settings/settings_page/settings_subpage.js
+++ b/chrome/browser/resources/settings/settings_page/settings_subpage.js
@@ -15,6 +15,8 @@
     // TODO(michaelpg): phase out NeonAnimatableBehavior.
     Polymer.NeonAnimatableBehavior,
     Polymer.IronResizableBehavior,
+    settings.FindShortcutBehavior,
+    settings.RouteObserverBehavior,
   ],
 
   properties: {
@@ -47,6 +49,13 @@
       type: Object,
       value: null,
     },
+
+    /** @private */
+    active_: {
+      type: Boolean,
+      value: false,
+      observer: 'onActiveChanged_',
+    },
   },
 
   /** @override */
@@ -71,6 +80,22 @@
         this, () => cr.ui.focusWithoutInk(this.$.closeButton));
   },
 
+  /** @protected */
+  currentRouteChanged: function(route) {
+    this.active_ = this.getAttribute('route-path') == route.path;
+  },
+
+  /** @private */
+  onActiveChanged_: function() {
+    if (!this.searchLabel)
+      return;
+
+    if (this.active_)
+      this.becomeActiveFindShortcutListener();
+    else
+      this.removeSelfAsFindShortcutListener();
+  },
+
   /**
    * Clear the value of the search field.
    * @param {!Event} e
@@ -89,4 +114,15 @@
   onSearchChanged_: function(e) {
     this.searchTerm = e.detail;
   },
+
+  // Override settings.FindShortcutBehavior methods.
+  handleFindShortcut: function(modalContextOpen) {
+    if (modalContextOpen)
+      return false;
+    const subpageSearch = this.$$('settings-subpage-search');
+    const searchInput = subpageSearch.getSearchInput();
+    if (searchInput != subpageSearch.shadowRoot.activeElement)
+      searchInput.focus();
+    return true;
+  },
 });
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index d2c4fdc..28cf453 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -609,8 +609,7 @@
                  type="chrome_html" />
       <structure name="IDR_SETTINGS_FIND_SHORTCUT_BEHAVIOR_JS"
                  file ="find_shortcut_behavior.js"
-                 type="chrome_html"
-                 preprocess="true" />
+                 type="chrome_html" />
       <structure name="IDR_SETTINGS_POWERWASH_DIALOG_HTML"
                  file="reset_page/powerwash_dialog.html"
                  type="chrome_html" />
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js
index b3e2d45..fde4fd05 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.js
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -80,15 +80,6 @@
     'refresh-pref': 'onRefreshPref_',
   },
 
-  /**
-   * Tracks if any cr-dialog is open anywhere in the UI. An assumption is being
-   * made that only one cr-dialog is open at a time. If this assumption changes
-   * |dialogOpen_| should be replaced with a count of the number of dialogs that
-   * are open.
-   * @private {boolean}
-   */
-  dialogOpen_: false,
-
   /** @override */
   created: function() {
     settings.initializeRouteFromUrl();
@@ -173,15 +164,6 @@
     this.addEventListener('hide-container', () => {
       this.$.container.style.visibility = 'hidden';
     });
-
-    this.addEventListener('cr-dialog-open', () => {
-      this.dialogOpen_ = true;
-    });
-
-    this.addEventListener('close', e => {
-      if (e.composedPath()[0].nodeName == 'CR-DIALOG')
-        this.dialogOpen_ = false;
-    });
   },
 
   /** @override */
@@ -215,6 +197,8 @@
       scrollToTop(e.detail.bottom - this.$.container.clientHeight)
           .then(e.detail.callback);
     });
+
+    this.becomeActiveFindShortcutListener();
   },
 
   /** @override */
@@ -246,12 +230,11 @@
   },
 
   // Override settings.FindShortcutBehavior methods.
-  canHandleFindShortcut: function() {
-    return !this.$.drawer.open && !this.dialogOpen_;
-  },
-
-  handleFindShortcut: function() {
+  handleFindShortcut: function(modalContextOpen) {
+    if (modalContextOpen)
+      return false;
     this.$$('cr-toolbar').getSearchField().showAndFocus();
+    return true;
   },
 
   /**
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index 52f82e2..29044636 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -402,9 +402,10 @@
   // Get theme information from theme service.
   theme_info_.reset(new ThemeBackgroundInfo());
 
-  // Get if the current theme is the default theme.
+  // Get if the current theme is the default theme (or GTK+ on linux).
   ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile_);
-  theme_info_->using_default_theme = theme_service->UsingDefaultTheme();
+  theme_info_->using_default_theme =
+      theme_service->UsingDefaultTheme() || theme_service->UsingSystemTheme();
 
   // Get theme colors.
   const ui::ThemeProvider& theme_provider =
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc
index 46e5865..69ead942 100644
--- a/chrome/browser/themes/browser_theme_pack.cc
+++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -51,7 +51,7 @@
 // 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 = 51;
+const int kThemePackVersion = 52;
 
 // 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
diff --git a/chrome/browser/ui/ash/ash_shell_init.cc b/chrome/browser/ui/ash/ash_shell_init.cc
index 9ce7976f..d95547c 100644
--- a/chrome/browser/ui/ash/ash_shell_init.cc
+++ b/chrome/browser/ui/ash/ash_shell_init.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/ui/ash/chrome_shell_delegate.h"
 #include "content/public/browser/context_factory.h"
+#include "content/public/common/service_manager_connection.h"
 #include "ui/aura/window_tree_host.h"
 
 namespace {
@@ -27,6 +28,9 @@
       content::GetContextFactoryPrivate();
   shell_init_params.gpu_interface_provider =
       std::make_unique<ash::ContentGpuInterfaceProvider>();
+  shell_init_params.connector =
+      content::ServiceManagerConnection::GetForProcess()->GetConnector();
+  DCHECK(shell_init_params.connector);
   // Pass the initial display prefs to ash::Shell as a Value dictionary.
   // This is done this way to avoid complexities with registering the display
   // prefs in multiple places (i.e. in g_browser_process->local_state() and
diff --git a/chrome/browser/ui/ash/chrome_keyboard_ui.cc b/chrome/browser/ui/ash/chrome_keyboard_ui.cc
index b4ed238..37ee9b4 100644
--- a/chrome/browser/ui/ash/chrome_keyboard_ui.cc
+++ b/chrome/browser/ui/ash/chrome_keyboard_ui.cc
@@ -479,8 +479,7 @@
   return (contents_window->GetRootWindow() == window->GetRootWindow() &&
           keyboard::IsKeyboardOverscrollEnabled() &&
           contents_window->IsVisible() &&
-          keyboard_controller()->IsKeyboardVisible() &&
-          !keyboard::IsFullscreenHandwritingVirtualKeyboardEnabled());
+          keyboard_controller()->IsKeyboardVisible());
 }
 
 void ChromeKeyboardUI::AddBoundsChangedObserver(aura::Window* window) {
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index 151c564..c5837ec 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -26,7 +26,6 @@
 #include "chrome/browser/ui/ash/session_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
-#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
@@ -89,10 +88,6 @@
 
 ChromeShellDelegate::~ChromeShellDelegate() = default;
 
-service_manager::Connector* ChromeShellDelegate::GetShellConnector() const {
-  return content::ServiceManagerConnection::GetForProcess()->GetConnector();
-}
-
 bool ChromeShellDelegate::CanShowWindowForUser(aura::Window* window) const {
   return ::CanShowWindowForUser(window,
                                 base::BindRepeating(&GetActiveBrowserContext));
@@ -111,17 +106,10 @@
 }
 
 void ChromeShellDelegate::OpenKeyboardShortcutHelpPage() const {
-  Profile* profile = ProfileManager::GetActiveUserProfile();
-  Browser* browser = chrome::FindTabbedBrowser(profile, false);
-
-  if (!browser) {
-    browser = new Browser(Browser::CreateParams(profile, true));
-    browser->window()->Show();
-  }
-
-  browser->window()->Activate();
-
-  NavigateParams params(browser, GURL(kKeyboardShortcutHelpPageUrl),
+  chrome::ScopedTabbedBrowserDisplayer scoped_tabbed_browser_displayer(
+      ProfileManager::GetActiveUserProfile());
+  NavigateParams params(scoped_tabbed_browser_displayer.browser(),
+                        GURL(kKeyboardShortcutHelpPageUrl),
                         ui::PAGE_TRANSITION_AUTO_BOOKMARK);
   params.disposition = WindowOpenDisposition::SINGLETON_TAB;
   Navigate(&params);
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h
index 51e7944..6532405 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.h
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -22,7 +22,6 @@
   ~ChromeShellDelegate() override;
 
   // ash::ShellDelegate overrides;
-  service_manager::Connector* GetShellConnector() const override;
   bool CanShowWindowForUser(aura::Window* window) const override;
   void PreInit() override;
   std::unique_ptr<keyboard::KeyboardUI> CreateKeyboardUI() override;
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index 2275f916..b15d21e 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -477,7 +477,9 @@
 
   const int item_padding = GetLayoutConstant(LOCATION_BAR_ELEMENT_PADDING);
 
-  constexpr int kTextJogIndentDp = 12;
+  // We have an odd indent value because this is what matches the odd text
+  // indent value in OmniboxMatchCellView.
+  constexpr int kTextJogIndentDp = 11;
   int leading_edit_item_padding =
       OmniboxFieldTrial::IsJogTextfieldOnPopupEnabled()
           ? GetOmniboxPopupView()->IsOpen() ? kTextJogIndentDp : 0
diff --git a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc
index 1fab783c..ed3c0ae 100644
--- a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc
+++ b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc
@@ -66,8 +66,6 @@
           IdentityManagerFactory::GetForProfile(
               Profile::FromBrowserContext(web_contents_->GetBrowserContext())
                   ->GetOriginalProfile()),
-          /*unmask_delegate=*/this,
-          /*save_delegate=*/nullptr,
           Profile::FromBrowserContext(web_contents_->GetBrowserContext())
               ->IsOffTheRecord()),
       full_card_request_(this,
@@ -82,12 +80,6 @@
 
 CvcUnmaskViewController::~CvcUnmaskViewController() {}
 
-void CvcUnmaskViewController::OnDidGetRealPan(
-    autofill::AutofillClient::PaymentsRpcResult result,
-    const std::string& real_pan) {
-  full_card_request_.OnDidGetRealPan(result, real_pan);
-}
-
 void CvcUnmaskViewController::LoadRiskData(
     const base::Callback<void(const std::string&)>& callback) {
   autofill::LoadRiskData(0, web_contents_, callback);
diff --git a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h
index 612715c..41e8c78f 100644
--- a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h
+++ b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.h
@@ -39,7 +39,6 @@
 class CvcUnmaskViewController
     : public PaymentRequestSheetController,
       public autofill::RiskDataLoader,
-      public autofill::payments::PaymentsClientUnmaskDelegate,
       public autofill::payments::FullCardRequest::UIDelegate,
       public views::ComboboxListener,
       public views::TextfieldController {
@@ -54,10 +53,6 @@
       content::WebContents* web_contents);
   ~CvcUnmaskViewController() override;
 
-  // autofill::payments::PaymentsClientUnmaskDelegate:
-  void OnDidGetRealPan(autofill::AutofillClient::PaymentsRpcResult result,
-                       const std::string& real_pan) override;
-
   // autofill::RiskDataLoader:
   void LoadRiskData(
       const base::Callback<void(const std::string&)>& callback) override;
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index 2d328a81..0d06906c 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -40,7 +40,6 @@
 #include "chrome/browser/lifetime/browser_shutdown.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/ash/login_screen_client.h"
 #include "chrome/browser/ui/webui/chromeos/login/active_directory_password_change_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
@@ -580,9 +579,6 @@
   AddCallback("updateOobeDialogSize",
               &GaiaScreenHandler::HandleUpdateOobeDialogSize);
   AddCallback("hideOobeDialog", &GaiaScreenHandler::HandleHideOobeDialog);
-  AddCallback("updateSigninUIState",
-              &GaiaScreenHandler::HandleUpdateSigninUIState);
-  AddCallback("showGuestButton", &GaiaScreenHandler::HandleShowGuestButton);
 
   // Allow UMA metrics collection from JS.
   web_ui()->AddMessageHandler(std::make_unique<MetricsHandler>());
@@ -856,26 +852,6 @@
                             base::Value(false) /* isSamlUserPasswordless */);
 }
 
-void GaiaScreenHandler::HandleUpdateSigninUIState(int state) {
-  if (!ash::features::IsViewsLoginEnabled() ||
-      !LoginScreenClient::HasInstance()) {
-    return;
-  }
-
-  auto dialog_state = static_cast<ash::mojom::OobeDialogState>(state);
-  DCHECK(ash::mojom::IsKnownEnumValue(dialog_state));
-  LoginScreenClient::Get()->login_screen()->NotifyOobeDialogState(dialog_state);
-}
-
-void GaiaScreenHandler::HandleShowGuestButton(bool show) {
-  if (!ash::features::IsViewsLoginEnabled() ||
-      !LoginScreenClient::HasInstance()) {
-    return;
-  }
-
-  LoginScreenClient::Get()->login_screen()->SetAllowLoginAsGuest(show);
-}
-
 void GaiaScreenHandler::OnShowAddUser() {
   signin_screen_handler_->is_account_picker_showing_first_time_ = false;
   lock_screen_utils::EnforcePolicyInputMethods(std::string());
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
index 6178fa46..84306fd 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
@@ -137,9 +137,6 @@
   void HandleGetIsSamlUserPasswordless(const std::string& callback_id,
                                        const std::string& typed_email,
                                        const std::string& gaia_id);
-  void HandleUpdateSigninUIState(int state);
-  void HandleShowGuestButton(bool show);
-
   void OnShowAddUser();
 
   // Really handles the complete login message.
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.cc b/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.cc
index a54f351..9153024 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.cc
@@ -14,18 +14,29 @@
 #include "content/public/browser/web_ui.h"
 #include "content/public/common/service_manager_connection.h"
 #include "services/service_manager/public/cpp/connector.h"
+#include "ui/chromeos/events/event_rewriter_chromeos.h"
 #include "ui/events/devices/input_device_manager.h"
 
 namespace {
 
-bool HasExternalKeyboard() {
+struct KeyboardsStateResult {
+  bool has_external_non_apple_keyboard = false;
+  bool has_apple_keyboard = false;
+};
+
+KeyboardsStateResult GetKeyboardsState() {
+  KeyboardsStateResult result;
   for (const ui::InputDevice& keyboard :
        ui::InputDeviceManager::GetInstance()->GetKeyboardDevices()) {
-    if (keyboard.type == ui::InputDeviceType::INPUT_DEVICE_EXTERNAL)
-      return true;
+    const ui::EventRewriterChromeOS::DeviceType type =
+        ui::EventRewriterChromeOS::GetDeviceType(keyboard);
+    if (type == ui::EventRewriterChromeOS::kDeviceAppleKeyboard)
+      result.has_apple_keyboard = true;
+    else if (type == ui::EventRewriterChromeOS::kDeviceExternalNonAppleKeyboard)
+      result.has_external_non_apple_keyboard = true;
   }
 
-  return false;
+  return result;
 }
 
 }  // namespace
@@ -115,14 +126,25 @@
 void KeyboardHandler::UpdateShowKeys() {
   // kHasChromeOSKeyboard will be unset on Chromebooks that have standalone Caps
   // Lock keys.
-  const base::Value has_caps_lock(
-      HasExternalKeyboard() ||
-      !base::CommandLine::ForCurrentProcess()->HasSwitch(
-          chromeos::switches::kHasChromeOSKeyboard));
-  const base::Value has_diamond_key(
+  const KeyboardsStateResult keyboards_state = GetKeyboardsState();
+  const bool has_caps_lock = keyboards_state.has_apple_keyboard ||
+                             keyboards_state.has_external_non_apple_keyboard ||
+                             !base::CommandLine::ForCurrentProcess()->HasSwitch(
+                                 chromeos::switches::kHasChromeOSKeyboard);
+  const bool has_diamond_key =
       base::CommandLine::ForCurrentProcess()->HasSwitch(
-          chromeos::switches::kHasChromeOSDiamondKey));
-  FireWebUIListener(kShowKeysChangedName, has_caps_lock, has_diamond_key);
+          chromeos::switches::kHasChromeOSDiamondKey);
+
+  base::Value keyboard_params(base::Value::Type::DICTIONARY);
+  keyboard_params.SetKey("showCapsLock", base::Value(has_caps_lock));
+  keyboard_params.SetKey("showDiamondKey", base::Value(has_diamond_key));
+  keyboard_params.SetKey(
+      "showExternalMetaKey",
+      base::Value(keyboards_state.has_external_non_apple_keyboard));
+  keyboard_params.SetKey("showAppleCommandKey",
+                         base::Value(keyboards_state.has_apple_keyboard));
+
+  FireWebUIListener(kShowKeysChangedName, keyboard_params);
 }
 
 }  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc b/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc
index c875a448..a020a2e 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc
@@ -45,7 +45,9 @@
   // which keys should be shown. False is returned if the message was invalid or
   // not found.
   bool GetLastShowKeysChangedMessage(bool* has_caps_lock_out,
-                                     bool* has_diamond_key_out)
+                                     bool* has_diamond_key_out,
+                                     bool* has_external_meta_key_out,
+                                     bool* has_apple_command_key_out)
       WARN_UNUSED_RESULT {
     for (auto it = web_ui_.call_data().rbegin();
          it != web_ui_.call_data().rend(); ++it) {
@@ -56,8 +58,29 @@
           name != KeyboardHandler::kShowKeysChangedName) {
         continue;
       }
-      return data->arg2()->GetAsBoolean(has_caps_lock_out) &&
-             data->arg3()->GetAsBoolean(has_diamond_key_out);
+
+      if (!data->arg2() ||
+          data->arg2()->type() != base::Value::Type::DICTIONARY) {
+        return false;
+      }
+
+      const base::Value* keyboard_params = data->arg2();
+      const std::vector<std::pair<std::string, bool*>> path_to_out_param = {
+          {"showCapsLock", has_caps_lock_out},
+          {"showDiamondKey", has_diamond_key_out},
+          {"showExternalMetaKey", has_external_meta_key_out},
+          {"showAppleCommandKey", has_apple_command_key_out},
+      };
+
+      for (const auto& pair : path_to_out_param) {
+        auto* found = keyboard_params->FindKey(pair.first);
+        if (!found)
+          return false;
+
+        *(pair.second) = found->GetBool();
+      }
+
+      return true;
     }
     return false;
   }
@@ -66,8 +89,10 @@
   // is present and false otherwise. A failure is added if a message wasn't
   // found.
   bool HasCapsLock() {
-    bool has_caps_lock = false, has_diamond_key = false;
-    if (!GetLastShowKeysChangedMessage(&has_caps_lock, &has_diamond_key)) {
+    bool has_caps_lock = false;
+    bool ignored = false;
+    if (!GetLastShowKeysChangedMessage(&has_caps_lock, &ignored, &ignored,
+                                       &ignored)) {
       ADD_FAILURE() << "Didn't get " << KeyboardHandler::kShowKeysChangedName;
       return false;
     }
@@ -78,14 +103,44 @@
   // is present and false otherwise. A failure is added if a message wasn't
   // found.
   bool HasDiamondKey() {
-    bool has_caps_lock = false, has_diamond_key = false;
-    if (!GetLastShowKeysChangedMessage(&has_caps_lock, &has_diamond_key)) {
+    bool has_diamond_key = false;
+    bool ignored = false;
+    if (!GetLastShowKeysChangedMessage(&ignored, &has_diamond_key, &ignored,
+                                       &ignored)) {
       ADD_FAILURE() << "Didn't get " << KeyboardHandler::kShowKeysChangedName;
       return false;
     }
     return has_diamond_key;
   }
 
+  // Returns true if the last keys-changed message reported that a Meta key on
+  // an external keyboard is present and false otherwise. A failure is added if
+  // a message wasn't found.
+  bool HasExternalMetaKey() {
+    bool has_external_meta = false;
+    bool ignored = false;
+    if (!GetLastShowKeysChangedMessage(&ignored, &ignored, &has_external_meta,
+                                       &ignored)) {
+      ADD_FAILURE() << "Didn't get " << KeyboardHandler::kShowKeysChangedName;
+      return false;
+    }
+    return has_external_meta;
+  }
+
+  // Returns true if the last keys-changed message reported that a Command key
+  // on an Apple keyboard is present and false otherwise. A failure is added if
+  // a message wasn't found.
+  bool HasAppleCommandKey() {
+    bool has_apple_command_key = false;
+    bool ignored = false;
+    if (!GetLastShowKeysChangedMessage(&ignored, &ignored, &ignored,
+                                       &has_apple_command_key)) {
+      ADD_FAILURE() << "Didn't get " << KeyboardHandler::kShowKeysChangedName;
+      return false;
+    }
+    return has_apple_command_key;
+  }
+
   ui::InputDeviceClientTestApi input_device_client_test_api_;
   content::TestWebUI web_ui_;
   TestKeyboardHandler handler_;
@@ -101,6 +156,8 @@
   handler_test_api_.Initialize();
   EXPECT_FALSE(HasCapsLock());
   EXPECT_FALSE(HasDiamondKey());
+  EXPECT_FALSE(HasExternalMetaKey());
+  EXPECT_FALSE(HasAppleCommandKey());
 }
 
 TEST_F(KeyboardHandlerTest, NonChromeOSKeyboard) {
@@ -109,6 +166,8 @@
   handler_test_api_.Initialize();
   EXPECT_TRUE(HasCapsLock());
   EXPECT_FALSE(HasDiamondKey());
+  EXPECT_FALSE(HasExternalMetaKey());
+  EXPECT_FALSE(HasAppleCommandKey());
 }
 
 TEST_F(KeyboardHandlerTest, ExternalKeyboard) {
@@ -120,18 +179,43 @@
   handler_test_api_.Initialize();
   EXPECT_FALSE(HasCapsLock());
   EXPECT_FALSE(HasDiamondKey());
+  EXPECT_FALSE(HasExternalMetaKey());
+  EXPECT_FALSE(HasAppleCommandKey());
 
   // Simulate an external keyboard being connected. We should assume there's a
-  // Caps Lock key now.
+  // Caps Lock and Meta keys now.
   input_device_client_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{
       {2, ui::INPUT_DEVICE_EXTERNAL, "external keyboard"}});
   EXPECT_TRUE(HasCapsLock());
   EXPECT_FALSE(HasDiamondKey());
+  EXPECT_TRUE(HasExternalMetaKey());
+  EXPECT_FALSE(HasAppleCommandKey());
+
+  // Simulate an external Apple keyboard being connected. Now users can remap
+  // the command key.
+  input_device_client_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{
+      {3, ui::INPUT_DEVICE_EXTERNAL, "Apple Inc. Apple Keyboard"}});
+  EXPECT_TRUE(HasCapsLock());
+  EXPECT_FALSE(HasDiamondKey());
+  EXPECT_FALSE(HasExternalMetaKey());
+  EXPECT_TRUE(HasAppleCommandKey());
+
+  // Simulate two external keyboards (Apple and non-Apple) are connected at the
+  // same time.
+  input_device_client_test_api_.SetKeyboardDevices(std::vector<ui::InputDevice>{
+      {2, ui::INPUT_DEVICE_EXTERNAL, "external keyboard"},
+      {3, ui::INPUT_DEVICE_EXTERNAL, "Apple Inc. Apple Keyboard"}});
+  EXPECT_TRUE(HasCapsLock());
+  EXPECT_FALSE(HasDiamondKey());
+  EXPECT_TRUE(HasExternalMetaKey());
+  EXPECT_TRUE(HasAppleCommandKey());
 
   // Disconnect the external keyboard and check that the key goes away.
   input_device_client_test_api_.SetKeyboardDevices({});
   EXPECT_FALSE(HasCapsLock());
   EXPECT_FALSE(HasDiamondKey());
+  EXPECT_FALSE(HasExternalMetaKey());
+  EXPECT_FALSE(HasAppleCommandKey());
 }
 
 TEST_F(KeyboardHandlerTest, DiamondKey) {
@@ -142,6 +226,8 @@
   handler_test_api_.Initialize();
   EXPECT_FALSE(HasCapsLock());
   EXPECT_TRUE(HasDiamondKey());
+  EXPECT_FALSE(HasExternalMetaKey());
+  EXPECT_FALSE(HasAppleCommandKey());
 }
 
 }  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 8b6355b..0339dfc 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -613,6 +613,9 @@
       {"keyboardKeyEscape", IDS_SETTINGS_KEYBOARD_KEY_ESCAPE},
       {"keyboardKeyBackspace", IDS_SETTINGS_KEYBOARD_KEY_BACKSPACE},
       {"keyboardKeyDisabled", IDS_SETTINGS_KEYBOARD_KEY_DISABLED},
+      {"keyboardKeyExternalCommand",
+       IDS_SETTINGS_KEYBOARD_KEY_EXTERNAL_COMMAND},
+      {"keyboardKeyExternalMeta", IDS_SETTINGS_KEYBOARD_KEY_EXTERNAL_META},
       {"keyboardSendFunctionKeys", IDS_SETTINGS_KEYBOARD_SEND_FUNCTION_KEYS},
       {"keyboardSendFunctionKeysDescription",
        ui::DeviceUsesKeyboardLayout2()
diff --git a/chrome/browser/web_applications/bookmark_apps/BUILD.gn b/chrome/browser/web_applications/bookmark_apps/BUILD.gn
index c79a8c9..12dc550 100644
--- a/chrome/browser/web_applications/bookmark_apps/BUILD.gn
+++ b/chrome/browser/web_applications/bookmark_apps/BUILD.gn
@@ -8,8 +8,6 @@
 
 source_set("bookmark_apps") {
   sources = [
-    "external_web_apps.cc",
-    "external_web_apps.h",
     "policy/web_app_policy_constants.cc",
     "policy/web_app_policy_constants.h",
     "policy/web_app_policy_manager.cc",
@@ -27,7 +25,6 @@
   testonly = true
 
   sources = [
-    "external_web_apps_unittest.cc",
     "policy/web_app_policy_manager_unittest.cc",
   ]
 
diff --git a/chrome/browser/web_applications/bookmark_apps/external_web_apps.cc b/chrome/browser/web_applications/bookmark_apps/external_web_apps.cc
deleted file mode 100644
index f65bc5d..0000000
--- a/chrome/browser/web_applications/bookmark_apps/external_web_apps.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/web_applications/bookmark_apps/external_web_apps.h"
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/callback.h"
-#include "base/files/file_enumerator.h"
-#include "base/json/json_file_value_serializer.h"
-#include "base/threading/thread_restrictions.h"
-#include "url/gurl.h"
-
-namespace web_app {
-
-static constexpr char kWebAppManifestUrl[] = "web_app_manifest_url";
-static constexpr char kWebAppStartUrl[] = "web_app_start_url";
-
-void ScanDirForExternalWebApps(base::FilePath dir,
-                               ScanDirForExternalWebAppsCallback callback) {
-  base::AssertBlockingAllowed();
-  base::FilePath::StringType extension(FILE_PATH_LITERAL(".json"));
-  base::FileEnumerator json_files(dir,
-                                  false,  // Recursive.
-                                  base::FileEnumerator::FILES);
-
-  std::vector<web_app::PendingAppManager::AppInfo> app_infos;
-
-  for (base::FilePath file = json_files.Next(); !file.empty();
-       file = json_files.Next()) {
-    if (!file.MatchesExtension(extension)) {
-      continue;
-    }
-
-    JSONFileValueDeserializer deserializer(file);
-    std::string error_msg;
-    std::unique_ptr<base::Value> value =
-        deserializer.Deserialize(nullptr, &error_msg);
-    if (!value) {
-      VLOG(2) << file.value() << " was not valid JSON: " << error_msg;
-      continue;
-    }
-    if (value->type() != base::Value::Type::DICTIONARY) {
-      VLOG(2) << file.value() << " was not a dictionary as the top level";
-      continue;
-    }
-    std::unique_ptr<base::DictionaryValue> dict_value =
-        base::DictionaryValue::From(std::move(value));
-
-    std::string manifest_url_str;
-    if (!dict_value->GetString(kWebAppStartUrl, &manifest_url_str) ||
-        manifest_url_str.empty() || !GURL(manifest_url_str).is_valid()) {
-      VLOG(2) << file.value() << " had an invalid " << kWebAppManifestUrl;
-      continue;
-    }
-
-    std::string start_url_str;
-    if (!dict_value->GetString(kWebAppStartUrl, &start_url_str) ||
-        start_url_str.empty()) {
-      VLOG(2) << file.value() << " had an invalid " << kWebAppStartUrl;
-      continue;
-    }
-    GURL start_url(start_url_str);
-    if (!start_url.is_valid()) {
-      VLOG(2) << file.value() << " had an invalid " << kWebAppStartUrl;
-      continue;
-    }
-
-    app_infos.emplace_back(
-        std::move(start_url),
-        web_app::PendingAppManager::LaunchContainer::kWindow);
-  }
-
-  std::move(callback).Run(std::move(app_infos));
-}
-
-}  //  namespace web_app
diff --git a/chrome/browser/web_applications/bookmark_apps/external_web_apps.h b/chrome/browser/web_applications/bookmark_apps/external_web_apps.h
deleted file mode 100644
index 5976242..0000000
--- a/chrome/browser/web_applications/bookmark_apps/external_web_apps.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_WEB_APPLICATIONS_BOOKMARK_APPS_EXTERNAL_WEB_APPS_H_
-#define CHROME_BROWSER_WEB_APPLICATIONS_BOOKMARK_APPS_EXTERNAL_WEB_APPS_H_
-
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/files/file_path.h"
-#include "chrome/browser/web_applications/components/pending_app_manager.h"
-
-namespace web_app {
-
-using ScanDirForExternalWebAppsCallback =
-    base::OnceCallback<void(std::vector<web_app::PendingAppManager::AppInfo>)>;
-
-// Scans the given directory (non-recursively) for *.json files that define
-// "external web apps", the Web App analogs of "external extensions", described
-// at https://developer.chrome.com/apps/external_extensions
-//
-// This function performs file I/O, and must not be scheduled on UI threads.
-void ScanDirForExternalWebApps(base::FilePath dir,
-                               ScanDirForExternalWebAppsCallback callback);
-
-}  // namespace web_app
-
-#endif  // CHROME_BROWSER_WEB_APPLICATIONS_BOOKMARK_APPS_EXTERNAL_WEB_APPS_H_
diff --git a/chrome/browser/web_applications/bookmark_apps/external_web_apps_unittest.cc b/chrome/browser/web_applications/bookmark_apps/external_web_apps_unittest.cc
deleted file mode 100644
index 84c98b1..0000000
--- a/chrome/browser/web_applications/bookmark_apps/external_web_apps_unittest.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 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/web_applications/bookmark_apps/external_web_apps.h"
-
-#include <algorithm>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/path_service.h"
-#include "chrome/common/chrome_paths.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace {
-
-static constexpr char kWebAppDefaultApps[] = "web_app_default_apps";
-
-// Returns the chrome/test/data/web_app_default_apps/sub_dir directory that
-// holds the *.json data files from which ScanDirForExternalWebApps should
-// extract URLs from.
-static base::FilePath test_dir(const char* sub_dir) {
-  base::FilePath dir;
-  if (!base::PathService::Get(chrome::DIR_TEST_DATA, &dir)) {
-    ADD_FAILURE()
-        << "base::PathService::Get could not resolve chrome::DIR_TEST_DATA";
-  }
-  return dir.AppendASCII(kWebAppDefaultApps).AppendASCII(sub_dir);
-}
-
-using AppInfos = std::vector<web_app::PendingAppManager::AppInfo>;
-
-}  // namespace
-
-class ScanDirForExternalWebAppsTest : public testing::Test {};
-
-TEST_F(ScanDirForExternalWebAppsTest, GoodJson) {
-  // The good_json directory contains two good JSON files:
-  // chrome_platform_status.json and google_io_2016.json.
-  web_app::ScanDirForExternalWebApps(
-      test_dir("good_json"), base::BindOnce([](AppInfos app_infos) {
-        static std::string urls[] = {
-            "https://www.chromestatus.com/features",
-            "https://events.google.com/io2016/?utm_source=web_app_manifest",
-        };
-
-        EXPECT_EQ(2u, app_infos.size());
-
-        for (const auto& url : urls) {
-          EXPECT_NE(
-              app_infos.end(),
-              std::find(
-                  app_infos.begin(), app_infos.end(),
-                  web_app::PendingAppManager::AppInfo(
-                      GURL(url),
-                      web_app::PendingAppManager::LaunchContainer::kWindow)));
-        }
-      }));
-}
-
-TEST_F(ScanDirForExternalWebAppsTest, BadJson) {
-  // The bad_json directory contains one (malformed) JSON file.
-  web_app::ScanDirForExternalWebApps(test_dir("bad_json"),
-                                     base::BindOnce([](AppInfos app_infos) {
-                                       EXPECT_EQ(0u, app_infos.size());
-                                     }));
-}
-
-TEST_F(ScanDirForExternalWebAppsTest, TxtButNoJson) {
-  // The txt_but_no_json directory contains one file, and the contents of that
-  // file is valid JSON, but that file's name does not end with ".json".
-  web_app::ScanDirForExternalWebApps(test_dir("txt_but_no_json"),
-                                     base::BindOnce([](AppInfos app_infos) {
-                                       EXPECT_EQ(0u, app_infos.size());
-                                     }));
-}
-
-TEST_F(ScanDirForExternalWebAppsTest, MixedJson) {
-  // The mixed_json directory contains one empty JSON file, one malformed JSON
-  // file and one good JSON file. ScanDirForExternalWebApps should still pick
-  // up that one good JSON file: polytimer.json.
-  web_app::ScanDirForExternalWebApps(
-      test_dir("mixed_json"), base::BindOnce([](AppInfos app_infos) {
-        EXPECT_EQ(1u, app_infos.size());
-        if (app_infos.size() == 1) {
-          EXPECT_EQ(app_infos[0].url.spec(),
-                    std::string("https://polytimer.rocks/?homescreen=1"));
-        }
-      }));
-}
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index 5e4ef808..6ccec79 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -4,14 +4,8 @@
 
 #include "chrome/browser/web_applications/web_app_provider.h"
 
-#include "base/bind.h"
-#include "base/path_service.h"
-#include "base/task_scheduler/post_task.h"
-#include "build/build_config.h"
-#include "chrome/browser/web_applications/bookmark_apps/external_web_apps.h"
 #include "chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager.h"
 #include "chrome/browser/web_applications/web_app_provider_factory.h"
-#include "chrome/common/chrome_paths.h"
 
 namespace web_app {
 
@@ -23,70 +17,9 @@
 WebAppProvider::WebAppProvider(PrefService* pref_service)
     : web_app_policy_manager_(
           std::make_unique<WebAppPolicyManager>(pref_service)) {
-#if defined(OS_CHROMEOS)
-  // As of mid 2018, only Chrome OS has default web apps or external web apps.
-  // In the future, we might open external web apps to other flavors.
-  ScanForExternalWebApps();
-#endif  // defined(OS_CHROMEOS)
+  // TODO(nigeltao): install default web apps as per http://crbug.com/855281
 }
 
 WebAppProvider::~WebAppProvider() = default;
 
-void WebAppProvider::ScanForExternalWebApps() {
-#if !defined(OS_CHROMEOS)
-  // chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS is only defined for OS_LINUX.
-  // OS_CHROMEOS is a variant of OS_LINUX.
-#else
-  // For manual testing, it can be useful to s/STANDALONE/USER/, as writing to
-  // "$HOME/.config/chromium/test-user/.config/chromium/External Extensions"
-  // does not require root ACLs, unlike "/usr/share/chromium/extensions".
-  //
-  // TODO(nigeltao): do we want to append a sub-directory name, analogous to
-  // the "arc" in "/usr/share/chromium/extensions/arc" as per
-  // chrome/browser/ui/app_list/arc/arc_default_app_list.cc? Or should we not
-  // sort "system apps" into directories based on their platform (e.g. ARC,
-  // PWA, etc.), and instead examine the JSON contents (e.g. an "activity"
-  // key means ARC, "web_app_start_url" key means PWA, etc.)?
-  base::FilePath dir;
-  if (!base::PathService::Get(chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS,
-                              &dir)) {
-    LOG(ERROR) << "ScanForExternalWebApps: base::PathService::Get failed";
-    return;
-  }
-
-  auto callback =
-      base::BindOnce(&WebAppProvider::ScanForExternalWebAppsCallback,
-                     weak_ptr_factory_.GetWeakPtr());
-
-  base::PostTaskWithTraits(FROM_HERE,
-                           {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
-                           base::BindOnce(&web_app::ScanDirForExternalWebApps,
-                                          dir, std::move(callback)));
-#endif  // !defined(OS_CHROMEOS)
-}
-
-void WebAppProvider::ScanForExternalWebAppsCallback(
-    std::vector<web_app::PendingAppManager::AppInfo> app_infos) {
-  // TODO(nigeltao/ortuno): we shouldn't need a *policy* manager to get to a
-  // PendingAppManager. As ortuno@ says, "We should refactor PendingAppManager
-  // to no longer be owned by WebAppPolicyManager. I made it that way since at
-  // the time, WebAppPolicyManager was its only client."
-  //
-  // TODO(nigeltao/ortuno): drop the const_cast. Either
-  // WebAppPolicyManager::pending_app_manager should lose the const or we
-  // should acquire a (non-const) PendingAppManager by other means.
-  auto& pending_app_manager = const_cast<web_app::PendingAppManager&>(
-      web_app_policy_manager_->pending_app_manager());
-
-  // TODO(nigeltao/ortuno): confirm that the PendingAppManager callee is
-  // responsible for filtering out already-installed apps.
-  //
-  // TODO(nigeltao/ortuno): does the PendingAppManager care which thread we're
-  // on (e.g. "the UI thread", "the File thread") when we call into it? Do we
-  // need to bounce to another thread from here? Note that, in the long term,
-  // we might not be in the browser process, so there might not be the concept
-  // of "the UI thread".
-  pending_app_manager.ProcessAppOperations(std::move(app_infos));
-}
-
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_provider.h b/chrome/browser/web_applications/web_app_provider.h
index 9a7f35da..f2bec23 100644
--- a/chrome/browser/web_applications/web_app_provider.h
+++ b/chrome/browser/web_applications/web_app_provider.h
@@ -6,11 +6,8 @@
 #define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_PROVIDER_H_
 
 #include <memory>
-#include <vector>
 
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/web_applications/components/pending_app_manager.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/prefs/pref_service.h"
 
@@ -32,14 +29,8 @@
   ~WebAppProvider() override;
 
  private:
-  void ScanForExternalWebApps();
-  void ScanForExternalWebAppsCallback(
-      std::vector<web_app::PendingAppManager::AppInfo>);
-
   std::unique_ptr<WebAppPolicyManager> web_app_policy_manager_;
 
-  base::WeakPtrFactory<WebAppProvider> weak_ptr_factory_{this};
-
   DISALLOW_COPY_AND_ASSIGN(WebAppProvider);
 };
 
diff --git a/chrome/common/extensions/api/settings_private.idl b/chrome/common/extensions/api/settings_private.idl
index f998ee3..1e2996c 100644
--- a/chrome/common/extensions/api/settings_private.idl
+++ b/chrome/common/extensions/api/settings_private.idl
@@ -62,10 +62,10 @@
     // Sets a pref value.
     // |name|: The name of the pref.
     // |value|: The new value of the pref.
-    // |pageId|: The user metrics identifier or null.
+    // |pageId|: An optional user metrics identifier.
     // |callback|: The callback for whether the pref was set or not.
     static void setPref(DOMString name, any value,
-        DOMString pageId, OnPrefSetCallback callback);
+        optional DOMString pageId, optional OnPrefSetCallback callback);
 
     // Gets an array of all the prefs.
     static void getAllPrefs(GetAllPrefsCallback callback);
diff --git a/chrome/common/media_router/discovery/media_sink_internal.cc b/chrome/common/media_router/discovery/media_sink_internal.cc
index 30a7b726..17e42335 100644
--- a/chrome/common/media_router/discovery/media_sink_internal.cc
+++ b/chrome/common/media_router/discovery/media_sink_internal.cc
@@ -25,6 +25,10 @@
   InternalCopyConstructFrom(other);
 }
 
+MediaSinkInternal::MediaSinkInternal(MediaSinkInternal&& other) noexcept {
+  InternalMoveConstructFrom(std::move(other));
+}
+
 MediaSinkInternal::~MediaSinkInternal() {
   InternalCleanup();
 }
@@ -38,6 +42,15 @@
   return *this;
 }
 
+MediaSinkInternal& MediaSinkInternal::operator=(
+    MediaSinkInternal&& other) noexcept {
+  if (this != &other) {
+    InternalCleanup();
+    InternalMoveConstructFrom(std::move(other));
+  }
+  return *this;
+}
+
 bool MediaSinkInternal::operator==(const MediaSinkInternal& other) const {
   if (sink_type_ != other.sink_type_)
     return false;
@@ -142,6 +155,23 @@
   NOTREACHED();
 }
 
+void MediaSinkInternal::InternalMoveConstructFrom(MediaSinkInternal&& other) {
+  sink_ = std::move(other.sink_);
+  sink_type_ = other.sink_type_;
+
+  switch (sink_type_) {
+    case SinkType::DIAL:
+      new (&dial_data_) DialSinkExtraData(std::move(other.dial_data_));
+      return;
+    case SinkType::CAST:
+      new (&cast_data_) CastSinkExtraData(std::move(other.cast_data_));
+      return;
+    case SinkType::GENERIC:
+      return;
+  }
+  NOTREACHED();
+}
+
 void MediaSinkInternal::InternalCleanup() {
   switch (sink_type_) {
     case SinkType::DIAL:
@@ -158,6 +188,8 @@
 
 DialSinkExtraData::DialSinkExtraData() = default;
 DialSinkExtraData::DialSinkExtraData(const DialSinkExtraData& other) = default;
+DialSinkExtraData::DialSinkExtraData(DialSinkExtraData&& other) noexcept =
+    default;
 DialSinkExtraData::~DialSinkExtraData() = default;
 
 bool DialSinkExtraData::operator==(const DialSinkExtraData& other) const {
@@ -167,6 +199,8 @@
 
 CastSinkExtraData::CastSinkExtraData() = default;
 CastSinkExtraData::CastSinkExtraData(const CastSinkExtraData& other) = default;
+CastSinkExtraData::CastSinkExtraData(CastSinkExtraData&& other) noexcept =
+    default;
 CastSinkExtraData::~CastSinkExtraData() = default;
 
 bool CastSinkExtraData::operator==(const CastSinkExtraData& other) const {
diff --git a/chrome/common/media_router/discovery/media_sink_internal.h b/chrome/common/media_router/discovery/media_sink_internal.h
index b1cbe15..c2e3691 100644
--- a/chrome/common/media_router/discovery/media_sink_internal.h
+++ b/chrome/common/media_router/discovery/media_sink_internal.h
@@ -26,6 +26,7 @@
 
   DialSinkExtraData();
   DialSinkExtraData(const DialSinkExtraData& other);
+  DialSinkExtraData(DialSinkExtraData&& other) noexcept;
   ~DialSinkExtraData();
 
   bool operator==(const DialSinkExtraData& other) const;
@@ -54,6 +55,7 @@
 
   CastSinkExtraData();
   CastSinkExtraData(const CastSinkExtraData& other);
+  CastSinkExtraData(CastSinkExtraData&& other) noexcept;
   ~CastSinkExtraData();
 
   bool operator==(const CastSinkExtraData& other) const;
@@ -73,10 +75,12 @@
 
   // Used to push instance of this class into vector.
   MediaSinkInternal(const MediaSinkInternal& other);
+  MediaSinkInternal(MediaSinkInternal&& other) noexcept;
 
   ~MediaSinkInternal();
 
   MediaSinkInternal& operator=(const MediaSinkInternal& other);
+  MediaSinkInternal& operator=(MediaSinkInternal&& other) noexcept;
   bool operator==(const MediaSinkInternal& other) const;
   bool operator!=(const MediaSinkInternal& other) const;
   // Sorted by sink id.
@@ -109,6 +113,7 @@
 
  private:
   void InternalCopyConstructFrom(const MediaSinkInternal& other);
+  void InternalMoveConstructFrom(MediaSinkInternal&& other);
   void InternalCleanup();
 
   enum class SinkType { GENERIC, DIAL, CAST };
diff --git a/chrome/common/media_router/discovery/media_sink_service_base.cc b/chrome/common/media_router/discovery/media_sink_service_base.cc
index fc68861..a9536cd 100644
--- a/chrome/common/media_router/discovery/media_sink_service_base.cc
+++ b/chrome/common/media_router/discovery/media_sink_service_base.cc
@@ -72,6 +72,21 @@
   StartTimer();
 }
 
+void MediaSinkServiceBase::RemoveSinkById(const MediaSink::Id& sink_id) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  auto it = sinks_.find(sink_id);
+  if (it == sinks_.end())
+    return;
+
+  // Make a copy of the sink to avoid potential use-after-free.
+  MediaSinkInternal sink = it->second;
+  sinks_.erase(it);
+  for (auto& observer : observers_)
+    observer.OnSinkRemoved(sink);
+
+  StartTimer();
+}
+
 void MediaSinkServiceBase::SetTimerForTest(
     std::unique_ptr<base::OneShotTimer> timer) {
   discovery_timer_ = std::move(timer);
diff --git a/chrome/common/media_router/discovery/media_sink_service_base.h b/chrome/common/media_router/discovery/media_sink_service_base.h
index fa7c038..71a4e84b 100644
--- a/chrome/common/media_router/discovery/media_sink_service_base.h
+++ b/chrome/common/media_router/discovery/media_sink_service_base.h
@@ -63,6 +63,7 @@
   // Also invokes |StartTimer()|.
   void AddOrUpdateSink(const MediaSinkInternal& sink);
   void RemoveSink(const MediaSinkInternal& sink);
+  void RemoveSinkById(const MediaSink::Id& sink_id);
 
   const base::flat_map<MediaSink::Id, MediaSinkInternal>& GetSinks() const;
   const MediaSinkInternal* GetSinkById(const MediaSink::Id& sink_id) const;
diff --git a/chrome/common/media_router/media_sink.cc b/chrome/common/media_router/media_sink.cc
index fe05c1c..09b41997 100644
--- a/chrome/common/media_router/media_sink.cc
+++ b/chrome/common/media_router/media_sink.cc
@@ -19,10 +19,12 @@
       provider_id_(provider_id) {}
 
 MediaSink::MediaSink(const MediaSink& other) = default;
+MediaSink::MediaSink(MediaSink&& other) noexcept = default;
+MediaSink::MediaSink() = default;
+MediaSink::~MediaSink() = default;
 
-MediaSink::MediaSink() {}
-
-MediaSink::~MediaSink() {}
+MediaSink& MediaSink::operator=(const MediaSink& other) = default;
+MediaSink& MediaSink::operator=(MediaSink&& other) noexcept = default;
 
 bool MediaSink::Equals(const MediaSink& other) const {
   return sink_id_ == other.sink_id_;
diff --git a/chrome/common/media_router/media_sink.h b/chrome/common/media_router/media_sink.h
index f47b68fc..f4b6f8c 100644
--- a/chrome/common/media_router/media_sink.h
+++ b/chrome/common/media_router/media_sink.h
@@ -49,10 +49,13 @@
             SinkIconType icon_type,
             MediaRouteProviderId provider_id = MediaRouteProviderId::UNKNOWN);
   MediaSink(const MediaSink& other);
+  MediaSink(MediaSink&& other) noexcept;
   MediaSink();
-
   ~MediaSink();
 
+  MediaSink& operator=(const MediaSink& other);
+  MediaSink& operator=(MediaSink&& other) noexcept;
+
   void set_sink_id(const MediaSink::Id& sink_id) { sink_id_ = sink_id; }
   const MediaSink::Id& id() const { return sink_id_; }
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index b058385..e2bc910 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -504,8 +504,6 @@
       "../browser/chrome_find_request_manager_browsertest.cc",
       "../browser/chrome_main_browsertest.cc",
       "../browser/chrome_navigation_browsertest.cc",
-      "../browser/chrome_network_service_browsertest.cc",
-      "../browser/chrome_network_service_restart_browsertest.cc",
       "../browser/chrome_origin_trials_browsertest.cc",
       "../browser/chrome_plugin_browsertest.cc",
       "../browser/chrome_security_exploit_browsertest.cc",
@@ -621,6 +619,8 @@
       "../browser/net/chrome_accept_header_browsertest.cc",
       "../browser/net/chrome_mojo_proxy_resolver_factory_browsertest.cc",
       "../browser/net/chrome_network_delegate_browsertest.cc",
+      "../browser/net/chrome_network_service_browsertest.cc",
+      "../browser/net/chrome_network_service_restart_browsertest.cc",
       "../browser/net/cookie_policy_browsertest.cc",
       "../browser/net/dns_probe_browsertest.cc",
       "../browser/net/errorpage_browsertest.cc",
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 1f5cc05..391d57b 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -113,6 +113,8 @@
     'ChromeDriverTest.testWindowMinimize',
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2522
     'ChromeDriverTest.testWindowMaximize',
+    # https://bugs.chromium.org/p/chromium/issues/detail?id=868376
+    'ChromeDriverTest.testHasFocusOnStartup',
 ]
 
 _DESKTOP_NEGATIVE_FILTER = [
diff --git a/chrome/test/data/navigation_predictor/anchors_different_area.html b/chrome/test/data/navigation_predictor/anchors_different_area.html
new file mode 100644
index 0000000..c0daddb
--- /dev/null
+++ b/chrome/test/data/navigation_predictor/anchors_different_area.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+  </head>
+  <body>
+    <a id="small" href="https://example.com/2"><img height="2" width="2"></a>
+    <a id="xlarge" href="https://google.com"><img height="5" width="5"></a>
+    <a id="xmall" href="https://example.com/1"><img height="1" width="1"></a>
+    <a id="medium" href="https://example.com"><img height="3" width="3"></a>
+    <a id="large" href="https://dummy.com"><img height="4" width="4"></a>
+  </body>
+</html>
\ No newline at end of file
diff --git a/chrome/test/data/web_app_default_apps/bad_json/malformed0.json b/chrome/test/data/web_app_default_apps/bad_json/malformed0.json
deleted file mode 100644
index 520f87f..0000000
--- a/chrome/test/data/web_app_default_apps/bad_json/malformed0.json
+++ /dev/null
@@ -1 +0,0 @@
-This is not valid JSON.
diff --git a/chrome/test/data/web_app_default_apps/good_json/chrome_platform_status.json b/chrome/test/data/web_app_default_apps/good_json/chrome_platform_status.json
deleted file mode 100644
index f5e81a7..0000000
--- a/chrome/test/data/web_app_default_apps/good_json/chrome_platform_status.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "web_app_manifest_url": "https://www.chromestatus.com/static/manifest.json",
-  "web_app_start_url": "https://www.chromestatus.com/features"
-}
diff --git a/chrome/test/data/web_app_default_apps/good_json/google_io_2016.json b/chrome/test/data/web_app_default_apps/good_json/google_io_2016.json
deleted file mode 100644
index e7c5c10..0000000
--- a/chrome/test/data/web_app_default_apps/good_json/google_io_2016.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "web_app_manifest_url": "https://events.google.com/io2016/manifest.json",
-  "web_app_start_url": "https://events.google.com/io2016/?utm_source=web_app_manifest"
-}
diff --git a/chrome/test/data/web_app_default_apps/mixed_json/empty.json b/chrome/test/data/web_app_default_apps/mixed_json/empty.json
deleted file mode 100644
index e69de29..0000000
--- a/chrome/test/data/web_app_default_apps/mixed_json/empty.json
+++ /dev/null
diff --git a/chrome/test/data/web_app_default_apps/mixed_json/malformed1.json b/chrome/test/data/web_app_default_apps/mixed_json/malformed1.json
deleted file mode 100644
index 10cce0e..0000000
--- a/chrome/test/data/web_app_default_apps/mixed_json/malformed1.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "web_app_manifest_url": "https://www.chromestatus.com/static/manifest.json",
-  "web_app_start_url": "https://www.chromestatus.com/features",
-  "this is malformed JSON because there's no end quote
-}
diff --git a/chrome/test/data/web_app_default_apps/mixed_json/polytimer.json b/chrome/test/data/web_app_default_apps/mixed_json/polytimer.json
deleted file mode 100644
index 7858618..0000000
--- a/chrome/test/data/web_app_default_apps/mixed_json/polytimer.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "web_app_manifest_url": "https://polytimer.rocks/manifest.json",
-  "web_app_start_url": "https://polytimer.rocks/?homescreen=1"
-}
diff --git a/chrome/test/data/web_app_default_apps/txt_but_no_json/chrome_platform_status.txt b/chrome/test/data/web_app_default_apps/txt_but_no_json/chrome_platform_status.txt
deleted file mode 100644
index f5e81a7..0000000
--- a/chrome/test/data/web_app_default_apps/txt_but_no_json/chrome_platform_status.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "web_app_manifest_url": "https://www.chromestatus.com/static/manifest.json",
-  "web_app_start_url": "https://www.chromestatus.com/features"
-}
diff --git a/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js b/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js
index df9a05ba..486c5b0 100644
--- a/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js
+++ b/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js
@@ -884,3 +884,34 @@
     function() {
   this.runMochaTest(destination_list_test.TestNames.FireDestinationSelected);
 });
+
+PrintPreviewPrintButtonTest = class extends NewPrintPreviewTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://print/new/app.html';
+  }
+
+  /** @override */
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      '../test_browser_proxy.js',
+      'native_layer_stub.js',
+      'plugin_stub.js',
+      'print_preview_test_utils.js',
+      'print_button_test.js',
+    ]);
+  }
+
+  /** @override */
+  get suiteName() {
+    return print_button_test.suiteName;
+  }
+};
+
+TEST_F('PrintPreviewPrintButtonTest', 'LocalPrintHidePreview', function() {
+  this.runMochaTest(print_button_test.TestNames.LocalPrintHidePreview);
+});
+
+TEST_F('PrintPreviewPrintButtonTest', 'PDFPrintVisiblePreview', function() {
+  this.runMochaTest(print_button_test.TestNames.PDFPrintVisiblePreview);
+});
diff --git a/chrome/test/data/webui/print_preview/print_button_test.js b/chrome/test/data/webui/print_preview/print_button_test.js
new file mode 100644
index 0000000..28a3d92
--- /dev/null
+++ b/chrome/test/data/webui/print_preview/print_button_test.js
@@ -0,0 +1,140 @@
+// 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.
+
+cr.define('print_button_test', function() {
+  /** @enum {string} */
+  const TestNames = {
+    LocalPrintHidePreview: 'local print hide preview',
+    PDFPrintVisiblePreview: 'pdf print visible preview',
+  };
+
+  const suiteName = 'PrintButtonTest';
+  suite(suiteName, function() {
+    /** @type {?PrintPreviewAppElement} */
+    let page = null;
+
+    /** @type {?print_preview.NativeLayer} */
+    let nativeLayer = null;
+
+    /** @type {boolean} */
+    let printBeforePreviewReady = false;
+
+    /** @type {boolean} */
+    let previewHidden = false;
+
+    /** @type {!print_preview.NativeInitialSettings} */
+    const initialSettings =
+        print_preview_test_utils.getDefaultInitialSettings();
+
+    /** @override */
+    setup(function() {
+      nativeLayer = new print_preview.NativeLayerStub();
+      print_preview.NativeLayer.setInstance(nativeLayer);
+      PolymerTest.clearBody();
+      nativeLayer.setInitialSettings(initialSettings);
+      let localDestinationInfos = [
+        {printerName: 'FooName', deviceName: 'FooDevice'},
+      ];
+      nativeLayer.setLocalDestinations(localDestinationInfos);
+      nativeLayer.setLocalDestinationCapabilities(
+          print_preview_test_utils.getCddTemplate(
+              initialSettings.printerName));
+      nativeLayer.setLocalDestinationCapabilities(
+          print_preview_test_utils.getPdfPrinter());
+
+      const pluginProxy = new print_preview.PDFPluginStub();
+      pluginProxy.setPluginCompatible(true);
+      print_preview_new.PluginProxy.setInstance(pluginProxy);
+
+      page = document.createElement('print-preview-app');
+      document.body.appendChild(page);
+      pluginProxy.setLoadCallback(() => {
+        // Print before calling previewArea.onPluginLoad_. This simulates the
+        // user clicking the print button while the preview is still loading,
+        // since previewArea.onPluginLoad_() indicates to the UI that the
+        // preview is ready.
+        if (printBeforePreviewReady) {
+          const header = page.$$('print-preview-header');
+          const printButton = header.$$('.print');
+          assertFalse(printButton.disabled);
+          printButton.click();
+        }
+
+        const previewArea = page.$.previewArea;
+        previewArea.onPluginLoad_(true);
+      });
+
+      previewHidden = false;
+      nativeLayer.whenCalled('hidePreview').then(() => {
+        previewHidden = true;
+      });
+    });
+
+    function waitForInitialPreview() {
+      return nativeLayer.whenCalled('getInitialSettings')
+          .then(function() {
+            page.destinationStore_.startLoadDestinations(
+                print_preview.PrinterType.LOCAL_PRINTER);
+            // Wait for the preview request.
+            return Promise.all([
+              nativeLayer.whenCalled('getPrinterCapabilities'),
+              nativeLayer.whenCalled('getPreview')
+            ]);
+          });
+    }
+
+    // Tests that hidePreview() is called before print() if a local printer is
+    // selected and the user clicks print while the preview is loading.
+    test(assert(TestNames.LocalPrintHidePreview), function() {
+      printBeforePreviewReady = true;
+
+      return waitForInitialPreview().then(function() {
+        // Wait for the print request.
+        return nativeLayer.whenCalled('print');
+      }).then(function(printTicket) {
+        assertTrue(previewHidden);
+
+        // Verify that the printer name is correct.
+        assertEquals('FooDevice', JSON.parse(printTicket).deviceName);
+        return nativeLayer.whenCalled('dialogClose');
+      });
+    });
+
+    // Tests that hidePreview() is not called if Save as PDF is selected and
+    // the user clicks print while the preview is loading.
+    test(assert(TestNames.PDFPrintVisiblePreview), function() {
+      printBeforePreviewReady = false;
+
+      return waitForInitialPreview().then(function() {
+        // Setup to print before the preview loads.
+        printBeforePreviewReady = true;
+
+        // Select Save as PDF destination
+        const pdfDestination = page.destinationStore_.destinations().find(
+                d => d.id == 'Save as PDF');
+        assertTrue(!!pdfDestination);
+        page.destinationStore_.selectDestination(pdfDestination);
+
+        // Reload preview and wait for print.
+        return Promise.all([
+          nativeLayer.whenCalled('getPrinterCapabilities'),
+          nativeLayer.whenCalled('getPreview'),
+          nativeLayer.whenCalled('print')
+        ]);
+      }).then(function(args) {
+        assertFalse(previewHidden);
+
+        const printTicket = args[2];
+        // Verify that the printer name is correct.
+        assertEquals('Save as PDF', JSON.parse(printTicket).deviceName);
+        return nativeLayer.whenCalled('dialogClose');
+      });
+    });
+  });
+
+  return {
+    suiteName: suiteName,
+    TestNames: TestNames,
+  };
+});
diff --git a/chrome/test/data/webui/print_preview/print_preview_test_utils.js b/chrome/test/data/webui/print_preview/print_preview_test_utils.js
index 8695eb0..34231067 100644
--- a/chrome/test/data/webui/print_preview/print_preview_test_utils.js
+++ b/chrome/test/data/webui/print_preview/print_preview_test_utils.js
@@ -167,6 +167,38 @@
   }
 
   /**
+   * @return {!print_preview.PrinterCapabilitiesResponse} The capabilities of
+   *     the Save as PDF destination.
+   */
+  function getPdfPrinter() {
+    return {
+      printer: {
+        deviceName: 'Save as PDF',
+      },
+      capabilities: {
+        version: '1.0',
+        printer: {
+          page_orientation: {
+            option: [
+              {type: 'AUTO', is_default: true}, {type: 'PORTRAIT'},
+              {type: 'LANDSCAPE'}
+            ]
+          },
+          color: {option: [{type: 'STANDARD_COLOR', is_default: true}]},
+          media_size: {
+            option: [{
+              name: 'NA_LETTER',
+              width_microns: 0,
+              height_microns: 0,
+              is_default: true
+            }]
+          }
+        }
+      }
+    };
+  }
+
+  /**
    * Get the default media size for |device|.
    * @param {!print_preview.PrinterCapabilitiesResponse} device
    * @return {{width_microns: number,
@@ -259,5 +291,6 @@
     getDestinations: getDestinations,
     getMediaSizeCapabilityWithCustomNames:
         getMediaSizeCapabilityWithCustomNames,
+    getPdfPrinter: getPdfPrinter,
   };
 });
diff --git a/chrome/test/data/webui/print_preview/print_preview_tests.js b/chrome/test/data/webui/print_preview/print_preview_tests.js
index cf7f030..e2352d0 100644
--- a/chrome/test/data/webui/print_preview/print_preview_tests.js
+++ b/chrome/test/data/webui/print_preview/print_preview_tests.js
@@ -108,38 +108,6 @@
   }
 
   /**
-   * @return {!print_preview.PrinterCapabilitiesResponse} The capabilities of
-   *     the Save as PDF destination.
-   */
-  function getPdfPrinter() {
-    return {
-      printer: {
-        deviceName: 'Save as PDF',
-      },
-      capabilities: {
-        version: '1.0',
-        printer: {
-          page_orientation: {
-            option: [
-              {type: 'AUTO', is_default: true}, {type: 'PORTRAIT'},
-              {type: 'LANDSCAPE'}
-            ]
-          },
-          color: {option: [{type: 'STANDARD_COLOR', is_default: true}]},
-          media_size: {
-            option: [{
-              name: 'NA_LETTER',
-              width_microns: 0,
-              height_microns: 0,
-              is_default: true
-            }]
-          }
-        }
-      }
-    };
-  }
-
-  /**
    * Gets a serialized app state string with some non-default values.
    * @return {string}
    */
@@ -618,7 +586,8 @@
       initialSettings.printerName = 'Save as PDF';
 
       // Set PDF printer
-      nativeLayer.setLocalDestinationCapabilities(getPdfPrinter());
+      nativeLayer.setLocalDestinationCapabilities(
+          print_preview_test_utils.getPdfPrinter());
 
       setInitialSettings();
       return nativeLayer.whenCalled('getInitialSettings')
@@ -1661,7 +1630,7 @@
       // Test that Mac "Open PDF in Preview" link is treated correctly as a
       // local printer. See crbug.com/741341 and crbug.com/741528
       test('MacOpenPDFInPreview', function() {
-        const device = getPdfPrinter();
+        const device = print_preview_test_utils.getPdfPrinter();
         initialSettings.printerName = device.printer.deviceName;
         return setupSettingsAndDestinationsWithCapabilities(device)
             .then(function() {
@@ -1691,7 +1660,7 @@
       // Test that the OpenPDFInPreview link is correctly disabled when the
       // print ticket is invalid.
       test('MacOpenPDFInPreviewBadPrintTicket', function() {
-        const device = getPdfPrinter();
+        const device = print_preview_test_utils.getPdfPrinter();
         initialSettings.printerName = device.printer.deviceName;
         const openPdfPreviewLink = $('open-pdf-in-preview-link');
         return Promise
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index c6f4ab2..4e635502 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -2097,3 +2097,31 @@
   mocha.run();
 });
 GEN('#endif  // defined(OS_CHROMEOS)');
+
+/**
+ * Test fixture for FindShortcutBehavior.
+ * @constructor
+ * @extends {CrSettingsBrowserTest}
+ */
+function CrSettingsFindShortcutBehavior() {}
+
+CrSettingsFindShortcutBehavior.prototype = {
+  __proto__: CrSettingsBrowserTest.prototype,
+
+  /**
+   * Preload a module that depends on both cr-dialog and FindShortcutBehavior.
+   * cr-dialog is used in the tests.
+   * @override
+   */
+  browsePreload: 'chrome://settings/languages_page/add_languages_dialog.html',
+
+  /** @override */
+  extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
+    'test_util.js',
+    'find_shortcut_behavior_test.js',
+  ]),
+};
+
+TEST_F('CrSettingsFindShortcutBehavior', 'All', function() {
+  mocha.run();
+});
diff --git a/chrome/test/data/webui/settings/device_page_tests.js b/chrome/test/data/webui/settings/device_page_tests.js
index 3ef75e1..3e2fd9f 100644
--- a/chrome/test/data/webui/settings/device_page_tests.js
+++ b/chrome/test/data/webui/settings/device_page_tests.js
@@ -611,21 +611,45 @@
             expectFalse(!!keyboardPage.$$('#diamondKey'));
 
             // Pretend the diamond key is available.
-            let showCapsLock = false;
-            const showDiamondKey = true;
-            cr.webUIListenerCallback(
-                'show-keys-changed', showCapsLock, showDiamondKey);
+            let keyboardParams = {
+              'showCapsLock': false,
+              'showDiamondKey': true,
+              'showExternalMetaKey': false,
+              'showAppleCommandKey': false,
+            };
+            cr.webUIListenerCallback('show-keys-changed', keyboardParams);
             Polymer.dom.flush();
             expectFalse(!!keyboardPage.$$('#capsLockKey'));
             expectTrue(!!keyboardPage.$$('#diamondKey'));
+            expectFalse(!!keyboardPage.$$('#externalMetaKey'));
+            expectFalse(!!keyboardPage.$$('#externalCommandKey'));
 
             // Pretend a Caps Lock key is now available.
-            showCapsLock = true;
-            cr.webUIListenerCallback(
-                'show-keys-changed', showCapsLock, showDiamondKey);
+            keyboardParams['showCapsLock'] = true;
+            cr.webUIListenerCallback('show-keys-changed', keyboardParams);
             Polymer.dom.flush();
             expectTrue(!!keyboardPage.$$('#capsLockKey'));
             expectTrue(!!keyboardPage.$$('#diamondKey'));
+            expectFalse(!!keyboardPage.$$('#externalMetaKey'));
+            expectFalse(!!keyboardPage.$$('#externalCommandKey'));
+
+            // Add a non-Apple external keyboard.
+            keyboardParams['showExternalMetaKey'] = true;
+            cr.webUIListenerCallback('show-keys-changed', keyboardParams);
+            Polymer.dom.flush();
+            expectTrue(!!keyboardPage.$$('#capsLockKey'));
+            expectTrue(!!keyboardPage.$$('#diamondKey'));
+            expectTrue(!!keyboardPage.$$('#externalMetaKey'));
+            expectFalse(!!keyboardPage.$$('#externalCommandKey'));
+
+            // Add an Apple keyboard.
+            keyboardParams['showAppleCommandKey'] = true;
+            cr.webUIListenerCallback('show-keys-changed', keyboardParams);
+            Polymer.dom.flush();
+            expectTrue(!!keyboardPage.$$('#capsLockKey'));
+            expectTrue(!!keyboardPage.$$('#diamondKey'));
+            expectTrue(!!keyboardPage.$$('#externalMetaKey'));
+            expectTrue(!!keyboardPage.$$('#externalCommandKey'));
 
             const collapse = keyboardPage.$$('iron-collapse');
             assertTrue(!!collapse);
diff --git a/chrome/test/data/webui/settings/find_shortcut_behavior_test.js b/chrome/test/data/webui/settings/find_shortcut_behavior_test.js
new file mode 100644
index 0000000..bd2ba29
--- /dev/null
+++ b/chrome/test/data/webui/settings/find_shortcut_behavior_test.js
@@ -0,0 +1,152 @@
+// 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.
+
+suite('find-shortcut', () => {
+  /** @typedef {{
+   *    becomeActiveFindShortcutListener: !Function,
+   *    removeSelfAsFindShortcutListener: !Function,
+   *  }}
+   */
+  let Listener;
+
+  /**
+   * @type {PromiseResolver<!{modalContextOpen: boolean, self: HTMLElement}>}
+   */
+  let waits;
+  /** @type {number} */
+  let nextWait;
+
+  /**
+   * @param {!Array} fns
+   * @return {!Promise}
+   */
+  const promiseSeries = fns =>
+      fns.reduce((acc, fn) => acc.then(fn), Promise.resolve());
+
+  /**
+   * @param {!HTMLElement} testElement
+   * @return {!function(!Function)): !Promise}
+   */
+  const listenScope = testElement => wrapped => promiseSeries([
+    () => testElement.becomeActiveFindShortcutListener(),
+    wrapped,
+    () => testElement.removeSelfAsFindShortcutListener(),
+  ]);
+
+  /**
+   * @param {!Array<!HTMLElement>} expectedSelves
+   * @param {?boolean} expectedModalContextOpen
+   * @return {!Promise}
+   */
+  const checkMultiple = (expectedSelves, expectedModalContextOpen) => {
+    waits = expectedSelves.map(() => new PromiseResolver());
+    nextWait = 0;
+    MockInteractions.pressAndReleaseKeyOn(
+        window, 70, cr.isMac ? 'meta' : 'ctrl', 'f');
+    return Promise.all(waits.map(wait => wait.promise)).then(argss => {
+      argss.forEach((args, index) => {
+        assertEquals(expectedSelves[index], args.self);
+        assertEquals(!!expectedModalContextOpen, args.modalContextOpen);
+      });
+    });
+  };
+
+  /**
+   * @param {!HTMLElement} expectedSelf
+   * @param {?boolean} expectedModalContextOpen
+   * @return {!Promise}
+   */
+  const check = (expectedSelf, expectedModalContextOpen) =>
+      checkMultiple([expectedSelf], expectedModalContextOpen);
+
+  /**
+   * @param {!HTMLElement} expectedSelf
+   * @param {?boolean} expectedModalContextOpen
+   * @return {!Promise}
+   */
+  const wrappedCheck = (expectedSelf, expectedModalContextOpen) => listenScope(
+      expectedSelf)(() => check(expectedSelf, expectedModalContextOpen));
+
+  suiteSetup(() => {
+    document.body.innerHTML = `
+        <dom-module id="find-shortcut-element">
+          <template></template>
+        </dom-module>
+      `;
+
+    Polymer({
+      is: 'find-shortcut-element',
+      behaviors: [settings.FindShortcutBehavior],
+
+      handledResponse: true,
+
+      handleFindShortcut(modalContextOpen) {
+        assert(nextWait < waits.length);
+        waits[nextWait++].resolve({modalContextOpen, self: this});
+        return this.handledResponse;
+      },
+    });
+  });
+
+  setup(() => {
+    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');
+    return wrappedCheck(testElement);
+  });
+
+  test('handled with modal context open', () => {
+    document.body.innerHTML = `
+        <find-shortcut-element></find-shortcut-element>
+        <cr-dialog></cr-dialog>`;
+    const testElement = document.body.querySelector('find-shortcut-element');
+    const dialog = document.body.querySelector('cr-dialog');
+    dialog.showModal();
+    return wrappedCheck(testElement, true);
+  });
+
+  test('handled with modal context closed', () => {
+    document.body.innerHTML = `
+        <find-shortcut-element></find-shortcut-element>
+        <cr-dialog></cr-dialog>`;
+    const testElement = document.body.querySelector('find-shortcut-element');
+    const dialog = document.body.querySelector('cr-dialog');
+    dialog.showModal();
+    assertTrue(dialog.open);
+    const whenCloseFired = test_util.eventToPromise('close', dialog);
+    dialog.close();
+    return whenCloseFired.then(() => wrappedCheck(testElement));
+  });
+
+  test('last listener is active', () => {
+    document.body.innerHTML = `
+        <find-shortcut-element></find-shortcut-element>
+        <find-shortcut-element></find-shortcut-element>`;
+    const testElements =
+        document.body.querySelectorAll('find-shortcut-element');
+    return promiseSeries([
+      () => listenScope(testElements[0])(() => wrappedCheck(testElements[1])),
+      () => listenScope(testElements[1])(() => wrappedCheck(testElements[0])),
+    ]);
+  });
+
+  test('removing self when not active throws exception', () => {
+    document.body.innerHTML = `<find-shortcut-element></find-shortcut-element>`;
+    const testElement = document.body.querySelector('find-shortcut-element');
+    assertThrows(() => testElement.removeSelfAsFindShortcutListener());
+  });
+
+  test('becoming active when already active throws exception', () => {
+    document.body.innerHTML = `<find-shortcut-element></find-shortcut-element>`;
+    const testElement = document.body.querySelector('find-shortcut-element');
+    return listenScope(testElement)(() => {
+      assertThrows(() => testElement.becomeActiveFindShortcutListener());
+    });
+  });
+});
diff --git a/chrome/test/data/webui/settings/settings_ui_browsertest.js b/chrome/test/data/webui/settings/settings_ui_browsertest.js
index 700bc99..a2d17cd 100644
--- a/chrome/test/data/webui/settings/settings_ui_browsertest.js
+++ b/chrome/test/data/webui/settings/settings_ui_browsertest.js
@@ -166,21 +166,6 @@
       urlParams = settings.getQueryParameters();
       assertFalse(urlParams.has('search'));
     });
-
-    test('find shortcut', function() {
-      document.body.focus();
-      assertTrue(ui.canHandleFindShortcut());
-
-      ui.handleFindShortcut();
-      assertTrue(ui.$$('cr-toolbar').getSearchField().isSearchFocused());
-
-      const whenDialogOpen = test_util.eventToPromise('cr-dialog-open', ui);
-      settings.navigateTo(settings.routes.RESET_DIALOG);
-
-      return whenDialogOpen.then(function() {
-        assertFalse(ui.canHandleFindShortcut());
-      });
-    });
   });
 
   mocha.run();
diff --git a/chromecast/system/reboot/reboot_util.h b/chromecast/system/reboot/reboot_util.h
index 3f5179d..21dd79e5c 100644
--- a/chromecast/system/reboot/reboot_util.h
+++ b/chromecast/system/reboot/reboot_util.h
@@ -45,12 +45,14 @@
   static bool IsOtaForNextRebootSupported();
   static void SetOtaForNextReboot();
 
-  // These are used for logging/metrics purposes. In general, setting the last
+  // Returns last reboot source. This value persists throughout each boot.
+  static RebootShlib::RebootSource GetLastRebootSource();
+
+  // This is used for logging/metrics purposes. In general, setting the next
   // reboot type is handled automatically by RebootUtil, so it should not
   // be necessary to set explicitly.
-  static RebootShlib::RebootSource GetLastRebootSource();
   // Returns true if successful.
-  static bool SetLastRebootSource(RebootShlib::RebootSource reboot_source);
+  static bool SetNextRebootSource(RebootShlib::RebootSource reboot_source);
 
   using RebootCallback =
       base::RepeatingCallback<bool(RebootShlib::RebootSource)>;
diff --git a/chromecast/system/reboot/reboot_util_core.cc b/chromecast/system/reboot/reboot_util_core.cc
index c0aed49b..4d57445d 100644
--- a/chromecast/system/reboot/reboot_util_core.cc
+++ b/chromecast/system/reboot/reboot_util_core.cc
@@ -55,7 +55,7 @@
   // If we have a testing callback avoid calling RebootShlib::RebootNow
   // because it will crash our test
   RebootUtil::RebootCallback& callback = GetTestRebootCallback();
-  SetLastRebootSource(reboot_source);
+  SetNextRebootSource(reboot_source);
   if (callback) {
     LOG(WARNING) << "Using reboot callback for test! Device will not reboot!";
     return callback.Run(reboot_source);
diff --git a/chromecast/system/reboot/reboot_util_dummy.cc b/chromecast/system/reboot/reboot_util_dummy.cc
index b216f861..5de5adf 100644
--- a/chromecast/system/reboot/reboot_util_dummy.cc
+++ b/chromecast/system/reboot/reboot_util_dummy.cc
@@ -22,7 +22,7 @@
 }
 
 // static
-bool RebootUtil::SetLastRebootSource(
+bool RebootUtil::SetNextRebootSource(
     RebootShlib::RebootSource /* reboot_source */) {
   return false;
 }
diff --git a/chromecast/system/reboot/reboot_util_test.cc b/chromecast/system/reboot/reboot_util_test.cc
index 66045fe..7b02c79 100644
--- a/chromecast/system/reboot/reboot_util_test.cc
+++ b/chromecast/system/reboot/reboot_util_test.cc
@@ -9,30 +9,6 @@
 
 namespace chromecast {
 
-TEST(RebootUtil, SingleSetGetLastRebootSource) {
-  if (RebootUtil::SetLastRebootSource(RebootShlib::RebootSource::FORCED)) {
-    EXPECT_EQ(RebootUtil::GetLastRebootSource(),
-              RebootShlib::RebootSource::FORCED);
-  }
-}
-
-TEST(RebootUtil, MultipleSetGetLastRebootSource) {
-  if (RebootUtil::SetLastRebootSource(RebootShlib::RebootSource::FORCED)) {
-    EXPECT_EQ(RebootUtil::GetLastRebootSource(),
-              RebootShlib::RebootSource::FORCED);
-  }
-
-  if (RebootUtil::SetLastRebootSource(RebootShlib::RebootSource::OTA)) {
-    EXPECT_EQ(RebootUtil::GetLastRebootSource(),
-              RebootShlib::RebootSource::OTA);
-  }
-
-  if (RebootUtil::SetLastRebootSource(RebootShlib::RebootSource::FDR)) {
-    EXPECT_EQ(RebootUtil::GetLastRebootSource(),
-              RebootShlib::RebootSource::FDR);
-  }
-}
-
 // Ensure that we can call RebootNow during a test without crashing
 // and that it properly keeps track of the reboot source.
 TEST(RebootUtil, CaptureReboot) {
diff --git a/chromeos/components/nearby/BUILD.gn b/chromeos/components/nearby/BUILD.gn
index 07b777a..779b8d43 100644
--- a/chromeos/components/nearby/BUILD.gn
+++ b/chromeos/components/nearby/BUILD.gn
@@ -11,6 +11,8 @@
     "hash_utils_impl.cc",
     "hash_utils_impl.h",
     "settable_future_impl.h",
+    "system_clock_impl.cc",
+    "system_clock_impl.h",
     "thread_utils_impl.cc",
     "thread_utils_impl.h",
   ]
diff --git a/chromeos/components/nearby/library/BUILD.gn b/chromeos/components/nearby/library/BUILD.gn
index 367c8ed..3a96ebb1 100644
--- a/chromeos/components/nearby/library/BUILD.gn
+++ b/chromeos/components/nearby/library/BUILD.gn
@@ -12,6 +12,7 @@
     "future.h",
     "hash_utils.h",
     "settable_future.h",
+    "system_clock.h",
     "thread_utils.h",
   ]
 
diff --git a/chromeos/components/nearby/library/system_clock.h b/chromeos/components/nearby/library/system_clock.h
new file mode 100644
index 0000000..dd48d1fe
--- /dev/null
+++ b/chromeos/components/nearby/library/system_clock.h
@@ -0,0 +1,26 @@
+// Copyright (c) 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 CHROMEOS_COMPONENTS_NEARBY_LIBRARY_SYSTEM_CLOCK_H_
+#define CHROMEOS_COMPONENTS_NEARBY_LIBRARY_SYSTEM_CLOCK_H_
+
+#include <cstdint>
+
+namespace location {
+namespace nearby {
+
+class SystemClock {
+ public:
+  virtual ~SystemClock() {}
+
+  // Returns the time since the system was booted, and includes deep sleep. This
+  // clock should be guaranteed to be monotonic, and should continue to tick
+  // even when the CPU is in power saving modes.
+  virtual std::int64_t elapsedRealtime() = 0;
+};
+
+}  // namespace nearby
+}  // namespace location
+
+#endif  // CHROMEOS_COMPONENTS_NEARBY_LIBRARY_SYSTEM_CLOCK_H_
diff --git a/chromeos/components/nearby/system_clock_impl.cc b/chromeos/components/nearby/system_clock_impl.cc
new file mode 100644
index 0000000..db68c29
--- /dev/null
+++ b/chromeos/components/nearby/system_clock_impl.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 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 "chromeos/components/nearby/system_clock_impl.h"
+
+#include "base/sys_info.h"
+
+namespace chromeos {
+
+namespace nearby {
+
+SystemClockImpl::SystemClockImpl() = default;
+
+SystemClockImpl::~SystemClockImpl() = default;
+
+int64_t SystemClockImpl::elapsedRealtime() {
+  // TODO(kyleqian): The POSIX implementation of base::SysInfo::Uptime()
+  // currently does not include time spent suspended. See
+  // https://crbug.com/166153.
+  return base::SysInfo::Uptime().InMilliseconds();
+}
+
+}  // namespace nearby
+
+}  // namespace chromeos
diff --git a/chromeos/components/nearby/system_clock_impl.h b/chromeos/components/nearby/system_clock_impl.h
new file mode 100644
index 0000000..7f785c96e
--- /dev/null
+++ b/chromeos/components/nearby/system_clock_impl.h
@@ -0,0 +1,32 @@
+// Copyright (c) 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 CHROMEOS_COMPONENTS_NEARBY_SYSTEM_CLOCK_IMPL_H_
+#define CHROMEOS_COMPONENTS_NEARBY_SYSTEM_CLOCK_IMPL_H_
+
+#include "base/macros.h"
+#include "chromeos/components/nearby/library/system_clock.h"
+
+namespace chromeos {
+
+namespace nearby {
+
+// Concrete location::nearby::SystemClock implementation.
+class SystemClockImpl : public location::nearby::SystemClock {
+ public:
+  SystemClockImpl();
+  ~SystemClockImpl() override;
+
+ private:
+  // location::nearby::SystemClock:
+  int64_t elapsedRealtime() override;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemClockImpl);
+};
+
+}  // namespace nearby
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_NEARBY_SYSTEM_CLOCK_IMPL_H_
diff --git a/chromeos/dbus/fake_machine_learning_client.cc b/chromeos/dbus/fake_machine_learning_client.cc
index b4392e2..2996828 100644
--- a/chromeos/dbus/fake_machine_learning_client.cc
+++ b/chromeos/dbus/fake_machine_learning_client.cc
@@ -15,7 +15,7 @@
 void FakeMachineLearningClient::BootstrapMojoConnection(
     base::ScopedFD fd,
     base::OnceCallback<void(bool success)> result_callback) {
-  const bool success = false;
+  const bool success = true;
   std::move(result_callback).Run(success);
 }
 
diff --git a/chromeos/dbus/services/proxy_resolution_service_provider.cc b/chromeos/dbus/services/proxy_resolution_service_provider.cc
index c9bb074f..0b96b55 100644
--- a/chromeos/dbus/services/proxy_resolution_service_provider.cc
+++ b/chromeos/dbus/services/proxy_resolution_service_provider.cc
@@ -50,6 +50,9 @@
   // this request.
   const scoped_refptr<net::URLRequestContextGetter> context_getter;
 
+  // Handle to ProxyResolutionService's Request
+  std::unique_ptr<net::ProxyResolutionService::Request> request;
+
   // ProxyInfo resolved for |source_url|.
   net::ProxyInfo proxy_info;
 
@@ -160,7 +163,7 @@
           << request_ptr->source_url;
   const int result = proxy_resolution_service->ResolveProxy(
       GURL(request_ptr->source_url), std::string(), &request_ptr->proxy_info,
-      callback, nullptr, nullptr, net::NetLogWithSource());
+      callback, &request_ptr->request, nullptr, net::NetLogWithSource());
   if (result != net::ERR_IO_PENDING) {
     VLOG(1) << "Network proxy resolution completed synchronously.";
     callback.Run(result);
diff --git a/chromeos/services/BUILD.gn b/chromeos/services/BUILD.gn
index 047dc25..9e91de61 100644
--- a/chromeos/services/BUILD.gn
+++ b/chromeos/services/BUILD.gn
@@ -22,6 +22,7 @@
   testonly = true
   deps = [
     "//chromeos/services/device_sync:unit_tests",
+    "//chromeos/services/machine_learning/public/cpp:unit_tests",
     "//chromeos/services/multidevice_setup:unit_tests",
     "//chromeos/services/secure_channel:unit_tests",
   ]
diff --git a/chromeos/services/machine_learning/DEPS b/chromeos/services/machine_learning/DEPS
index b5a57d6..2e2e8d99 100644
--- a/chromeos/services/machine_learning/DEPS
+++ b/chromeos/services/machine_learning/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   "+chromeos/dbus",
+  "+mojo/core/embedder",
   "+mojo/public",
 ]
diff --git a/chromeos/services/machine_learning/public/cpp/BUILD.gn b/chromeos/services/machine_learning/public/cpp/BUILD.gn
index d714aa3..868c98e 100644
--- a/chromeos/services/machine_learning/public/cpp/BUILD.gn
+++ b/chromeos/services/machine_learning/public/cpp/BUILD.gn
@@ -15,3 +15,19 @@
     "//chromeos/services/machine_learning/public/mojom",
   ]
 }
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "service_connection_unittest.cc",
+  ]
+  deps = [
+    ":cpp",
+    "//base/test:test_support",
+    "//chromeos",
+    "//chromeos/services/machine_learning/public/mojom",
+    "//mojo/core/embedder",
+    "//mojo/public/cpp/bindings",
+    "//testing/gtest",
+  ]
+}
diff --git a/chromeos/services/machine_learning/public/cpp/service_connection.cc b/chromeos/services/machine_learning/public/cpp/service_connection.cc
index ed89eed8..3a2e604 100644
--- a/chromeos/services/machine_learning/public/cpp/service_connection.cc
+++ b/chromeos/services/machine_learning/public/cpp/service_connection.cc
@@ -7,7 +7,7 @@
 #include "base/no_destructor.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/machine_learning_client.h"
-#include "chromeos/services/machine_learning/public/mojom/interface.mojom.h"
+#include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
 #include "mojo/public/cpp/platform/platform_channel.h"
 #include "mojo/public/cpp/system/invitation.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
diff --git a/chromeos/services/machine_learning/public/cpp/service_connection.h b/chromeos/services/machine_learning/public/cpp/service_connection.h
index 6345ea9..da57df94 100644
--- a/chromeos/services/machine_learning/public/cpp/service_connection.h
+++ b/chromeos/services/machine_learning/public/cpp/service_connection.h
@@ -8,7 +8,7 @@
 #include "base/macros.h"
 #include "base/no_destructor.h"
 #include "base/sequence_checker.h"
-#include "chromeos/services/machine_learning/public/mojom/interface.mojom.h"
+#include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
 
 namespace chromeos {
 namespace machine_learning {
diff --git a/chromeos/services/machine_learning/public/cpp/service_connection_unittest.cc b/chromeos/services/machine_learning/public/cpp/service_connection_unittest.cc
new file mode 100644
index 0000000..7ed2d7d
--- /dev/null
+++ b/chromeos/services/machine_learning/public/cpp/service_connection_unittest.cc
@@ -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.
+
+#include "chromeos/services/machine_learning/public/cpp/service_connection.h"
+
+#include "base/macros.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom.h"
+#include "mojo/core/embedder/embedder.h"
+#include "mojo/core/embedder/scoped_ipc_support.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace machine_learning {
+namespace {
+
+class ServiceConnectionTest : public testing::Test {
+ public:
+  ServiceConnectionTest() = default;
+
+ protected:
+  static void SetUpTestCase() {
+    DBusThreadManager::Initialize();
+
+    static base::Thread ipc_thread("ipc");
+    ipc_thread.StartWithOptions(
+        base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
+    static mojo::core::ScopedIPCSupport ipc_support(
+        ipc_thread.task_runner(),
+        mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN);
+  }
+
+ private:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+  DISALLOW_COPY_AND_ASSIGN(ServiceConnectionTest);
+};
+
+// Tests that BindModelProvider runs OK (no crash) in a basic Mojo environment.
+TEST_F(ServiceConnectionTest, BindModelProvider) {
+  mojom::ModelProviderPtr model_provider;
+  ServiceConnection::GetInstance()->BindModelProvider(
+      mojo::MakeRequest(&model_provider));
+}
+
+}  // namespace
+}  // namespace machine_learning
+}  // namespace chromeos
diff --git a/chromeos/services/multidevice_setup/public/cpp/prefs.cc b/chromeos/services/multidevice_setup/public/cpp/prefs.cc
index a616ff2..341943ff 100644
--- a/chromeos/services/multidevice_setup/public/cpp/prefs.cc
+++ b/chromeos/services/multidevice_setup/public/cpp/prefs.cc
@@ -10,11 +10,27 @@
 
 namespace multidevice_setup {
 
-const char kMultiDeviceSuiteEnabledPrefName[] =
-    "multidevice_setup.enable_feature_suite";
+// Note that the pref names have slightly inconsistent naming conventions
+// because some were named before the unified MultiDeviceSetup project and we
+// wanted to avoid changing the internal names of existing prefs. The general
+// naming pattern for each individual feature enabling pref moving forward
+// should be of the form
+//     const char k[FeatureName]FeatureEnabledPrefName =
+//         "multidevice_setup.[feature_name]_enabled";
+
+// This pref is a gatekeeper for all MultiDevice features (e.g. Easy Unlock,
+// Instant Tethering). Setting the pref to 'true' is necessary but not
+// sufficient to enable the individual features, which are each controlled by
+// their own pref and may involve additional setup steps.
+const char kSuiteEnabledPrefName[] = "multidevice_setup.suite_enabled";
+
+// Individual feature prefs.
+const char kAndroidMessagesFeatureEnabledPrefName[] =
+    "multidevice.sms_connect_enabled";
 
 void RegisterFeaturePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterBooleanPref(kMultiDeviceSuiteEnabledPrefName, false);
+  registry->RegisterBooleanPref(kSuiteEnabledPrefName, false);
+  registry->RegisterBooleanPref(kAndroidMessagesFeatureEnabledPrefName, false);
 }
 
 }  // namespace multidevice_setup
diff --git a/chromeos/services/multidevice_setup/public/cpp/prefs.h b/chromeos/services/multidevice_setup/public/cpp/prefs.h
index 781e89cb..1d8ddfac 100644
--- a/chromeos/services/multidevice_setup/public/cpp/prefs.h
+++ b/chromeos/services/multidevice_setup/public/cpp/prefs.h
@@ -11,11 +11,8 @@
 
 namespace multidevice_setup {
 
-// This pref is a gatekeeper for all MultiDevice features (e.g. Easy Unlock,
-// Instant Tethering). Setting the pref to 'true' is necessary but not
-// sufficient to enable the individual features, which are each controlled by
-// their own pref and may involve additional setup steps.
-extern const char kMultiDeviceSuiteEnabledPrefName[];
+extern const char kSuiteEnabledPrefName[];
+extern const char kAndroidMessagesFeatureEnabledPrefName[];
 
 void RegisterFeaturePrefs(PrefRegistrySimple* registry);
 
diff --git a/components/arc/arc_prefs.cc b/components/arc/arc_prefs.cc
index 9e44f23..c96e15a0 100644
--- a/components/arc/arc_prefs.cc
+++ b/components/arc/arc_prefs.cc
@@ -89,9 +89,6 @@
 // Integer pref indicating the ecryptfs to ext4 migration strategy. One of
 // options: forbidden = 0, migrate = 1, wipe = 2 or ask the user = 3.
 const char kEcryptfsMigrationStrategy[] = "ecryptfs_migration_strategy";
-// A preference that indicates whether the SMS Connect feature is enabled.
-const char kSmsConnectEnabled[] = "multidevice.sms_connect_enabled";
-
 // A preference that indicates the user has accepted voice interaction activity
 // control settings.
 const char kVoiceInteractionActivityControlAccepted[] =
@@ -147,7 +144,6 @@
   registry->RegisterBooleanPref(kArcTermsAccepted, false);
   registry->RegisterBooleanPref(kArcTermsShownInOobe, false);
   registry->RegisterBooleanPref(kArcVoiceInteractionValuePropAccepted, false);
-  registry->RegisterBooleanPref(kSmsConnectEnabled, true);
   registry->RegisterBooleanPref(kVoiceInteractionContextEnabled, false);
   registry->RegisterBooleanPref(kVoiceInteractionEnabled, false);
   registry->RegisterBooleanPref(kVoiceInteractionHotwordEnabled, false);
diff --git a/components/arc/arc_prefs.h b/components/arc/arc_prefs.h
index 9a43759c..d7accf8 100644
--- a/components/arc/arc_prefs.h
+++ b/components/arc/arc_prefs.h
@@ -38,7 +38,6 @@
 ARC_EXPORT extern const char kArcCompatibleFilesystemChosen[];
 ARC_EXPORT extern const char kArcVoiceInteractionValuePropAccepted[];
 ARC_EXPORT extern const char kEcryptfsMigrationStrategy[];
-ARC_EXPORT extern const char kSmsConnectEnabled[];
 
 // TODO(b/110211045): Move Assistant related prefs to ash.
 ARC_EXPORT extern const char kVoiceInteractionActivityControlAccepted[];
diff --git a/components/arc/volume_mounter/arc_volume_mounter_bridge.cc b/components/arc/volume_mounter/arc_volume_mounter_bridge.cc
index fbaebba..d8148cb 100644
--- a/components/arc/volume_mounter/arc_volume_mounter_bridge.cc
+++ b/components/arc/volume_mounter/arc_volume_mounter_bridge.cc
@@ -77,38 +77,6 @@
                                 weak_ptr_factory_.GetWeakPtr()));
 }
 
-void ArcVolumeMounterBridge::OnAutoMountableDiskEvent(
-    chromeos::disks::DiskMountManager::DiskEvent event,
-    const chromeos::disks::DiskMountManager::Disk& disk) {
-  // Ignored. DiskEvents will be maintained in Vold during MountEvents.
-}
-
-void ArcVolumeMounterBridge::OnBootDeviceDiskEvent(
-    chromeos::disks::DiskMountManager::DiskEvent event,
-    const chromeos::disks::DiskMountManager::Disk& disk) {
-  // Ignored. ARC doesn't care about boot device disk events.
-}
-
-void ArcVolumeMounterBridge::OnDeviceEvent(
-    chromeos::disks::DiskMountManager::DeviceEvent event,
-    const std::string& device_path) {
-  // Ignored. ARC doesn't care about events other than Disk and Mount events.
-}
-
-void ArcVolumeMounterBridge::OnFormatEvent(
-    chromeos::disks::DiskMountManager::FormatEvent event,
-    chromeos::FormatError error_code,
-    const std::string& device_path) {
-  // Ignored. ARC doesn't care about events other than Disk and Mount events.
-}
-
-void ArcVolumeMounterBridge::OnRenameEvent(
-    chromeos::disks::DiskMountManager::RenameEvent event,
-    chromeos::RenameError error_code,
-    const std::string& device_path) {
-  // Ignored. ARC doesn't care about events other than Disk and Mount events.
-}
-
 void ArcVolumeMounterBridge::OnMountEvent(
     DiskMountManager::MountEvent event,
     chromeos::MountError error_code,
diff --git a/components/arc/volume_mounter/arc_volume_mounter_bridge.h b/components/arc/volume_mounter/arc_volume_mounter_bridge.h
index 654cefa..6da3adde 100644
--- a/components/arc/volume_mounter/arc_volume_mounter_bridge.h
+++ b/components/arc/volume_mounter/arc_volume_mounter_bridge.h
@@ -44,24 +44,10 @@
   void OnConnectionReady() override;
 
   // chromeos::disks::DiskMountManager::Observer overrides:
-  void OnAutoMountableDiskEvent(
-      chromeos::disks::DiskMountManager::DiskEvent event,
-      const chromeos::disks::DiskMountManager::Disk& disk) override;
-  void OnBootDeviceDiskEvent(
-      chromeos::disks::DiskMountManager::DiskEvent event,
-      const chromeos::disks::DiskMountManager::Disk& disk) override;
-  void OnDeviceEvent(chromeos::disks::DiskMountManager::DeviceEvent event,
-                     const std::string& device_path) override;
   void OnMountEvent(chromeos::disks::DiskMountManager::MountEvent event,
                     chromeos::MountError error_code,
                     const chromeos::disks::DiskMountManager::MountPointInfo&
                         mount_info) override;
-  void OnFormatEvent(chromeos::disks::DiskMountManager::FormatEvent event,
-                     chromeos::FormatError error_code,
-                     const std::string& device_path) override;
-  void OnRenameEvent(chromeos::disks::DiskMountManager::RenameEvent event,
-                     chromeos::RenameError error_code,
-                     const std::string& device_path) override;
 
   // mojom::VolumeMounterHost overrides:
   void RequestAllMountPoints() override;
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index 3d80a38..4237918 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -1151,10 +1151,6 @@
           driver->GetURLLoaderFactory(),
           client->GetPrefs(),
           client->GetIdentityManager(),
-          /*unmask_delegate=*/this,
-          // save_delegate starts out as nullptr and is set up by the
-          // CreditCardSaveManager owned by form_data_importer_.
-          /*save_delegate=*/nullptr,
           driver->IsIncognito())),
       app_locale_(app_locale),
       personal_data_(personal_data),
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h
index eda55e31..7733d20 100644
--- a/components/autofill/core/browser/autofill_manager.h
+++ b/components/autofill/core/browser/autofill_manager.h
@@ -71,7 +71,6 @@
 // forms. One per frame; owned by the AutofillDriver.
 class AutofillManager : public AutofillHandler,
                         public AutofillDownloadManager::Observer,
-                        public payments::PaymentsClientUnmaskDelegate,
                         public payments::FullCardRequest::ResultDelegate,
                         public payments::FullCardRequest::UIDelegate {
  public:
@@ -344,10 +343,10 @@
   void OnLoadedServerPredictions(
       std::string response,
       const std::vector<std::string>& form_signatures) override;
-
-  // payments::PaymentsClientUnmaskDelegate:
+  // Returns the real PAN retrieved from Payments. |real_pan| will be empty on
+  // failure.
   void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
-                       const std::string& real_pan) override;
+                       const std::string& real_pan);
 
   // payments::FullCardRequest::ResultDelegate:
   void OnFullCardRequestSucceeded(
diff --git a/components/autofill/core/browser/credit_card_save_manager.cc b/components/autofill/core/browser/credit_card_save_manager.cc
index 6c0d86a..838d343e 100644
--- a/components/autofill/core/browser/credit_card_save_manager.cc
+++ b/components/autofill/core/browser/credit_card_save_manager.cc
@@ -78,11 +78,7 @@
       payments_client_(payments_client),
       app_locale_(app_locale),
       personal_data_manager_(personal_data_manager),
-      weak_ptr_factory_(this) {
-  if (payments_client_) {
-    payments_client_->SetSaveDelegate(this);
-  }
-}
+      weak_ptr_factory_(this) {}
 
 CreditCardSaveManager::~CreditCardSaveManager() {}
 
@@ -104,7 +100,6 @@
   // Abort the uploading if |payments_client_| is nullptr.
   if (!payments_client_)
     return;
-  payments_client_->SetSaveDelegate(this);
   upload_request_ = payments::PaymentsClient::UploadRequestDetails();
   upload_request_.card = card;
   uploading_local_card_ = uploading_local_card;
@@ -183,7 +178,9 @@
       upload_request_.profiles, detected_values,
       base::UTF16ToASCII(CreditCard::StripSeparators(card.number()))
           .substr(0, 6),
-      upload_request_.active_experiments, app_locale_);
+      upload_request_.active_experiments, app_locale_,
+      base::BindOnce(&CreditCardSaveManager::OnDidGetUploadDetails,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 bool CreditCardSaveManager::IsCreditCardUploadEnabled() {
@@ -514,7 +511,9 @@
       uploading_local_card_
           ? AutofillMetrics::USER_ACCEPTED_UPLOAD_OF_LOCAL_CARD
           : AutofillMetrics::USER_ACCEPTED_UPLOAD_OF_NEW_CARD);
-  payments_client_->UploadCard(upload_request_);
+  payments_client_->UploadCard(
+      upload_request_, base::BindOnce(&CreditCardSaveManager::OnDidUploadCard,
+                                      weak_ptr_factory_.GetWeakPtr()));
 }
 
 AutofillMetrics::CardUploadDecisionMetric
diff --git a/components/autofill/core/browser/credit_card_save_manager.h b/components/autofill/core/browser/credit_card_save_manager.h
index d966e3f..93d721e 100644
--- a/components/autofill/core/browser/credit_card_save_manager.h
+++ b/components/autofill/core/browser/credit_card_save_manager.h
@@ -24,7 +24,7 @@
 // Manages logic for determining whether upload credit card save to Google
 // Payments is available as well as actioning both local and upload credit card
 // save logic.  Owned by FormDataImporter.
-class CreditCardSaveManager : public payments::PaymentsClientSaveDelegate {
+class CreditCardSaveManager {
  public:
   // Possible fields and values detected during credit card form submission, to
   // be sent to Google Payments to better determine if upload credit card save
@@ -100,19 +100,22 @@
   void SetAppLocale(std::string app_locale) { app_locale_ = app_locale; }
 
  protected:
-  // payments::PaymentsClientSaveDelegate:
-  // Exposed for testing.
-  void OnDidUploadCard(AutofillClient::PaymentsRpcResult result,
-                       const std::string& server_id) override;
+  // Returns the result of an upload request. If |result| ==
+  // |AutofillClient::SUCCESS|, |server_id| may, optionally, contain the opaque
+  // identifier for the card on the server. Exposed for testing.
+  virtual void OnDidUploadCard(AutofillClient::PaymentsRpcResult result,
+                               const std::string& server_id);
 
  private:
   friend class SaveCardBubbleViewsBrowserTestBase;
 
-  // payments::PaymentsClientSaveDelegate:
+  // Returns the legal message retrieved from Payments. On failure or not
+  // meeting Payments's conditions for upload, |legal_message| will contain
+  // nullptr.
   void OnDidGetUploadDetails(
       AutofillClient::PaymentsRpcResult result,
       const base::string16& context_token,
-      std::unique_ptr<base::DictionaryValue> legal_message) override;
+      std::unique_ptr<base::DictionaryValue> legal_message);
 
   // Examines |card| and the stored profiles and if a candidate set of profiles
   // is found that matches the client-side validation rules, assigns the values
diff --git a/components/autofill/core/browser/credit_card_save_manager_unittest.cc b/components/autofill/core/browser/credit_card_save_manager_unittest.cc
index 51bdb565..a22f131d 100644
--- a/components/autofill/core/browser/credit_card_save_manager_unittest.cc
+++ b/components/autofill/core/browser/credit_card_save_manager_unittest.cc
@@ -109,10 +109,7 @@
     autofill_driver_->SetURLRequestContext(request_context_.get());
     payments_client_ = new payments::TestPaymentsClient(
         autofill_driver_->GetURLLoaderFactory(), autofill_client_.GetPrefs(),
-        autofill_client_.GetIdentityManager(),
-        /*unmask_delegate=*/nullptr,
-        // Will be set by CreditCardSaveManager's ctor
-        /*save_delegate=*/nullptr);
+        autofill_client_.GetIdentityManager());
     credit_card_save_manager_ =
         new TestCreditCardSaveManager(autofill_driver_.get(), &autofill_client_,
                                       payments_client_, &personal_data_);
@@ -121,7 +118,6 @@
         std::unique_ptr<CreditCardSaveManager>(credit_card_save_manager_),
         payments_client_));
     autofill_manager_->SetExpectedObservedSubmission(true);
-    payments_client_->SetSaveDelegate(credit_card_save_manager_);
   }
 
   void TearDown() override {
diff --git a/components/autofill/core/browser/local_card_migration_manager.cc b/components/autofill/core/browser/local_card_migration_manager.cc
index eb0372e..c197aa5b 100644
--- a/components/autofill/core/browser/local_card_migration_manager.cc
+++ b/components/autofill/core/browser/local_card_migration_manager.cc
@@ -35,10 +35,7 @@
       payments_client_(payments_client),
       app_locale_(app_locale),
       personal_data_manager_(personal_data_manager),
-      weak_ptr_factory_(this) {
-  if (payments_client_)
-    payments_client_->SetSaveDelegate(this);
-}
+      weak_ptr_factory_(this) {}
 
 LocalCardMigrationManager::~LocalCardMigrationManager() {}
 
@@ -86,7 +83,6 @@
   // Abort the migration if |payments_client_| is nullptr.
   if (!payments_client_)
     return;
-  payments_client_->SetSaveDelegate(this);
   upload_request_ = payments::PaymentsClient::UploadRequestDetails();
 
   // Payments server determines which version of the legal message to show based
@@ -101,7 +97,9 @@
   payments_client_->GetUploadDetails(
       upload_request_.profiles, GetDetectedValues(),
       /*pan_first_six=*/std::string(), upload_request_.active_experiments,
-      app_locale_);
+      app_locale_,
+      base::BindOnce(&LocalCardMigrationManager::OnDidGetUploadDetails,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 // TODO(crbug.com/852904): Pops up a larger, modal dialog showing the local
@@ -148,10 +146,6 @@
   user_accepted_main_migration_dialog_ = true;
 }
 
-void LocalCardMigrationManager::OnDidUploadCard(
-    AutofillClient::PaymentsRpcResult result,
-    const std::string& server_id) {}
-
 int LocalCardMigrationManager::GetDetectedValues() const {
   int detected_values = 0;
 
diff --git a/components/autofill/core/browser/local_card_migration_manager.h b/components/autofill/core/browser/local_card_migration_manager.h
index 12c3a210..621e03e3 100644
--- a/components/autofill/core/browser/local_card_migration_manager.h
+++ b/components/autofill/core/browser/local_card_migration_manager.h
@@ -46,7 +46,7 @@
 // Manages logic for determining whether migration of locally saved credit cards
 // to Google Payments is available as well as multiple local card uploading.
 // Owned by FormDataImporter.
-class LocalCardMigrationManager : public payments::PaymentsClientSaveDelegate {
+class LocalCardMigrationManager {
  public:
   // The parameters should outlive the LocalCardMigrationManager.
   LocalCardMigrationManager(AutofillClient* client,
@@ -76,20 +76,13 @@
   int GetDetectedValues() const;
 
  protected:
-  // payments::PaymentsClientSaveDelegate:
   // Callback after successfully getting the legal documents. On success,
   // displays the offer-to-migrate dialog, which the user can accept or not.
-  void OnDidGetUploadDetails(
+  // Exposed for testing.
+  virtual void OnDidGetUploadDetails(
       AutofillClient::PaymentsRpcResult result,
       const base::string16& context_token,
-      std::unique_ptr<base::DictionaryValue> legal_message) override;
-
-  // payments::PaymentsClientSaveDelegate:
-  // Callback after a local card was uploaded. Starts the upload of the next
-  // local card if one exists.
-  // Exposed for testing.
-  void OnDidUploadCard(AutofillClient::PaymentsRpcResult result,
-                       const std::string& server_id) override;
+      std::unique_ptr<base::DictionaryValue> legal_message);
 
   // Check whether a local card is already a server card.
   bool IsServerCard(CreditCard* local_card) const;
diff --git a/components/autofill/core/browser/local_card_migration_manager_unittest.cc b/components/autofill/core/browser/local_card_migration_manager_unittest.cc
index cb6124b..08577ffc 100644
--- a/components/autofill/core/browser/local_card_migration_manager_unittest.cc
+++ b/components/autofill/core/browser/local_card_migration_manager_unittest.cc
@@ -68,9 +68,7 @@
     autofill_driver_->SetURLRequestContext(request_context_.get());
     payments_client_ = new payments::TestPaymentsClient(
         autofill_driver_->GetURLLoaderFactory(), autofill_client_.GetPrefs(),
-        autofill_client_.GetIdentityManager(),
-        /*unmask_delegate=*/nullptr,
-        /*save_delegate=*/nullptr);
+        autofill_client_.GetIdentityManager());
     credit_card_save_manager_ =
         new TestCreditCardSaveManager(autofill_driver_.get(), &autofill_client_,
                                       payments_client_, &personal_data_);
diff --git a/components/autofill/core/browser/payments/full_card_request.cc b/components/autofill/core/browser/payments/full_card_request.cc
index 9fab4b42..ba71e3c3 100644
--- a/components/autofill/core/browser/payments/full_card_request.cc
+++ b/components/autofill/core/browser/payments/full_card_request.cc
@@ -131,7 +131,9 @@
 
 void FullCardRequest::SendUnmaskCardRequest() {
   real_pan_request_timestamp_ = AutofillClock::Now();
-  payments_client_->UnmaskCard(*request_);
+  payments_client_->UnmaskCard(*request_,
+                               base::BindOnce(&FullCardRequest::OnDidGetRealPan,
+                                              weak_ptr_factory_.GetWeakPtr()));
 }
 
 void FullCardRequest::OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
diff --git a/components/autofill/core/browser/payments/full_card_request_unittest.cc b/components/autofill/core/browser/payments/full_card_request_unittest.cc
index 03d1b3e..284f113 100644
--- a/components/autofill/core/browser/payments/full_card_request_unittest.cc
+++ b/components/autofill/core/browser/payments/full_card_request_unittest.cc
@@ -66,8 +66,7 @@
 };
 
 // The test fixture for full card request.
-class FullCardRequestTest : public testing::Test,
-                            public PaymentsClientUnmaskDelegate {
+class FullCardRequestTest : public testing::Test {
  public:
   FullCardRequestTest()
       : request_context_(new net::TestURLRequestContextGetter(
@@ -82,7 +81,7 @@
     autofill_client_.SetPrefs(std::move(pref_service));
     payments_client_ = std::make_unique<PaymentsClient>(
         test_shared_loader_factory_, autofill_client_.GetPrefs(),
-        autofill_client_.GetIdentityManager(), this, nullptr);
+        autofill_client_.GetIdentityManager());
     request_ = std::make_unique<FullCardRequest>(
         &autofill_client_, payments_client_.get(), &personal_data_);
     // Silence the warning from PaymentsClient about matching sync and Payments
@@ -105,9 +104,8 @@
 
   MockUIDelegate* ui_delegate() { return &ui_delegate_; }
 
-  // PaymentsClientUnmaskDelegate:
   void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
-                       const std::string& real_pan) override {
+                       const std::string& real_pan) {
     request_->OnDidGetRealPan(result, real_pan);
   }
 
diff --git a/components/autofill/core/browser/payments/payments_client.cc b/components/autofill/core/browser/payments/payments_client.cc
index 6785c518..58cd6962 100644
--- a/components/autofill/core/browser/payments/payments_client.cc
+++ b/components/autofill/core/browser/payments/payments_client.cc
@@ -198,8 +198,9 @@
 class UnmaskCardRequest : public PaymentsRequest {
  public:
   UnmaskCardRequest(const PaymentsClient::UnmaskRequestDetails& request_details,
-                    PaymentsClientUnmaskDelegate* delegate)
-      : request_details_(request_details), delegate_(delegate) {
+                    base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                                            const std::string&)> callback)
+      : request_details_(request_details), callback_(std::move(callback)) {
     DCHECK(
         CreditCard::MASKED_SERVER_CARD == request_details.card.record_type() ||
         CreditCard::FULL_SERVER_CARD == request_details.card.record_type());
@@ -252,29 +253,34 @@
   bool IsResponseComplete() override { return !real_pan_.empty(); }
 
   void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override {
-    delegate_->OnDidGetRealPan(result, real_pan_);
+    std::move(callback_).Run(result, real_pan_);
   }
 
  private:
   PaymentsClient::UnmaskRequestDetails request_details_;
-  PaymentsClientUnmaskDelegate* delegate_;
+  base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                          const std::string&)>
+      callback_;
   std::string real_pan_;
 };
 
 class GetUploadDetailsRequest : public PaymentsRequest {
  public:
-  GetUploadDetailsRequest(const std::vector<AutofillProfile>& addresses,
-                          const int detected_values,
-                          const std::string& pan_first_six,
-                          const std::vector<const char*>& active_experiments,
-                          const std::string& app_locale,
-                          PaymentsClientSaveDelegate* delegate)
+  GetUploadDetailsRequest(
+      const std::vector<AutofillProfile>& addresses,
+      const int detected_values,
+      const std::string& pan_first_six,
+      const std::vector<const char*>& active_experiments,
+      const std::string& app_locale,
+      base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                              const base::string16&,
+                              std::unique_ptr<base::DictionaryValue>)> callback)
       : addresses_(addresses),
         detected_values_(detected_values),
         pan_first_six_(pan_first_six),
         active_experiments_(active_experiments),
         app_locale_(app_locale),
-        delegate_(delegate) {}
+        callback_(std::move(callback)) {}
   ~GetUploadDetailsRequest() override {}
 
   std::string GetRequestUrlPath() override {
@@ -331,8 +337,7 @@
   }
 
   void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override {
-    delegate_->OnDidGetUploadDetails(result, context_token_,
-                                     std::move(legal_message_));
+    std::move(callback_).Run(result, context_token_, std::move(legal_message_));
   }
 
  private:
@@ -341,7 +346,10 @@
   const std::string pan_first_six_;
   const std::vector<const char*> active_experiments_;
   std::string app_locale_;
-  PaymentsClientSaveDelegate* delegate_;
+  base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                          const base::string16&,
+                          std::unique_ptr<base::DictionaryValue>)>
+      callback_;
   base::string16 context_token_;
   std::unique_ptr<base::DictionaryValue> legal_message_;
 };
@@ -349,8 +357,9 @@
 class UploadCardRequest : public PaymentsRequest {
  public:
   UploadCardRequest(const PaymentsClient::UploadRequestDetails& request_details,
-                    PaymentsClientSaveDelegate* delegate)
-      : request_details_(request_details), delegate_(delegate) {}
+                    base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                                            const std::string&)> callback)
+      : request_details_(request_details), callback_(std::move(callback)) {}
   ~UploadCardRequest() override {}
 
   std::string GetRequestUrlPath() override { return kUploadCardRequestPath; }
@@ -431,12 +440,14 @@
   bool IsResponseComplete() override { return true; }
 
   void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override {
-    delegate_->OnDidUploadCard(result, server_id_);
+    std::move(callback_).Run(result, server_id_);
   }
 
  private:
   const PaymentsClient::UploadRequestDetails request_details_;
-  PaymentsClientSaveDelegate* delegate_;
+  base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                          const std::string&)>
+      callback_;
   std::string server_id_;
 };
 
@@ -459,14 +470,10 @@
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     PrefService* pref_service,
     identity::IdentityManager* identity_manager,
-    PaymentsClientUnmaskDelegate* unmask_delegate,
-    PaymentsClientSaveDelegate* save_delegate,
     bool is_off_the_record)
     : url_loader_factory_(url_loader_factory),
       pref_service_(pref_service),
       identity_manager_(identity_manager),
-      unmask_delegate_(unmask_delegate),
-      save_delegate_(save_delegate),
       is_off_the_record_(is_off_the_record),
       has_retried_authorization_(false),
       weak_ptr_factory_(this) {}
@@ -478,20 +485,16 @@
     StartTokenFetch(false);
 }
 
-void PaymentsClient::SetSaveDelegate(
-    PaymentsClientSaveDelegate* save_delegate) {
-  save_delegate_ = save_delegate;
-}
-
 PrefService* PaymentsClient::GetPrefService() const {
   return pref_service_;
 }
 
 void PaymentsClient::UnmaskCard(
-    const PaymentsClient::UnmaskRequestDetails& request_details) {
-  DCHECK(unmask_delegate_);
+    const PaymentsClient::UnmaskRequestDetails& request_details,
+    base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                            const std::string&)> callback) {
   IssueRequest(
-      std::make_unique<UnmaskCardRequest>(request_details, unmask_delegate_),
+      std::make_unique<UnmaskCardRequest>(request_details, std::move(callback)),
       true);
 }
 
@@ -500,19 +503,22 @@
     const int detected_values,
     const std::string& pan_first_six,
     const std::vector<const char*>& active_experiments,
-    const std::string& app_locale) {
-  DCHECK(save_delegate_);
+    const std::string& app_locale,
+    base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                            const base::string16&,
+                            std::unique_ptr<base::DictionaryValue>)> callback) {
   IssueRequest(std::make_unique<GetUploadDetailsRequest>(
                    addresses, detected_values, pan_first_six,
-                   active_experiments, app_locale, save_delegate_),
+                   active_experiments, app_locale, std::move(callback)),
                false);
 }
 
 void PaymentsClient::UploadCard(
-    const PaymentsClient::UploadRequestDetails& request_details) {
-  DCHECK(save_delegate_);
+    const PaymentsClient::UploadRequestDetails& request_details,
+    base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                            const std::string&)> callback) {
   IssueRequest(
-      std::make_unique<UploadCardRequest>(request_details, save_delegate_),
+      std::make_unique<UploadCardRequest>(request_details, std::move(callback)),
       true);
 }
 
diff --git a/components/autofill/core/browser/payments/payments_client.h b/components/autofill/core/browser/payments/payments_client.h
index e8eef9d9..ca740d4 100644
--- a/components/autofill/core/browser/payments/payments_client.h
+++ b/components/autofill/core/browser/payments/payments_client.h
@@ -34,31 +34,6 @@
 
 class PaymentsRequest;
 
-class PaymentsClientUnmaskDelegate {
- public:
-  // Returns the real PAN retrieved from Payments. |real_pan| will be empty
-  // on failure.
-  virtual void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
-                               const std::string& real_pan) = 0;
-};
-
-class PaymentsClientSaveDelegate {
- public:
-  // Returns the legal message retrieved from Payments. On failure or not
-  // meeting Payments's conditions for upload, |legal_message| will contain
-  // nullptr.
-  virtual void OnDidGetUploadDetails(
-      AutofillClient::PaymentsRpcResult result,
-      const base::string16& context_token,
-      std::unique_ptr<base::DictionaryValue> legal_message) = 0;
-
-  // Returns the result of an upload request.
-  // If |result| == |AutofillClient::SUCCESS|, |server_id| may, optionally,
-  // contain the opaque identifier for the card on the server.
-  virtual void OnDidUploadCard(AutofillClient::PaymentsRpcResult result,
-                               const std::string& server_id) = 0;
-};
-
 // PaymentsClient issues Payments RPCs and manages responses and failure
 // conditions. Only one request may be active at a time. Initiating a new
 // request will cancel a pending request.
@@ -111,8 +86,6 @@
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       PrefService* pref_service,
       identity::IdentityManager* identity_manager,
-      PaymentsClientUnmaskDelegate* unmask_delegate,
-      PaymentsClientSaveDelegate* save_delegate,
       bool is_off_the_record = false);
 
   virtual ~PaymentsClient();
@@ -124,15 +97,12 @@
   // accepted an upload prompt.
   void Prepare();
 
-  // Sets up the |save_delegate_|. Necessary because CreditCardSaveManager
-  // requires PaymentsClient during initialization, so PaymentsClient can't
-  // start with save_delegate_ initialized.
-  virtual void SetSaveDelegate(PaymentsClientSaveDelegate* save_delegate);
-
   PrefService* GetPrefService() const;
 
   // The user has attempted to unmask a card with the given cvc.
-  void UnmaskCard(const UnmaskRequestDetails& request_details);
+  void UnmaskCard(const UnmaskRequestDetails& request_details,
+                  base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                                          const std::string&)> callback);
 
   // Determine if the user meets the Payments service's conditions for upload.
   // The service uses |addresses| (from which names and phone numbers are
@@ -141,20 +111,28 @@
   // being considered for upload. |detected_values| is a bitmask of
   // CreditCardSaveManager::DetectedValue values that relays what data is
   // actually available for upload in order to make more informed upload
-  // decisions. If the conditions are met, the legal message will be returned
-  // via OnDidGetUploadDetails. |active_experiments| is used by Payments server
-  // to track requests that were triggered by enabled features.
+  // decisions. |callback| is the callback function when get response from
+  // server. If the conditions are met, the legal message will be returned via
+  // |callback|. |active_experiments| is used by Payments server to track
+  // requests that were triggered by enabled features.
   virtual void GetUploadDetails(
       const std::vector<AutofillProfile>& addresses,
       const int detected_values,
       const std::string& pan_first_six,
       const std::vector<const char*>& active_experiments,
-      const std::string& app_locale);
+      const std::string& app_locale,
+      base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                              const base::string16&,
+                              std::unique_ptr<base::DictionaryValue>)>
+          callback);
 
   // The user has indicated that they would like to upload a card with the given
   // cvc. This request will fail server-side if a successful call to
   // GetUploadDetails has not already been made.
-  virtual void UploadCard(const UploadRequestDetails& details);
+  virtual void UploadCard(
+      const UploadRequestDetails& details,
+      base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                              const std::string&)> callback);
 
   // Cancels and clears the current |request_|.
   void CancelRequest();
@@ -204,11 +182,6 @@
 
   identity::IdentityManager* const identity_manager_;
 
-  // Delegates for the results of the various requests to Payments. Both must
-  // outlive |this|.
-  PaymentsClientUnmaskDelegate* const unmask_delegate_;
-  PaymentsClientSaveDelegate* save_delegate_;
-
   // The current request.
   std::unique_ptr<PaymentsRequest> request_;
 
diff --git a/components/autofill/core/browser/payments/payments_client_unittest.cc b/components/autofill/core/browser/payments/payments_client_unittest.cc
index 2d2027d..1250d7f 100644
--- a/components/autofill/core/browser/payments/payments_client_unittest.cc
+++ b/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -48,11 +48,10 @@
 
 }  // namespace
 
-class PaymentsClientTest : public testing::Test,
-                           public PaymentsClientUnmaskDelegate,
-                           public PaymentsClientSaveDelegate {
+class PaymentsClientTest : public testing::Test {
  public:
-  PaymentsClientTest() : result_(AutofillClient::NONE) {}
+  PaymentsClientTest()
+      : result_(AutofillClient::NONE), weak_ptr_factory_(this) {}
   ~PaymentsClientTest() override {}
 
   void SetUp() override {
@@ -74,9 +73,9 @@
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
             &test_url_loader_factory_);
     TestingPrefServiceSimple pref_service_;
-    client_.reset(
-        new PaymentsClient(test_shared_loader_factory_, &pref_service_,
-                           identity_test_env_.identity_manager(), this, this));
+    client_.reset(new PaymentsClient(test_shared_loader_factory_,
+                                     &pref_service_,
+                                     identity_test_env_.identity_manager()));
   }
 
   void TearDown() override { client_.reset(); }
@@ -101,23 +100,22 @@
     base::FieldTrialList::CreateFieldTrial(trial_name, group_name)->group();
   }
 
-  // PaymentsClientUnmaskDelegate:
   void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
-                       const std::string& real_pan) override {
+                       const std::string& real_pan) {
     result_ = result;
     real_pan_ = real_pan;
   }
 
-  // PaymentsClientSaveDelegate:
   void OnDidGetUploadDetails(
       AutofillClient::PaymentsRpcResult result,
       const base::string16& context_token,
-      std::unique_ptr<base::DictionaryValue> legal_message) override {
+      std::unique_ptr<base::DictionaryValue> legal_message) {
     result_ = result;
     legal_message_ = std::move(legal_message);
   }
+
   void OnDidUploadCard(AutofillClient::PaymentsRpcResult result,
-                       const std::string& server_id) override {
+                       const std::string& server_id) {
     result_ = result;
     server_id_ = server_id;
   }
@@ -134,16 +132,21 @@
     request_details.card = test::GetMaskedServerCard();
     request_details.user_response.cvc = base::ASCIIToUTF16("123");
     request_details.risk_data = "some risk data";
-    client_->UnmaskCard(request_details);
+    client_->UnmaskCard(request_details,
+                        base::BindOnce(&PaymentsClientTest::OnDidGetRealPan,
+                                       weak_ptr_factory_.GetWeakPtr()));
   }
 
   void StartGettingUploadDetails() {
     if (!identity_test_env_.identity_manager()->HasPrimaryAccount())
       identity_test_env_.MakePrimaryAccountAvailable("example@gmail.com");
 
-    client_->GetUploadDetails(BuildTestProfiles(), kAllDetectableValues,
-                              /*pan_first_six=*/"411111",
-                              std::vector<const char*>(), "language-LOCALE");
+    client_->GetUploadDetails(
+        BuildTestProfiles(), kAllDetectableValues,
+        /*pan_first_six=*/"411111", std::vector<const char*>(),
+        "language-LOCALE",
+        base::BindOnce(&PaymentsClientTest::OnDidGetUploadDetails,
+                       weak_ptr_factory_.GetWeakPtr()));
   }
 
   void StartUploading(bool include_cvc) {
@@ -159,7 +162,9 @@
     request_details.risk_data = "some risk data";
     request_details.app_locale = "language-LOCALE";
     request_details.profiles = BuildTestProfiles();
-    client_->UploadCard(request_details);
+    client_->UploadCard(request_details,
+                        base::BindOnce(&PaymentsClientTest::OnDidUploadCard,
+                                       weak_ptr_factory_.GetWeakPtr()));
   }
 
   network::TestURLLoaderFactory* factory() { return &test_url_loader_factory_; }
@@ -199,6 +204,7 @@
 
   net::HttpRequestHeaders intercepted_headers_;
   std::string intercepted_body_;
+  base::WeakPtrFactory<PaymentsClientTest> weak_ptr_factory_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(PaymentsClientTest);
diff --git a/components/autofill/core/browser/payments/test_payments_client.cc b/components/autofill/core/browser/payments/test_payments_client.cc
index 1048649..c42daa5 100644
--- a/components/autofill/core/browser/payments/test_payments_client.cc
+++ b/components/autofill/core/browser/payments/test_payments_client.cc
@@ -13,15 +13,8 @@
 TestPaymentsClient::TestPaymentsClient(
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_,
     PrefService* pref_service,
-    identity::IdentityManager* identity_manager,
-    payments::PaymentsClientUnmaskDelegate* unmask_delegate,
-    payments::PaymentsClientSaveDelegate* save_delegate)
-    : PaymentsClient(url_loader_factory_,
-                     pref_service,
-                     identity_manager,
-                     unmask_delegate,
-                     save_delegate),
-      save_delegate_(save_delegate) {}
+    identity::IdentityManager* identity_manager)
+    : PaymentsClient(url_loader_factory_, pref_service, identity_manager) {}
 
 TestPaymentsClient::~TestPaymentsClient() {}
 
@@ -30,28 +23,27 @@
     const int detected_values,
     const std::string& pan_first_six,
     const std::vector<const char*>& active_experiments,
-    const std::string& app_locale) {
+    const std::string& app_locale,
+    base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                            const base::string16&,
+                            std::unique_ptr<base::DictionaryValue>)> callback) {
   upload_details_addresses_ = addresses;
   detected_values_ = detected_values;
   pan_first_six_ = pan_first_six;
   active_experiments_ = active_experiments;
-  save_delegate_->OnDidGetUploadDetails(
-      app_locale == "en-US" ? AutofillClient::SUCCESS
-                            : AutofillClient::PERMANENT_FAILURE,
-      base::ASCIIToUTF16("this is a context token"),
-      std::unique_ptr<base::DictionaryValue>(nullptr));
+  std::move(callback).Run(app_locale == "en-US"
+                              ? AutofillClient::SUCCESS
+                              : AutofillClient::PERMANENT_FAILURE,
+                          base::ASCIIToUTF16("this is a context token"),
+                          std::unique_ptr<base::DictionaryValue>(nullptr));
 }
 
 void TestPaymentsClient::UploadCard(
-    const payments::PaymentsClient::UploadRequestDetails& request_details) {
+    const payments::PaymentsClient::UploadRequestDetails& request_details,
+    base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                            const std::string&)> callback) {
   active_experiments_ = request_details.active_experiments;
-  save_delegate_->OnDidUploadCard(AutofillClient::SUCCESS, server_id_);
-}
-
-void TestPaymentsClient::SetSaveDelegate(
-    payments::PaymentsClientSaveDelegate* save_delegate) {
-  save_delegate_ = save_delegate;
-  payments::PaymentsClient::SetSaveDelegate(save_delegate);
+  std::move(callback).Run(AutofillClient::SUCCESS, server_id_);
 }
 
 void TestPaymentsClient::SetServerIdForCardUpload(std::string server_id) {
diff --git a/components/autofill/core/browser/payments/test_payments_client.h b/components/autofill/core/browser/payments/test_payments_client.h
index 13d24e0..b4394e93 100644
--- a/components/autofill/core/browser/payments/test_payments_client.h
+++ b/components/autofill/core/browser/payments/test_payments_client.h
@@ -22,23 +22,25 @@
   TestPaymentsClient(
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_,
       PrefService* pref_service,
-      identity::IdentityManager* identity_manager,
-      payments::PaymentsClientUnmaskDelegate* unmask_delegate,
-      payments::PaymentsClientSaveDelegate* save_delegate);
+      identity::IdentityManager* identity_manager);
 
   ~TestPaymentsClient() override;
 
-  void GetUploadDetails(const std::vector<AutofillProfile>& addresses,
-                        const int detected_values,
-                        const std::string& pan_first_six,
-                        const std::vector<const char*>& active_experiments,
-                        const std::string& app_locale) override;
+  void GetUploadDetails(
+      const std::vector<AutofillProfile>& addresses,
+      const int detected_values,
+      const std::string& pan_first_six,
+      const std::vector<const char*>& active_experiments,
+      const std::string& app_locale,
+      base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                              const base::string16&,
+                              std::unique_ptr<base::DictionaryValue>)> callback)
+      override;
 
-  void UploadCard(const payments::PaymentsClient::UploadRequestDetails&
-                      request_details) override;
-
-  void SetSaveDelegate(
-      payments::PaymentsClientSaveDelegate* save_delegate) override;
+  void UploadCard(
+      const payments::PaymentsClient::UploadRequestDetails& request_details,
+      base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                              const std::string&)> callback) override;
 
   void SetServerIdForCardUpload(std::string);
 
@@ -52,7 +54,6 @@
   }
 
  private:
-  payments::PaymentsClientSaveDelegate* save_delegate_;
   std::string server_id_;
   std::vector<AutofillProfile> upload_details_addresses_;
   int detected_values_;
diff --git a/components/autofill/core/browser/test_autofill_manager.cc b/components/autofill/core/browser/test_autofill_manager.cc
index dfbe4a7..51f1574b 100644
--- a/components/autofill/core/browser/test_autofill_manager.cc
+++ b/components/autofill/core/browser/test_autofill_manager.cc
@@ -25,9 +25,7 @@
       url_loader_factory_(driver->GetURLLoaderFactory()),
       client_(client) {
   set_payments_client(new payments::PaymentsClient(
-      url_loader_factory_, client->GetPrefs(), client->GetIdentityManager(),
-      /*unmask_delegate=*/this,
-      /*save_delegate=*/nullptr));
+      url_loader_factory_, client->GetPrefs(), client->GetIdentityManager()));
 }
 
 TestAutofillManager::TestAutofillManager(
diff --git a/components/autofill/core/browser/test_credit_card_save_manager.cc b/components/autofill/core/browser/test_credit_card_save_manager.cc
index c06d9507a..ab8a640 100644
--- a/components/autofill/core/browser/test_credit_card_save_manager.cc
+++ b/components/autofill/core/browser/test_credit_card_save_manager.cc
@@ -16,12 +16,7 @@
     : CreditCardSaveManager(client,
                             payments_client,
                             "en-US",
-                            personal_data_manager),
-      test_payments_client_(payments_client) {
-  if (test_payments_client_) {
-    test_payments_client_->SetSaveDelegate(this);
-  }
-}
+                            personal_data_manager) {}
 
 TestCreditCardSaveManager::~TestCreditCardSaveManager() {}
 
diff --git a/components/autofill/core/browser/test_credit_card_save_manager.h b/components/autofill/core/browser/test_credit_card_save_manager.h
index b00211b..cc157fc 100644
--- a/components/autofill/core/browser/test_credit_card_save_manager.h
+++ b/components/autofill/core/browser/test_credit_card_save_manager.h
@@ -38,7 +38,6 @@
   void OnDidUploadCard(AutofillClient::PaymentsRpcResult result,
                        const std::string& server_id) override;
 
-  payments::TestPaymentsClient* test_payments_client_;  // Weak reference.
   bool credit_card_upload_enabled_ = false;
   bool credit_card_was_uploaded_ = false;
 
diff --git a/components/autofill/core/browser/test_local_card_migration_manager.cc b/components/autofill/core/browser/test_local_card_migration_manager.cc
index 9ef4888..6a573a7 100644
--- a/components/autofill/core/browser/test_local_card_migration_manager.cc
+++ b/components/autofill/core/browser/test_local_card_migration_manager.cc
@@ -19,11 +19,7 @@
     : LocalCardMigrationManager(client,
                                 payments_client,
                                 "en-US",
-                                personal_data_manager),
-      test_payments_client_(payments_client) {
-  if (test_payments_client_)
-    test_payments_client_->SetSaveDelegate(this);
-}
+                                personal_data_manager) {}
 
 TestLocalCardMigrationManager::~TestLocalCardMigrationManager() {}
 
diff --git a/components/autofill/core/browser/test_local_card_migration_manager.h b/components/autofill/core/browser/test_local_card_migration_manager.h
index 07041a9d..6cb5cc6 100644
--- a/components/autofill/core/browser/test_local_card_migration_manager.h
+++ b/components/autofill/core/browser/test_local_card_migration_manager.h
@@ -41,7 +41,6 @@
       const base::string16& context_token,
       std::unique_ptr<base::DictionaryValue> legal_message) override;
 
-  payments::TestPaymentsClient* test_payments_client_;  // Weak reference.
   bool local_card_migration_was_triggered_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(TestLocalCardMigrationManager);
diff --git a/components/chrome_cleaner/public/constants/result_codes.h b/components/chrome_cleaner/public/constants/result_codes.h
index 09e1f86..ff41456 100644
--- a/components/chrome_cleaner/public/constants/result_codes.h
+++ b/components/chrome_cleaner/public/constants/result_codes.h
@@ -214,6 +214,10 @@
   // Some of the scanning configuration switches have invalid values.
   RESULT_CODE_INVALID_SCANNING_SWITCHES = 53,
 
+  // The target process for the JSON parser sandbox disconnected from the IPC
+  // while the pipe was still needed by the broker process.
+  RESULT_CODE_JSON_PARSER_SANDBOX_DISCONNECTED_TOO_SOON = 54,
+
   // WHEN YOU ADD NEW EXIT CODES, DON'T FORGET TO UPDATE THE MONITORING RULES.
   // See http://go/chrome-cleaner-exit-codes. (Google internal only - external
   // contributors please ask one of the OWNERS to do the update.)
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
index dd49dcc..cc04aa6 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
@@ -18,6 +18,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
 #include "components/data_reduction_proxy/core/browser/data_usage_store.h"
@@ -1398,6 +1399,12 @@
 
 void DataReductionProxyCompressionStats::InitializeWeeklyAggregateDataUse(
     const base::Time& now) {
+#if defined(OS_ANDROID) && defined(ARCH_CPU_X86)
+  // TODO(rajendrant): Enable aggregate metrics recording in x86 Android.
+  // http://crbug.com/865373
+  return;
+#endif
+
   MaybeInitWeeklyAggregateDataUsePrefs(now, pref_service_);
   // Record the histograms that will show up in the user feedback.
   RecordDictionaryToHistogram(
@@ -1434,6 +1441,11 @@
     bool is_user_request,
     data_use_measurement::DataUseUserData::DataUseContentType content_type,
     int32_t service_hash_code) {
+#if defined(OS_ANDROID) && defined(ARCH_CPU_X86)
+  // TODO(rajendrant): Enable aggregate metrics recording in x86 Android.
+  // http://crbug.com/865373
+  return;
+#endif
   // Update the prefs if this is a new week. This can happen when chrome is open
   // for weeks without being closed.
   MaybeInitWeeklyAggregateDataUsePrefs(now, pref_service_);
diff --git a/components/feed/core/feed_networking_host.cc b/components/feed/core/feed_networking_host.cc
index cd94af0..e40bc2d 100644
--- a/components/feed/core/feed_networking_host.cc
+++ b/components/feed/core/feed_networking_host.cc
@@ -8,6 +8,7 @@
 
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "components/variations/net/variations_http_headers.h"
 #include "google_apis/gaia/google_service_auth_error.h"
@@ -31,6 +32,8 @@
 constexpr char kApiKeyQueryParam[] = "key";
 constexpr char kAuthenticationScope[] =
     "https://www.googleapis.com/auth/googlenow";
+constexpr char kAuthorizationRequestHeaderFormat[] = "Bearer %s";
+
 constexpr char kContentEncoding[] = "Content-Encoding";
 constexpr char kContentType[] = "application/octet-stream";
 constexpr char kGzip[] = "gzip";
@@ -59,15 +62,15 @@
   void StartAccessTokenFetch();
   void AccessTokenFetchFinished(GoogleServiceAuthError error,
                                 identity::AccessTokenInfo access_token_info);
-  void StartLoader(const std::string& access_token);
-  std::unique_ptr<network::SimpleURLLoader> MakeLoader(
-      const std::string& access_token);
+  void StartLoader();
+  std::unique_ptr<network::SimpleURLLoader> MakeLoader();
   net::HttpRequestHeaders MakeHeaders(const std::string& auth_header) const;
   void PopulateRequestBody(network::SimpleURLLoader* loader);
   void OnSimpleLoaderComplete(std::unique_ptr<std::string> response);
 
   const GURL url_;
   const std::string request_type_;
+  std::string access_token_;
   const std::vector<uint8_t> request_body_;
   IdentityManager* const identity_manager_;
   std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher> token_fetcher_;
@@ -96,7 +99,7 @@
   done_callback_ = std::move(done_callback);
 
   if (!identity_manager_->HasPrimaryAccount()) {
-    StartLoader(std::string());
+    StartLoader();
     return;
   }
 
@@ -119,19 +122,24 @@
     identity::AccessTokenInfo access_token_info) {
   UMA_HISTOGRAM_ENUMERATION("ContentSuggestions.Feed.TokenFetchStatus",
                             error.state(), GoogleServiceAuthError::NUM_STATES);
-  StartLoader(access_token_info.token);
+  access_token_ = access_token_info.token;
+  StartLoader();
 }
 
-void NetworkFetch::StartLoader(const std::string& access_token) {
-  simple_loader_ = MakeLoader(access_token);
+void NetworkFetch::StartLoader() {
+  simple_loader_ = MakeLoader();
   simple_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
       loader_factory_, base::BindOnce(&NetworkFetch::OnSimpleLoaderComplete,
                                       base::Unretained(this)));
 }
 
-std::unique_ptr<network::SimpleURLLoader> NetworkFetch::MakeLoader(
-    const std::string& access_token) {
-  net::HttpRequestHeaders headers = MakeHeaders(access_token);
+std::unique_ptr<network::SimpleURLLoader> NetworkFetch::MakeLoader() {
+  std::string auth_header =
+      access_token_.empty()
+          ? std::string()
+          : base::StringPrintf(kAuthorizationRequestHeaderFormat,
+                               access_token_.c_str());
+  net::HttpRequestHeaders headers = MakeHeaders(auth_header);
   // TODO(pnoland): Add data use measurement once it's supported for simple
   // url loader.
   net::NetworkTrafficAnnotationTag traffic_annotation =
@@ -160,7 +168,7 @@
           }
         })");
   GURL url(url_);
-  if (access_token.empty() && !api_key_.empty())
+  if (access_token_.empty() && !api_key_.empty())
     url = net::AppendQueryParameter(url_, kApiKeyQueryParam, api_key_);
 
   auto resource_request = std::make_unique<network::ResourceRequest>();
@@ -223,6 +231,14 @@
   if (response) {
     status_code = simple_loader_->ResponseInfo()->headers->response_code();
 
+    if (status_code == net::HTTP_UNAUTHORIZED) {
+      OAuth2TokenService::ScopeSet scopes{kAuthenticationScope};
+      std::string account_id =
+          identity_manager_->GetPrimaryAccountInfo().account_id;
+      identity_manager_->RemoveAccessTokenFromCache(account_id, scopes,
+                                                    access_token_);
+    }
+
     const uint8_t* begin = reinterpret_cast<const uint8_t*>(response->data());
     const uint8_t* end = begin + response->size();
     response_body.assign(begin, end);
diff --git a/components/feed/core/feed_networking_host_unittest.cc b/components/feed/core/feed_networking_host_unittest.cc
index 5c51361..27d7364 100644
--- a/components/feed/core/feed_networking_host_unittest.cc
+++ b/components/feed/core/feed_networking_host_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/test_mock_time_task_runner.h"
 #include "net/http/http_response_headers.h"
@@ -127,6 +128,10 @@
               response_string);
   }
 
+  network::TestURLLoaderFactory* test_factory() {
+    return &test_factory_;
+  }
+
  private:
   scoped_refptr<base::TestMockTimeTaskRunner> mock_task_runner_;
   identity::IdentityTestEnvironment identity_test_env_;
@@ -222,8 +227,30 @@
   }
 }
 
-// TODO(pnoland): Add a test that verifies request headers
-// specify gzip.
+TEST_F(FeedNetworkingHostTest, ShouldSetHeadersCorrectly) {
+  MockResponseDoneCallback done_callback;
+  net::HttpRequestHeaders headers;
+  base::RunLoop interceptor_run_loop;
+  base::HistogramTester histogram_tester;
+
+  test_factory()->SetInterceptor(
+      base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
+        headers = request.headers;
+        interceptor_run_loop.Quit();
+      }));
+
+  SendRequestAndRespond("http://foobar.com/feed", "POST", "", "",
+                      net::HTTP_OK, network::URLLoaderCompletionStatus(),
+                      &done_callback);
+
+  std::string content_encoding;
+  std::string authorization;
+  EXPECT_TRUE(headers.GetHeader("content-encoding", &content_encoding));
+  EXPECT_TRUE(headers.GetHeader("Authorization", &authorization));
+
+  EXPECT_EQ(content_encoding, "gzip");
+  EXPECT_EQ(authorization, "Bearer access_token");
+}
 
 TEST_F(FeedNetworkingHostTest, ShouldReportSizeHistograms) {
   std::string uncompressed_request_string(2048, 'a');
diff --git a/components/payments/content/manifest_verifier.cc b/components/payments/content/manifest_verifier.cc
index 26047dd..8b6e910 100644
--- a/components/payments/content/manifest_verifier.cc
+++ b/components/payments/content/manifest_verifier.cc
@@ -94,9 +94,11 @@
       // https://w3c.github.io/payment-method-basic-card/
       // https://w3c.github.io/webpayments/proposals/interledger-payment-method.html
       // https://w3c.github.io/webpayments-methods-credit-transfer-direct-debit/
+      // https://w3c.github.io/webpayments-methods-tokenization/
       if (method == "basic-card" || method == "interledger" ||
           method == "payee-credit-transfer" ||
-          method == "payer-credit-transfer") {
+          method == "payer-credit-transfer" ||
+          method == "tokenized-card") {
         verified_method_names.emplace_back(method);
         continue;
       }
diff --git a/components/payments/core/autofill_payment_instrument_unittest.cc b/components/payments/core/autofill_payment_instrument_unittest.cc
index 57b9f6a..9e170be 100644
--- a/components/payments/core/autofill_payment_instrument_unittest.cc
+++ b/components/payments/core/autofill_payment_instrument_unittest.cc
@@ -59,9 +59,7 @@
   bool on_instrument_details_error_called_ = false;
 };
 
-class FakePaymentRequestDelegate
-    : public PaymentRequestDelegate,
-      public autofill::payments::PaymentsClientUnmaskDelegate {
+class FakePaymentRequestDelegate : public PaymentRequestDelegate {
  public:
   FakePaymentRequestDelegate()
       : locale_("en-US"),
@@ -71,10 +69,8 @@
             base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
                 &test_url_loader_factory_)),
         payments_client_(test_shared_loader_factory_,
-                         nullptr,
-                         nullptr,
-                         this,
-                         nullptr),
+                         /*pref_service=*/nullptr,
+                         /*identity_manager=*/nullptr),
         full_card_request_(&autofill_client_,
                            &payments_client_,
                            &personal_data_) {}
diff --git a/components/payments/core/test_payment_request_delegate.cc b/components/payments/core/test_payment_request_delegate.cc
index de207ed..ccd5d8d 100644
--- a/components/payments/core/test_payment_request_delegate.cc
+++ b/components/payments/core/test_payment_request_delegate.cc
@@ -17,10 +17,8 @@
           base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
               &test_url_loader_factory_)),
       payments_client_(test_shared_loader_factory_,
-                       nullptr,
-                       nullptr,
-                       /*unmask_delegate=*/&payments_client_delegate_,
-                       /*save_delegate=*/nullptr),
+                       /*pref_service=*/nullptr,
+                       /*identity_manager=*/nullptr),
       full_card_request_(&autofill_client_,
                          &payments_client_,
                          personal_data_manager) {}
@@ -102,12 +100,4 @@
   return true;
 }
 
-TestPaymentsClientDelegate::TestPaymentsClientDelegate() {}
-
-TestPaymentsClientDelegate::~TestPaymentsClientDelegate() {}
-
-void TestPaymentsClientDelegate::OnDidGetRealPan(
-    autofill::AutofillClient::PaymentsRpcResult result,
-    const std::string& real_pan) {}
-
 }  // namespace payments
diff --git a/components/payments/core/test_payment_request_delegate.h b/components/payments/core/test_payment_request_delegate.h
index 6c07f63d..5373fb1 100644
--- a/components/payments/core/test_payment_request_delegate.h
+++ b/components/payments/core/test_payment_request_delegate.h
@@ -21,18 +21,6 @@
 
 namespace payments {
 
-class TestPaymentsClientDelegate
-    : public autofill::payments::PaymentsClientUnmaskDelegate {
- public:
-  TestPaymentsClientDelegate();
-  ~TestPaymentsClientDelegate();
-
- private:
-  // autofill::payments::PaymentsClientUnmaskDelegate:
-  void OnDidGetRealPan(autofill::AutofillClient::PaymentsRpcResult result,
-                       const std::string& real_pan) override;
-};
-
 class TestPaymentRequestDelegate : public PaymentRequestDelegate {
  public:
   explicit TestPaymentRequestDelegate(
@@ -66,7 +54,6 @@
 
  private:
   base::MessageLoop loop_;
-  TestPaymentsClientDelegate payments_client_delegate_;
   autofill::PersonalDataManager* personal_data_manager_;
   std::string locale_;
   const GURL last_committed_url_;
diff --git a/components/storage_monitor/storage_monitor_chromeos.cc b/components/storage_monitor/storage_monitor_chromeos.cc
index 0954f2c..2eaafc2 100644
--- a/components/storage_monitor/storage_monitor_chromeos.cc
+++ b/components/storage_monitor/storage_monitor_chromeos.cc
@@ -162,10 +162,6 @@
                  weak_ptr_factory_.GetWeakPtr()));
 }
 
-void StorageMonitorCros::OnAutoMountableDiskEvent(
-    DiskMountManager::DiskEvent event,
-    const DiskMountManager::Disk& disk) {}
-
 void StorageMonitorCros::OnBootDeviceDiskEvent(
     DiskMountManager::DiskEvent event,
     const DiskMountManager::Disk& disk) {
@@ -191,9 +187,6 @@
   }
 }
 
-void StorageMonitorCros::OnDeviceEvent(DiskMountManager::DeviceEvent event,
-                                       const std::string& device_path) {}
-
 void StorageMonitorCros::OnMountEvent(
     DiskMountManager::MountEvent event,
     chromeos::MountError error_code,
@@ -235,14 +228,6 @@
   }
 }
 
-void StorageMonitorCros::OnFormatEvent(DiskMountManager::FormatEvent event,
-                                       chromeos::FormatError error_code,
-                                       const std::string& device_path) {}
-
-void StorageMonitorCros::OnRenameEvent(DiskMountManager::RenameEvent event,
-                                       chromeos::RenameError error_code,
-                                       const std::string& device_path) {}
-
 void StorageMonitorCros::SetMediaTransferProtocolManagerForTest(
     device::mojom::MtpManagerPtr test_manager) {
   DCHECK(!mtp_device_manager_);
diff --git a/components/storage_monitor/storage_monitor_chromeos.h b/components/storage_monitor/storage_monitor_chromeos.h
index 7786be421..1eb3bb92 100644
--- a/components/storage_monitor/storage_monitor_chromeos.h
+++ b/components/storage_monitor/storage_monitor_chromeos.h
@@ -46,24 +46,13 @@
       device::mojom::MtpManagerPtr test_manager);
 
   // chromeos::disks::DiskMountManager::Observer implementation.
-  void OnAutoMountableDiskEvent(
-      chromeos::disks::DiskMountManager::DiskEvent event,
-      const chromeos::disks::DiskMountManager::Disk& disk) override;
   void OnBootDeviceDiskEvent(
       chromeos::disks::DiskMountManager::DiskEvent event,
       const chromeos::disks::DiskMountManager::Disk& disk) override;
-  void OnDeviceEvent(chromeos::disks::DiskMountManager::DeviceEvent event,
-                     const std::string& device_path) override;
   void OnMountEvent(chromeos::disks::DiskMountManager::MountEvent event,
                     chromeos::MountError error_code,
                     const chromeos::disks::DiskMountManager::MountPointInfo&
                         mount_info) override;
-  void OnFormatEvent(chromeos::disks::DiskMountManager::FormatEvent event,
-                     chromeos::FormatError error_code,
-                     const std::string& device_path) override;
-  void OnRenameEvent(chromeos::disks::DiskMountManager::RenameEvent event,
-                     chromeos::RenameError error_code,
-                     const std::string& device_path) override;
 
   // StorageMonitor implementation.
   bool GetStorageInfoForPath(const base::FilePath& path,
diff --git a/components/viz/service/display_embedder/gl_output_surface_android.cc b/components/viz/service/display_embedder/gl_output_surface_android.cc
index 882e5d8..c5bd5a8 100644
--- a/components/viz/service/display_embedder/gl_output_surface_android.cc
+++ b/components/viz/service/display_embedder/gl_output_surface_android.cc
@@ -4,12 +4,16 @@
 
 #include "components/viz/service/display_embedder/gl_output_surface_android.h"
 
+#include "components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.h"
+
 namespace viz {
 
 GLOutputSurfaceAndroid::GLOutputSurfaceAndroid(
     scoped_refptr<VizProcessContextProvider> context_provider,
     SyntheticBeginFrameSource* synthetic_begin_frame_source)
-    : GLOutputSurface(context_provider, synthetic_begin_frame_source) {}
+    : GLOutputSurface(context_provider, synthetic_begin_frame_source),
+      overlay_candidate_validator_(
+          std::make_unique<CompositorOverlayCandidateValidatorAndroid>()) {}
 
 GLOutputSurfaceAndroid::~GLOutputSurfaceAndroid() = default;
 
@@ -23,4 +27,9 @@
       flags, std::move(swap_callback), std::move(presentation_callback));
 }
 
+OverlayCandidateValidator*
+GLOutputSurfaceAndroid::GetOverlayCandidateValidator() const {
+  return overlay_candidate_validator_.get();
+}
+
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/gl_output_surface_android.h b/components/viz/service/display_embedder/gl_output_surface_android.h
index 75827f1..e10c463 100644
--- a/components/viz/service/display_embedder/gl_output_surface_android.h
+++ b/components/viz/service/display_embedder/gl_output_surface_android.h
@@ -10,6 +10,7 @@
 #include "components/viz/service/display_embedder/gl_output_surface.h"
 
 namespace viz {
+class OverlayCandidateValidator;
 
 class GLOutputSurfaceAndroid : public GLOutputSurface {
  public:
@@ -24,8 +25,11 @@
       uint32_t flags,
       gpu::ContextSupport::SwapCompletedCallback swap_callback,
       gpu::ContextSupport::PresentationCallback presentation_callback) override;
+  OverlayCandidateValidator* GetOverlayCandidateValidator() const override;
 
  private:
+  std::unique_ptr<OverlayCandidateValidator> overlay_candidate_validator_;
+
   DISALLOW_COPY_AND_ASSIGN(GLOutputSurfaceAndroid);
 };
 
diff --git a/components/viz/service/main/viz_main_impl.cc b/components/viz/service/main/viz_main_impl.cc
index fdf998e..e547082 100644
--- a/components/viz/service/main/viz_main_impl.cc
+++ b/components/viz/service/main/viz_main_impl.cc
@@ -298,12 +298,19 @@
   DCHECK(gpu_service_);
   DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread());
 
+  gl::GLSurfaceFormat format;
+  // If we are running a SW Viz process, we may not have a default offscreen
+  // surface.
+  if (auto* offscreen_surface =
+          gpu_service_->gpu_channel_manager()->default_offscreen_surface()) {
+    format = offscreen_surface->GetFormat();
+  } else {
+    DCHECK_EQ(gl::GetGLImplementation(), gl::kGLImplementationDisabled);
+  }
+
   task_executor_ = base::MakeRefCounted<gpu::GpuInProcessThreadService>(
       gpu_thread_task_runner_, gpu_service_->sync_point_manager(),
-      gpu_service_->mailbox_manager(), gpu_service_->share_group(),
-      gpu_service_->gpu_channel_manager()
-          ->default_offscreen_surface()
-          ->GetFormat(),
+      gpu_service_->mailbox_manager(), gpu_service_->share_group(), format,
       gpu_service_->gpu_feature_info(),
       gpu_service_->gpu_channel_manager()->gpu_preferences());
 
diff --git a/content/browser/devtools/devtools_url_loader_interceptor.cc b/content/browser/devtools/devtools_url_loader_interceptor.cc
index 99e8fd1..fa63a56 100644
--- a/content/browser/devtools/devtools_url_loader_interceptor.cc
+++ b/content/browser/devtools/devtools_url_loader_interceptor.cc
@@ -944,7 +944,6 @@
                        create_loader_params_->request.url, "",
                        net::ForceSniffFileUrlsForHtml::kDisabled,
                        &head->mime_type);
-    head->did_mime_sniff = true;
   }
   head->content_length = body_size;
   head->encoded_data_length = header_size;
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc
index 1d467539..46cd268c 100644
--- a/content/browser/devtools/protocol/target_handler.cc
+++ b/content/browser/devtools/protocol/target_handler.cc
@@ -27,8 +27,6 @@
 
 namespace {
 
-static const char kMethod[] = "method";
-static const char kResumeMethod[] = "Runtime.runIfWaitingForDebugger";
 static const char kInitializerScript[] = R"(
   (function() {
     const bindingName = "%s";
@@ -241,8 +239,10 @@
     DevToolsAgentHostImpl* agent_host_impl =
         static_cast<DevToolsAgentHostImpl*>(agent_host);
     if (flatten_protocol) {
-      handler->target_registry_->AttachSubtargetSession(id, agent_host_impl,
-                                                        session);
+      handler->target_registry_->AttachSubtargetSession(
+          id, agent_host_impl, session,
+          base::BindOnce(&Session::ResumeIfThrottled,
+                         base::Unretained(session)));
     } else {
       agent_host_impl->AttachClient(session);
     }
@@ -275,17 +275,16 @@
 
   void SetThrottle(Throttle* throttle) { throttle_ = throttle; }
 
+  void ResumeIfThrottled() {
+    if (throttle_)
+      throttle_->Clear();
+  }
+
   void SendMessageToAgentHost(const std::string& message) {
     if (throttle_) {
-      bool resuming = false;
       std::unique_ptr<base::Value> value = base::JSONReader::Read(message);
-      if (value && value->is_dict()) {
-        base::Value* method = value->FindKey(kMethod);
-        resuming = method && method->is_string() &&
-                   method->GetString() == kResumeMethod;
-      }
-      if (resuming)
-        throttle_->Clear();
+      if (TargetRegistry::IsRuntimeResumeCommand(value.get()))
+        ResumeIfThrottled();
     }
 
     agent_host_->DispatchProtocolMessage(this, message);
@@ -426,7 +425,7 @@
 }
 
 Response TargetHandler::Disable() {
-  SetAutoAttach(false, false);
+  SetAutoAttach(false, false, false);
   SetDiscoverTargets(false);
   auto_attached_sessions_.clear();
   attached_sessions_.clear();
@@ -455,7 +454,7 @@
 void TargetHandler::AutoAttach(DevToolsAgentHost* host,
                                bool waiting_for_debugger) {
   std::string session_id =
-      Session::Attach(this, host, waiting_for_debugger, false);
+      Session::Attach(this, host, waiting_for_debugger, flatten_auto_attach_);
   auto_attached_sessions_[host] = attached_sessions_[session_id].get();
 }
 
@@ -517,8 +516,10 @@
   return Response::OK();
 }
 
-Response TargetHandler::SetAutoAttach(
-    bool auto_attach, bool wait_for_debugger_on_start) {
+Response TargetHandler::SetAutoAttach(bool auto_attach,
+                                      bool wait_for_debugger_on_start,
+                                      Maybe<bool> flatten) {
+  flatten_auto_attach_ = flatten.fromMaybe(false);
   auto_attacher_.SetAutoAttach(auto_attach, wait_for_debugger_on_start);
   if (!auto_attacher_.ShouldThrottleFramesNavigation())
     ClearThrottles();
diff --git a/content/browser/devtools/protocol/target_handler.h b/content/browser/devtools/protocol/target_handler.h
index ba5702a..69b17b4 100644
--- a/content/browser/devtools/protocol/target_handler.h
+++ b/content/browser/devtools/protocol/target_handler.h
@@ -49,7 +49,8 @@
   // Domain implementation.
   Response SetDiscoverTargets(bool discover) override;
   Response SetAutoAttach(bool auto_attach,
-                         bool wait_for_debugger_on_start) override;
+                         bool wait_for_debugger_on_start,
+                         Maybe<bool> flatten) override;
   Response SetRemoteLocations(
       std::unique_ptr<protocol::Array<Target::RemoteLocation>>) override;
   Response AttachToTarget(const std::string& target_id,
@@ -107,6 +108,7 @@
 
   std::unique_ptr<Target::Frontend> frontend_;
   TargetAutoAttacher auto_attacher_;
+  bool flatten_auto_attach_ = false;
   bool discover_;
   std::map<std::string, std::unique_ptr<Session>> attached_sessions_;
   std::map<DevToolsAgentHost*, Session*> auto_attached_sessions_;
diff --git a/content/browser/devtools/target_registry.cc b/content/browser/devtools/target_registry.cc
index aa783b0..6250b22 100644
--- a/content/browser/devtools/target_registry.cc
+++ b/content/browser/devtools/target_registry.cc
@@ -9,15 +9,45 @@
 
 namespace content {
 
+namespace {
+static const char kMethod[] = "method";
+static const char kResumeMethod[] = "Runtime.runIfWaitingForDebugger";
+}  // namespace
+
+// static
+bool TargetRegistry::IsRuntimeResumeCommand(base::Value* value) {
+  if (value && value->is_dict()) {
+    base::Value* method = value->FindKey(kMethod);
+    return method && method->is_string() &&
+           method->GetString() == kResumeMethod;
+  }
+  return false;
+}
+
+struct TargetRegistry::SessionInfo {
+  SessionInfo(scoped_refptr<DevToolsAgentHostImpl> agent_host,
+              DevToolsAgentHostClient* client,
+              base::OnceClosure resume_if_throttled)
+      : agent_host(agent_host),
+        client(client),
+        resume_if_throttled(std::move(resume_if_throttled)) {}
+  scoped_refptr<DevToolsAgentHostImpl> agent_host;
+  DevToolsAgentHostClient* client;
+  base::OnceClosure resume_if_throttled;
+};
+
 TargetRegistry::TargetRegistry(DevToolsSession* root_session)
     : root_session_(root_session) {}
 
 TargetRegistry::~TargetRegistry() {}
 
-void TargetRegistry::AttachSubtargetSession(const std::string& session_id,
-                                            DevToolsAgentHostImpl* agent_host,
-                                            DevToolsAgentHostClient* client) {
-  sessions_[session_id] = std::make_pair(agent_host, client);
+void TargetRegistry::AttachSubtargetSession(
+    const std::string& session_id,
+    DevToolsAgentHostImpl* agent_host,
+    DevToolsAgentHostClient* client,
+    base::OnceClosure resume_if_throttled) {
+  sessions_[session_id] = std::make_unique<SessionInfo>(
+      agent_host, client, std::move(resume_if_throttled));
   agent_host->AttachSubtargetClient(client, this);
 }
 void TargetRegistry::DetachSubtargetSession(const std::string& session_id) {
@@ -36,14 +66,17 @@
   std::string session_id;
   bool result = parsed_message->GetString("sessionId", &session_id);
   DCHECK(result);
-
   auto it = sessions_.find(session_id);
   if (it == sessions_.end()) {
     LOG(ERROR) << "Unknown session " << session_id;
     return;
   }
-  scoped_refptr<DevToolsAgentHostImpl> agent_host = it->second.first;
-  DevToolsAgentHostClient* client = it->second.second;
+  scoped_refptr<DevToolsAgentHostImpl> agent_host = it->second->agent_host;
+  DevToolsAgentHostClient* client = it->second->client;
+  if (!it->second->resume_if_throttled.is_null() &&
+      IsRuntimeResumeCommand(parsed_message.get())) {
+    std::move(it->second->resume_if_throttled).Run();
+  }
   agent_host->DispatchProtocolMessage(client, message,
                                       std::move(parsed_message));
 }
diff --git a/content/browser/devtools/target_registry.h b/content/browser/devtools/target_registry.h
index 5b12d858..9892da5 100644
--- a/content/browser/devtools/target_registry.h
+++ b/content/browser/devtools/target_registry.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/containers/flat_map.h"
 #include "base/values.h"
@@ -18,12 +19,15 @@
 
 class TargetRegistry {
  public:
+  static bool IsRuntimeResumeCommand(base::Value* value);
+
   explicit TargetRegistry(DevToolsSession* root_session);
   ~TargetRegistry();
 
   void AttachSubtargetSession(const std::string& session_id,
                               DevToolsAgentHostImpl* agent_host,
-                              DevToolsAgentHostClient* client);
+                              DevToolsAgentHostClient* client,
+                              base::OnceClosure resume_if_throttled);
   void DetachSubtargetSession(const std::string& session_id);
   bool CanDispatchMessageOnAgentHost(base::DictionaryValue* parsed_message);
   void DispatchMessageOnAgentHost(
@@ -34,10 +38,8 @@
 
  private:
   DevToolsSession* root_session_;
-  base::flat_map<
-      std::string,
-      std::pair<scoped_refptr<DevToolsAgentHostImpl>, DevToolsAgentHostClient*>>
-      sessions_;
+  struct SessionInfo;
+  base::flat_map<std::string, std::unique_ptr<SessionInfo>> sessions_;
   DISALLOW_COPY_AND_ASSIGN(TargetRegistry);
 };
 
diff --git a/content/browser/file_url_loader_factory.cc b/content/browser/file_url_loader_factory.cc
index cfed5f6..822e0a0 100644
--- a/content/browser/file_url_loader_factory.cc
+++ b/content/browser/file_url_loader_factory.cc
@@ -557,7 +557,6 @@
               ? net::ForceSniffFileUrlsForHtml::kEnabled
               : net::ForceSniffFileUrlsForHtml::kDisabled,
           &head.mime_type);
-      head.did_mime_sniff = true;
     }
     if (head.headers) {
       head.headers->AddHeader(
diff --git a/content/browser/fileapi/file_system_url_loader_factory.cc b/content/browser/fileapi/file_system_url_loader_factory.cc
index 183e2a9..7ef37b18 100644
--- a/content/browser/fileapi/file_system_url_loader_factory.cc
+++ b/content/browser/fileapi/file_system_url_loader_factory.cc
@@ -522,7 +522,6 @@
         SniffMimeType(file_data_->data(), result, url_.ToGURL(), type_hint,
                       net::ForceSniffFileUrlsForHtml::kDisabled,
                       &head_.mime_type);
-        head_.did_mime_sniff = true;
       }
 
       client_->OnReceiveResponse(head_);
diff --git a/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc b/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc
index 980fddb..82cfc276 100644
--- a/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc
+++ b/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc
@@ -739,7 +739,6 @@
   EXPECT_TRUE(client->has_received_completion());
 
   EXPECT_EQ(mime_type_direct, client->response_head().mime_type);
-  EXPECT_TRUE(client->response_head().did_mime_sniff);
 }
 
 IN_PROC_BROWSER_TEST_F(FileSystemURLLoaderFactoryTest, FileIncognito) {
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index e9d435c..9e0eae5d 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -42,6 +42,7 @@
 #include "content/public/browser/resource_dispatcher_host.h"
 #include "content/public/browser/resource_dispatcher_host_delegate.h"
 #include "content/public/browser/resource_throttle.h"
+#include "content/public/browser/site_isolation_policy.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -5391,6 +5392,11 @@
 // not modify the underlying last committed entry.)  Not crashing means that
 // the test is successful.
 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, ReloadOriginalRequest) {
+  // TODO(lukasza): https://crbug.com/417518: Get tests working with
+  // --site-per-process.
+  if (SiteIsolationPolicy::UseDedicatedProcessesForAllSites())
+    return;
+
   GURL original_url(embedded_test_server()->GetURL(
       "/navigation_controller/simple_page_1.html"));
   EXPECT_TRUE(NavigateToURL(shell(), original_url));
diff --git a/content/browser/gpu/gpu_ipc_browsertests.cc b/content/browser/gpu/gpu_ipc_browsertests.cc
index 31f2ab76..d69de17 100644
--- a/content/browser/gpu/gpu_ipc_browsertests.cc
+++ b/content/browser/gpu/gpu_ipc_browsertests.cc
@@ -367,4 +367,24 @@
 }
 #endif
 
+class GpuProcessHostDisableGLBrowserTest : public GpuProcessHostBrowserTest {
+ public:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    GpuProcessHostBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitchASCII(switches::kUseGL,
+                                    gl::kGLImplementationDisabledName);
+  }
+};
+
+// Android and CrOS don't support disabling GL.
+#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+IN_PROC_BROWSER_TEST_F(GpuProcessHostDisableGLBrowserTest, CreateAndDestroy) {
+  DCHECK(!IsChannelEstablished());
+  EstablishAndWait();
+  base::RunLoop run_loop;
+  StopGpuProcess(run_loop.QuitClosure());
+  run_loop.Run();
+}
+#endif
+
 }  // namespace content
diff --git a/content/browser/loader/loader_browsertest.cc b/content/browser/loader/loader_browsertest.cc
index 024fade..2a7dd5c 100644
--- a/content/browser/loader/loader_browsertest.cc
+++ b/content/browser/loader/loader_browsertest.cc
@@ -25,6 +25,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/resource_dispatcher_host_delegate.h"
 #include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/site_isolation_policy.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/previews_state.h"
@@ -1172,6 +1173,11 @@
 // bypass cookies SameSite=Strict protections by navigating a new window twice.
 IN_PROC_BROWSER_TEST_F(LoaderBrowserTest,
                        CookieSameSiteStrictOpenNewNamedWindowTwice) {
+  // TODO(lukasza): https://crbug.com/417518: Get tests working with
+  // --site-per-process.
+  if (SiteIsolationPolicy::UseDedicatedProcessesForAllSites())
+    return;
+
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // 1) Add cookies for 'a.com', one of them with the "SameSite=Strict" option.
diff --git a/content/browser/loader/mime_sniffing_resource_handler.cc b/content/browser/loader/mime_sniffing_resource_handler.cc
index 74707ef3..89e2c53 100644
--- a/content/browser/loader/mime_sniffing_resource_handler.cc
+++ b/content/browser/loader/mime_sniffing_resource_handler.cc
@@ -250,7 +250,6 @@
   // the mime type. However, even if it returns false, it returns a new type
   // that is probably better than the current one.
   response_->head.mime_type.assign(new_type);
-  response_->head.did_mime_sniff = true;
 
   if (!made_final_decision && (bytes_read > 0)) {
     controller->Resume();
diff --git a/content/browser/loader/mime_sniffing_resource_handler_unittest.cc b/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
index 6d23266..6ac3538 100644
--- a/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
+++ b/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
@@ -473,8 +473,6 @@
   EXPECT_EQ(1, test_handler->on_will_read_called());
   EXPECT_EQ(1, test_handler->on_read_completed_called());
 
-  EXPECT_TRUE(test_handler->resource_response()->head.did_mime_sniff);
-
   // Process all messages to ensure proper test teardown.
   content::RunAllPendingInMessageLoop();
 }
@@ -603,8 +601,6 @@
   EXPECT_EQ(1, test_handler->on_will_read_called());
   EXPECT_EQ(1, test_handler->on_read_completed_called());
 
-  EXPECT_FALSE(test_handler->resource_response()->head.did_mime_sniff);
-
   if (!read_completed) {
     EXPECT_EQ(MockResourceLoader::Status::CANCELED, mock_loader.status());
     EXPECT_EQ(net::ERR_ABORTED, mock_loader.error_code());
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 6f423f6..7b97b04 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -40,7 +40,6 @@
 #include "content/browser/web_package/signed_exchange_utils.h"
 #include "content/browser/webui/url_data_manager_backend.h"
 #include "content/browser/webui/web_ui_url_loader_factory_internal.h"
-#include "content/common/mime_sniffing_throttle.h"
 #include "content/common/navigation_subresource_loader_params.h"
 #include "content/common/net/record_load_histograms.h"
 #include "content/common/throttling_url_loader.h"
@@ -696,14 +695,11 @@
       // |interceptor| wants to handle the request with
       // |single_request_handler|.
       DCHECK(interceptor);
-      std::vector<std::unique_ptr<content::URLLoaderThrottle>> throttles =
-          CreateURLLoaderThrottles();
-      throttles.push_back(std::make_unique<MimeSniffingThrottle>());
       default_loader_used_ = false;
       url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
           base::MakeRefCounted<SingleRequestURLLoaderFactory>(
               std::move(single_request_handler)),
-          std::move(throttles), frame_tree_node_id_,
+          CreateURLLoaderThrottles(), frame_tree_node_id_,
           global_request_id_.request_id, network::mojom::kURLLoadOptionNone,
           resource_request_.get(), this, kNavigationUrlLoaderTrafficAnnotation,
           base::ThreadTaskRunnerHandle::Get());
diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc
index d11f55bf0f..a6d33ec2 100644
--- a/content/browser/loader/resource_dispatcher_host_unittest.cc
+++ b/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -2011,7 +2011,6 @@
 
   client.RunUntilResponseReceived();
   EXPECT_EQ("text/html", client.response_head().mime_type);
-  EXPECT_TRUE(client.response_head().did_mime_sniff);
 }
 
 // Tests that we don't sniff the mime type when the server provides one.
@@ -2033,7 +2032,6 @@
 
   client.RunUntilResponseReceived();
   EXPECT_EQ("image/jpeg", client.response_head().mime_type);
-  EXPECT_FALSE(client.response_head().did_mime_sniff);
 }
 
 // Tests that we don't sniff the mime type when there is no message body.
diff --git a/content/browser/renderer_host/input/fling_controller.cc b/content/browser/renderer_host/input/fling_controller.cc
index ba00279..2729115 100644
--- a/content/browser/renderer_host/input/fling_controller.cc
+++ b/content/browser/renderer_host/input/fling_controller.cc
@@ -449,6 +449,11 @@
   return fling_booster_ && fling_booster_->fling_cancellation_is_deferred();
 }
 
+bool FlingController::TouchscreenFlingInProgress() const {
+  return fling_in_progress_ && current_fling_parameters_.source_device ==
+                                   blink::kWebGestureDeviceTouchscreen;
+}
+
 gfx::Vector2dF FlingController::CurrentFlingVelocity() const {
   return current_fling_parameters_.velocity;
 }
diff --git a/content/browser/renderer_host/input/fling_controller.h b/content/browser/renderer_host/input/fling_controller.h
index 03288332..869e17b 100644
--- a/content/browser/renderer_host/input/fling_controller.h
+++ b/content/browser/renderer_host/input/fling_controller.h
@@ -99,6 +99,8 @@
 
   bool FlingCancellationIsDeferred() const;
 
+  bool TouchscreenFlingInProgress() const;
+
   gfx::Vector2dF CurrentFlingVelocity() const;
 
   // Returns the |TouchpadTapSuppressionController| instance.
diff --git a/content/browser/renderer_host/input/gesture_event_queue.cc b/content/browser/renderer_host/input/gesture_event_queue.cc
index 93347d9..a9ff466e 100644
--- a/content/browser/renderer_host/input/gesture_event_queue.cc
+++ b/content/browser/renderer_host/input/gesture_event_queue.cc
@@ -94,6 +94,9 @@
   return fling_controller_.FlingCancellationIsDeferred();
 }
 
+bool GestureEventQueue::TouchscreenFlingInProgress() const {
+  return fling_controller_.TouchscreenFlingInProgress();
+}
 gfx::Vector2dF GestureEventQueue::CurrentFlingVelocity() const {
   return fling_controller_.CurrentFlingVelocity();
 }
diff --git a/content/browser/renderer_host/input/gesture_event_queue.h b/content/browser/renderer_host/input/gesture_event_queue.h
index 3dec354..f07f3cd 100644
--- a/content/browser/renderer_host/input/gesture_event_queue.h
+++ b/content/browser/renderer_host/input/gesture_event_queue.h
@@ -117,6 +117,8 @@
 
   bool FlingCancellationIsDeferred() const;
 
+  bool TouchscreenFlingInProgress() const;
+
   gfx::Vector2dF CurrentFlingVelocity() const;
 
   void set_debounce_interval_time_ms_for_testing(int interval_ms) {
diff --git a/content/browser/renderer_host/input/input_router_client.h b/content/browser/renderer_host/input/input_router_client.h
index 01c2c1f..e714ee3 100644
--- a/content/browser/renderer_host/input/input_router_client.h
+++ b/content/browser/renderer_host/input/input_router_client.h
@@ -51,6 +51,9 @@
   // from the renderer.
   virtual void OnSetWhiteListedTouchAction(cc::TouchAction touch_action) = 0;
 
+  // Called when a renderer fling has terminated.
+  virtual void DidStopFlinging() = 0;
+
   // Called when a GSB has started scrolling a viewport.
   virtual void DidStartScrollingViewport() = 0;
 
diff --git a/content/browser/renderer_host/input/input_router_impl.cc b/content/browser/renderer_host/input/input_router_impl.cc
index 2028e30..788b74b 100644
--- a/content/browser/renderer_host/input/input_router_impl.cc
+++ b/content/browser/renderer_host/input/input_router_impl.cc
@@ -257,6 +257,15 @@
   client_->DidOverscroll(fling_updated_params);
 }
 
+void InputRouterImpl::DidStopFlinging() {
+  DCHECK_GT(active_renderer_fling_count_, 0);
+  // Note that we're only guaranteed to get a fling end notification from the
+  // renderer, not from any other consumers. Consequently, the GestureEventQueue
+  // cannot use this bookkeeping for logic like tap suppression.
+  --active_renderer_fling_count_;
+  client_->DidStopFlinging();
+}
+
 void InputRouterImpl::DidStartScrollingViewport() {
   client_->DidStartScrollingViewport();
 }
@@ -363,6 +372,10 @@
   output_stream_validator_.Validate(touch_event);
 }
 
+bool InputRouterImpl::TouchscreenFlingInProgress() {
+  return gesture_event_queue_.TouchscreenFlingInProgress();
+}
+
 void InputRouterImpl::SendGestureEventImmediately(
     const GestureEventWithLatencyInfo& gesture_event) {
   mojom::WidgetInputHandler::DispatchEventCallback callback = base::BindOnce(
@@ -548,6 +561,11 @@
                InputEventAckStateToString(state));
   if (source != InputEventAckSource::BROWSER)
     client_->DecrementInFlightEventCount(source);
+  if (gesture_event.event.GetType() ==
+          blink::WebInputEvent::kGestureFlingStart &&
+      state == INPUT_EVENT_ACK_STATE_CONSUMED) {
+    ++active_renderer_fling_count_;
+  }
 
   if (overscroll) {
     DCHECK_EQ(WebInputEvent::kGestureScrollUpdate,
diff --git a/content/browser/renderer_host/input/input_router_impl.h b/content/browser/renderer_host/input/input_router_impl.h
index b954551..53605ce 100644
--- a/content/browser/renderer_host/input/input_router_impl.h
+++ b/content/browser/renderer_host/input/input_router_impl.h
@@ -93,6 +93,7 @@
                                  uint32_t unique_touch_event_id,
                                  InputEventAckState state) override;
   void DidOverscroll(const ui::DidOverscrollParams& params) override;
+  void DidStopFlinging() override;
   void ImeCancelComposition() override;
   void DidStartScrollingViewport() override;
   void ImeCompositionRangeChanged(
@@ -126,6 +127,7 @@
                        InputEventAckSource ack_source,
                        InputEventAckState ack_result) override;
   void OnFilteringTouchEvent(const blink::WebTouchEvent& touch_event) override;
+  bool TouchscreenFlingInProgress() override;
 
   // GestureEventFilterClient
   void SendGestureEventImmediately(
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc
index b6b236d1..a4df1ae 100644
--- a/content/browser/renderer_host/input/input_router_impl_unittest.cc
+++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -134,6 +134,8 @@
     input_router_client_.DidOverscroll(params);
   }
 
+  void DidStopFlinging() override { input_router_client_.DidStopFlinging(); }
+
   void DidStartScrollingViewport() override {
     input_router_client_.DidStartScrollingViewport();
   }
diff --git a/content/browser/renderer_host/input/mock_input_router_client.cc b/content/browser/renderer_host/input/mock_input_router_client.cc
index 3d93e01..33168e9 100644
--- a/content/browser/renderer_host/input/mock_input_router_client.cc
+++ b/content/browser/renderer_host/input/mock_input_router_client.cc
@@ -60,6 +60,9 @@
   white_listed_touch_action_ = white_listed_touch_action;
 }
 
+void MockInputRouterClient::DidStopFlinging() {
+}
+
 void MockInputRouterClient::DidStartScrollingViewport() {}
 
 void MockInputRouterClient::ForwardGestureEventWithLatencyInfo(
diff --git a/content/browser/renderer_host/input/mock_input_router_client.h b/content/browser/renderer_host/input/mock_input_router_client.h
index 1ddce1a..8e161f5 100644
--- a/content/browser/renderer_host/input/mock_input_router_client.h
+++ b/content/browser/renderer_host/input/mock_input_router_client.h
@@ -33,6 +33,7 @@
   void OnHasTouchEventHandlers(bool has_handlers) override;
   void DidOverscroll(const ui::DidOverscrollParams& params) override;
   void OnSetWhiteListedTouchAction(cc::TouchAction touch_action) override;
+  void DidStopFlinging() override;
   void DidStartScrollingViewport() override;
   void ForwardWheelEventWithLatencyInfo(
       const blink::WebMouseWheelEvent& wheel_event,
diff --git a/content/browser/renderer_host/input/passthrough_touch_event_queue.h b/content/browser/renderer_host/input/passthrough_touch_event_queue.h
index 65d881e..bc5f793 100644
--- a/content/browser/renderer_host/input/passthrough_touch_event_queue.h
+++ b/content/browser/renderer_host/input/passthrough_touch_event_queue.h
@@ -33,6 +33,8 @@
 
   virtual void OnFilteringTouchEvent(
       const blink::WebTouchEvent& touch_event) = 0;
+
+  virtual bool TouchscreenFlingInProgress() = 0;
 };
 
 // A queue that processes a touch-event and forwards it on to the
diff --git a/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc b/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc
index 718e02b..3f23c3a3 100644
--- a/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc
+++ b/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc
@@ -94,6 +94,8 @@
   void OnFilteringTouchEvent(const blink::WebTouchEvent& touch_event) override {
   }
 
+  bool TouchscreenFlingInProgress() override { return false; }
+
  protected:
   void SetUpForTouchMoveSlopTesting(double slop_length_dips) {
     slop_length_dips_ = slop_length_dips;
diff --git a/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc b/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc
index 3fcb804a..63924d8 100644
--- a/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc
+++ b/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc
@@ -46,16 +46,7 @@
                  weak_factory_.GetWeakPtr()));
 }
 
-PepperNetworkProxyHost::~PepperNetworkProxyHost() {
-  while (!pending_requests_.empty()) {
-    // If the proxy_resolution_service_ is NULL, we shouldn't have any outstanding
-    // requests.
-    DCHECK(proxy_resolution_service_);
-    net::ProxyResolutionService::Request* request = pending_requests_.front();
-    proxy_resolution_service_->CancelRequest(request);
-    pending_requests_.pop();
-  }
-}
+PepperNetworkProxyHost::~PepperNetworkProxyHost() = default;
 
 PepperNetworkProxyHost::UIThreadData::UIThreadData() : is_allowed(false) {}
 
@@ -139,7 +130,7 @@
     } else {
       // Everything looks valid, so try to resolve the proxy.
       net::ProxyInfo* proxy_info = new net::ProxyInfo;
-      net::ProxyResolutionService::Request* pending_request = nullptr;
+      std::unique_ptr<net::ProxyResolutionService::Request> pending_request;
       base::Callback<void(int)> callback =
           base::Bind(&PepperNetworkProxyHost::OnResolveProxyCompleted,
                      weak_factory_.GetWeakPtr(),
@@ -148,7 +139,7 @@
       int result = proxy_resolution_service_->ResolveProxy(
           request.url, std::string(), proxy_info, callback, &pending_request,
           nullptr, net::NetLogWithSource());
-      pending_requests_.push(pending_request);
+      pending_requests_.push(std::move(pending_request));
       // If it was handled synchronously, we must run the callback now;
       // proxy_resolution_service_ won't run it for us in this case.
       if (result != net::ERR_IO_PENDING)
diff --git a/content/browser/renderer_host/pepper/pepper_network_proxy_host.h b/content/browser/renderer_host/pepper/pepper_network_proxy_host.h
index a3b9424ae..f1c5fe68 100644
--- a/content/browser/renderer_host/pepper/pepper_network_proxy_host.h
+++ b/content/browser/renderer_host/pepper/pepper_network_proxy_host.h
@@ -99,7 +99,8 @@
 
   // Requests awaiting a response from ProxyResolutionService. We need to store
   // these so that we can cancel them if we get destroyed.
-  base::queue<net::ProxyResolutionService::Request*> pending_requests_;
+  base::queue<std::unique_ptr<net::ProxyResolutionService::Request>>
+      pending_requests_;
 
   base::WeakPtrFactory<PepperNetworkProxyHost> weak_factory_;
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 8ac129f..89e3ced 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -713,7 +713,7 @@
   // Returns the keyboard layout mapping.
   base::flat_map<std::string, std::string> GetKeyboardLayoutMap();
 
-  void DidStopFlinging();
+  void DidStopFlinging() override;
 
   void GetContentRenderingTimeoutFrom(RenderWidgetHostImpl* other);
 
diff --git a/content/browser/resolve_proxy_msg_helper.cc b/content/browser/resolve_proxy_msg_helper.cc
index 347e7efea..7b77c5f 100644
--- a/content/browser/resolve_proxy_msg_helper.cc
+++ b/content/browser/resolve_proxy_msg_helper.cc
@@ -44,44 +44,28 @@
     StartPendingRequest();
 }
 
-ResolveProxyMsgHelper::~ResolveProxyMsgHelper() {
-  // Clear all pending requests if the ProxyResolutionService is still alive (if
-  // we have a default request context or override).
-  if (!pending_requests_.empty()) {
-    PendingRequest req = pending_requests_.front();
-    proxy_resolution_service_->CancelRequest(req.request);
-  }
-
-  for (PendingRequestList::iterator it = pending_requests_.begin();
-       it != pending_requests_.end();
-       ++it) {
-    delete it->reply_msg;
-  }
-
-  pending_requests_.clear();
-}
+ResolveProxyMsgHelper::~ResolveProxyMsgHelper() = default;
 
 void ResolveProxyMsgHelper::OnResolveProxyCompleted(int result) {
   CHECK(!pending_requests_.empty());
 
-  const PendingRequest& completed_req = pending_requests_.front();
-  ViewHostMsg_ResolveProxy::WriteReplyParams(
-      completed_req.reply_msg, result == net::OK, proxy_info_.ToPacString());
-  Send(completed_req.reply_msg);
-
   // Clear the current (completed) request.
+  PendingRequest completed_req = std::move(pending_requests_.front());
   pending_requests_.pop_front();
 
+  ViewHostMsg_ResolveProxy::WriteReplyParams(completed_req.reply_msg.get(),
+                                             result == net::OK,
+                                             proxy_info_.ToPacString());
+  Send(completed_req.reply_msg.release());
+
   // Start the next request.
   if (!pending_requests_.empty())
     StartPendingRequest();
 }
 
 void ResolveProxyMsgHelper::StartPendingRequest() {
-  PendingRequest& req = pending_requests_.front();
-
   // Verify the request wasn't started yet.
-  DCHECK(nullptr == req.request);
+  DCHECK(nullptr == pending_requests_.front().request);
 
   if (context_getter_.get()) {
     proxy_resolution_service_ = context_getter_->GetURLRequestContext()->proxy_resolution_service();
@@ -90,14 +74,26 @@
 
   // Start the request.
   int result = proxy_resolution_service_->ResolveProxy(
-      req.url, std::string(), &proxy_info_,
+      pending_requests_.front().url, std::string(), &proxy_info_,
       base::BindOnce(&ResolveProxyMsgHelper::OnResolveProxyCompleted,
                      base::Unretained(this)),
-      &req.request, nullptr, net::NetLogWithSource());
+      &pending_requests_.front().request, nullptr, net::NetLogWithSource());
 
   // Completed synchronously.
   if (result != net::ERR_IO_PENDING)
     OnResolveProxyCompleted(result);
 }
 
+ResolveProxyMsgHelper::PendingRequest::PendingRequest(const GURL& url,
+                                                      IPC::Message* reply_msg)
+    : url(url), reply_msg(reply_msg) {}
+
+ResolveProxyMsgHelper::PendingRequest::PendingRequest(
+    PendingRequest&& pending_request) = default;
+
+ResolveProxyMsgHelper::PendingRequest::~PendingRequest() noexcept = default;
+
+ResolveProxyMsgHelper::PendingRequest& ResolveProxyMsgHelper::PendingRequest::
+operator=(PendingRequest&& pending_request) noexcept = default;
+
 }  // namespace content
diff --git a/content/browser/resolve_proxy_msg_helper.h b/content/browser/resolve_proxy_msg_helper.h
index 8eacab90..ae5c0ff7 100644
--- a/content/browser/resolve_proxy_msg_helper.h
+++ b/content/browser/resolve_proxy_msg_helper.h
@@ -58,17 +58,23 @@
   // A PendingRequest is a resolve request that is in progress, or queued.
   struct PendingRequest {
    public:
-    PendingRequest(const GURL& url, IPC::Message* reply_msg)
-        : url(url), reply_msg(reply_msg), request(NULL) {}
+    PendingRequest(const GURL& url, IPC::Message* reply_msg);
+    PendingRequest(PendingRequest&& pending_request) noexcept;
+    ~PendingRequest();
+
+    PendingRequest& operator=(PendingRequest&& pending_request) noexcept;
 
     // The URL of the request.
     GURL url;
 
     // Data to pass back to the delegate on completion (we own it until then).
-    IPC::Message* reply_msg;
+    std::unique_ptr<IPC::Message> reply_msg;
 
     // Handle for cancelling the current request if it has started (else NULL).
-    net::ProxyResolutionService::Request* request;
+    std::unique_ptr<net::ProxyResolutionService::Request> request;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(PendingRequest);
   };
 
   // Info about the current outstanding proxy request.
diff --git a/content/browser/shared_worker/shared_worker_service_impl_unittest.cc b/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
index cf56ef37..e5d67bd 100644
--- a/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
+++ b/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
@@ -21,6 +21,7 @@
 #include "content/test/test_render_view_host.h"
 #include "content/test/test_web_contents.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/test_support/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/message_port/message_port_channel.h"
@@ -29,6 +30,42 @@
 
 namespace content {
 
+namespace {
+
+// A mock URLLoaderFactory which just fails to create a loader. This is
+// sufficient because the tests don't exercise script loading. Used when
+// S13nServiceWorker is enabled.
+class NotImplementedNetworkURLLoaderFactory final
+    : public network::mojom::URLLoaderFactory {
+ public:
+  NotImplementedNetworkURLLoaderFactory() = default;
+
+  // network::mojom::URLLoaderFactory implementation.
+  void CreateLoaderAndStart(network::mojom::URLLoaderRequest request,
+                            int32_t routing_id,
+                            int32_t request_id,
+                            uint32_t options,
+                            const network::ResourceRequest& url_request,
+                            network::mojom::URLLoaderClientPtr client,
+                            const net::MutableNetworkTrafficAnnotationTag&
+                                traffic_annotation) override {
+    network::URLLoaderCompletionStatus status;
+    status.error_code = net::ERR_NOT_IMPLEMENTED;
+    client->OnComplete(status);
+  }
+
+  void Clone(network::mojom::URLLoaderFactoryRequest request) override {
+    bindings_.AddBinding(this, std::move(request));
+  }
+
+ private:
+  mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(NotImplementedNetworkURLLoaderFactory);
+};
+
+}  // namespace
+
 class SharedWorkerServiceImplTest : public RenderViewHostImplTestHarness {
  public:
   mojom::SharedWorkerConnectorPtr MakeSharedWorkerConnector(
@@ -75,6 +112,8 @@
         std::make_unique<MockRenderProcessHostFactory>();
     RenderProcessHostImpl::set_render_process_host_factory_for_testing(
         render_process_host_factory_.get());
+    url_loader_factory_ =
+        std::make_unique<NotImplementedNetworkURLLoaderFactory>();
   }
 
   void TearDown() override {
@@ -86,6 +125,7 @@
   static std::queue<mojom::SharedWorkerFactoryRequest>
       s_factory_request_received_;
   std::unique_ptr<MockRenderProcessHostFactory> render_process_host_factory_;
+  std::unique_ptr<NotImplementedNetworkURLLoaderFactory> url_loader_factory_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(SharedWorkerServiceImplTest);
@@ -127,6 +167,7 @@
   renderer_host->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   MockSharedWorkerClient client;
   MessagePortChannel local_port;
@@ -202,6 +243,7 @@
   renderer_host0->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   MockSharedWorkerClient client0;
   MessagePortChannel local_port0;
@@ -270,6 +312,7 @@
   renderer_host1->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   MockSharedWorkerClient client1;
   MessagePortChannel local_port1;
@@ -331,6 +374,7 @@
   renderer_host0->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   // The second renderer host.
   std::unique_ptr<TestWebContents> web_contents1 =
@@ -402,6 +446,7 @@
   renderer_host0->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   // The second renderer host.
   std::unique_ptr<TestWebContents> web_contents1 =
@@ -411,6 +456,7 @@
   renderer_host1->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   // First client, creates worker.
 
@@ -485,6 +531,7 @@
   renderer_host0->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   // The second renderer host.
   std::unique_ptr<TestWebContents> web_contents1 =
@@ -494,6 +541,7 @@
   renderer_host1->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   // First client, creates worker.
 
@@ -567,6 +615,7 @@
   renderer_host0->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   // The second renderer host.
   std::unique_ptr<TestWebContents> web_contents1 =
@@ -576,6 +625,7 @@
   renderer_host1->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   // First client and second client are created before the worker starts.
 
@@ -640,6 +690,7 @@
   renderer_host0->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   // The second renderer host.
   std::unique_ptr<TestWebContents> web_contents1 =
@@ -649,6 +700,7 @@
   renderer_host1->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   // First client and second client are created before the workers start.
 
@@ -727,6 +779,7 @@
   renderer_host0->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   // The second renderer host.
   std::unique_ptr<TestWebContents> web_contents1 =
@@ -736,6 +789,7 @@
   renderer_host1->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   // First client and second client are created before the workers start.
 
@@ -814,6 +868,7 @@
   renderer_host0->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   std::unique_ptr<TestWebContents> web_contents1 =
       CreateWebContents(GURL("http://example.com/"));
@@ -822,6 +877,7 @@
   renderer_host1->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   std::unique_ptr<TestWebContents> web_contents2 =
       CreateWebContents(GURL("http://example.com/"));
@@ -830,6 +886,7 @@
   renderer_host2->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host2->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   MockSharedWorkerClient client0;
   MessagePortChannel local_port0;
@@ -922,6 +979,7 @@
   renderer_host0->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   std::unique_ptr<TestWebContents> web_contents1 =
       CreateWebContents(GURL("http://example.com/"));
@@ -930,6 +988,7 @@
   renderer_host1->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   std::unique_ptr<TestWebContents> web_contents2 =
       CreateWebContents(GURL("http://example.com/"));
@@ -938,6 +997,7 @@
   renderer_host2->OverrideBinderForTesting(
       mojom::SharedWorkerFactory::Name_,
       base::Bind(&SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host2->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   MockSharedWorkerClient client0;
   MessagePortChannel local_port0;
@@ -1007,6 +1067,7 @@
       mojom::SharedWorkerFactory::Name_,
       base::BindRepeating(
           &SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host0->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   // The second renderer host.
   std::unique_ptr<TestWebContents> web_contents1 =
@@ -1017,6 +1078,7 @@
       mojom::SharedWorkerFactory::Name_,
       base::BindRepeating(
           &SharedWorkerServiceImplTest::BindSharedWorkerFactory));
+  renderer_host1->OverrideURLLoaderFactory(url_loader_factory_.get());
 
   // Both clients try to connect/create a worker.
 
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index ffe38296..cf983f0 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -210,10 +210,6 @@
     "media/midi_messages.h",
     "media/peer_connection_tracker_messages.h",
     "media/video_capture.h",
-    "mime_sniffing_throttle.cc",
-    "mime_sniffing_throttle.h",
-    "mime_sniffing_url_loader.cc",
-    "mime_sniffing_url_loader.h",
     "navigation_gesture.h",
     "navigation_params.cc",
     "navigation_params.h",
diff --git a/content/common/DEPS b/content/common/DEPS
index 5f9362d..03fa018 100644
--- a/content/common/DEPS
+++ b/content/common/DEPS
@@ -84,8 +84,3 @@
   "+third_party/blink/public/web/web_triggering_event_info.h",
   "+third_party/blink/public/web/win/web_font_rendering.h",
 ]
-specific_include_rules = {
-  '.*_unittest.*': [
-    "+services/network/test",
-  ]
-}
diff --git a/content/common/input/input_handler.mojom b/content/common/input/input_handler.mojom
index bbf17cd..389e82b6 100644
--- a/content/common/input/input_handler.mojom
+++ b/content/common/input/input_handler.mojom
@@ -174,6 +174,9 @@
   // restrictions on the root scroll offset.
   DidOverscroll(DidOverscrollParams params);
 
+  // Sent by the compositor when a fling animation is stopped.
+  DidStopFlinging();
+
   // Sent by the compositor when a GSB has started scrolling the viewport.
   DidStartScrollingViewport();
 
diff --git a/content/common/mime_sniffing_throttle.cc b/content/common/mime_sniffing_throttle.cc
deleted file mode 100644
index dfeabde..0000000
--- a/content/common/mime_sniffing_throttle.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/common/mime_sniffing_throttle.h"
-
-#include "content/common/mime_sniffing_url_loader.h"
-#include "net/base/mime_sniffer.h"
-
-namespace content {
-
-MimeSniffingThrottle::MimeSniffingThrottle() : weak_factory_(this) {}
-
-MimeSniffingThrottle::~MimeSniffingThrottle() = default;
-
-void MimeSniffingThrottle::WillProcessResponse(
-    const GURL& response_url,
-    const network::ResourceResponseHead& response_head,
-    bool* defer) {
-  // No need to do mime sniffing again.
-  if (response_head.did_mime_sniff)
-    return;
-
-  bool blocked_sniffing_mime = false;
-  std::string content_type_options;
-  if (response_head.headers &&
-      response_head.headers->GetNormalizedHeader("x-content-type-options",
-                                                 &content_type_options)) {
-    blocked_sniffing_mime =
-        base::LowerCaseEqualsASCII(content_type_options, "nosniff");
-  }
-
-  if (!blocked_sniffing_mime &&
-      net::ShouldSniffMimeType(response_url, response_head.mime_type)) {
-    // Pause the response until the mime type becomes ready.
-    *defer = true;
-
-    network::mojom::URLLoaderPtr new_loader;
-    network::mojom::URLLoaderClientRequest new_loader_request;
-    network::mojom::URLLoaderPtr source_loader;
-    network::mojom::URLLoaderClientRequest source_client_request;
-    MimeSniffingURLLoader* mime_sniffing_loader;
-    std::tie(new_loader, new_loader_request, mime_sniffing_loader) =
-        MimeSniffingURLLoader::CreateLoader(weak_factory_.GetWeakPtr(),
-                                            response_url, response_head);
-    delegate_->InterceptResponse(std::move(new_loader),
-                                 std::move(new_loader_request), &source_loader,
-                                 &source_client_request);
-    mime_sniffing_loader->Start(std::move(source_loader),
-                                std::move(source_client_request));
-  }
-}
-
-void MimeSniffingThrottle::ResumeWithNewResponseHead(
-    const network::ResourceResponseHead& new_response_head) {
-  delegate_->UpdateDeferredResponseHead(new_response_head);
-  delegate_->Resume();
-}
-
-}  // namespace content
diff --git a/content/common/mime_sniffing_throttle.h b/content/common/mime_sniffing_throttle.h
deleted file mode 100644
index f8f35189..0000000
--- a/content/common/mime_sniffing_throttle.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_COMMON_MIME_SNIFFING_THROTTLE_H_
-#define CONTENT_COMMON_MIME_SNIFFING_THROTTLE_H_
-
-#include "base/memory/weak_ptr.h"
-#include "content/common/content_export.h"
-#include "content/public/common/url_loader_throttle.h"
-
-namespace content {
-
-// Throttle for mime type sniffing. This may intercept the request and
-// modify the response's mime type in the response head.
-class CONTENT_EXPORT MimeSniffingThrottle : public URLLoaderThrottle {
- public:
-  MimeSniffingThrottle();
-  ~MimeSniffingThrottle() override;
-
-  // Implements URLLoaderThrottle.
-  void WillProcessResponse(const GURL& response_url,
-                           const network::ResourceResponseHead& response_head,
-                           bool* defer) override;
-
-  // Called from MimeSniffingURLLoader once mime type is ready.
-  void ResumeWithNewResponseHead(
-      const network::ResourceResponseHead& new_response_head);
-
- private:
-  base::WeakPtrFactory<MimeSniffingThrottle> weak_factory_;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_COMMON_MIME_SNIFFING_THROTTLE_H_
diff --git a/content/common/mime_sniffing_throttle_unittest.cc b/content/common/mime_sniffing_throttle_unittest.cc
deleted file mode 100644
index 0e61e99..0000000
--- a/content/common/mime_sniffing_throttle_unittest.cc
+++ /dev/null
@@ -1,429 +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 "content/common/mime_sniffing_throttle.h"
-
-#include <memory>
-
-#include "base/run_loop.h"
-#include "base/test/scoped_task_environment.h"
-#include "content/common/mime_sniffing_url_loader.h"
-#include "content/public/common/url_loader_throttle.h"
-#include "mojo/public/cpp/system/data_pipe_utils.h"
-#include "services/network/test/test_url_loader_client.h"
-#include "services/network/test/test_url_loader_factory.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace content {
-
-namespace {
-
-class MojoDataPipeSender {
- public:
-  MojoDataPipeSender(mojo::ScopedDataPipeProducerHandle handle)
-      : handle_(std::move(handle)),
-        watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC) {}
-
-  void Start(std::string data, base::OnceClosure done_callback) {
-    data_ = std::move(data);
-    done_callback_ = std::move(done_callback);
-    watcher_.Watch(handle_.get(),
-                   MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
-                   base::BindRepeating(&MojoDataPipeSender::OnWritable,
-                                       base::Unretained(this)));
-  }
-
-  void OnWritable(MojoResult) {
-    uint32_t sending_bytes = data_.size() - sent_bytes_;
-    MojoResult result = handle_->WriteData(
-        data_.c_str() + sent_bytes_, &sending_bytes, MOJO_WRITE_DATA_FLAG_NONE);
-    switch (result) {
-      case MOJO_RESULT_OK:
-        break;
-      case MOJO_RESULT_FAILED_PRECONDITION:
-        // Finished unexpectedly.
-        std::move(done_callback_).Run();
-        return;
-      case MOJO_RESULT_SHOULD_WAIT:
-        // Just wait until OnWritable() is called by the watcher.
-        return;
-      default:
-        NOTREACHED();
-        return;
-    }
-    sent_bytes_ += sending_bytes;
-    if (data_.size() == sent_bytes_)
-      std::move(done_callback_).Run();
-  }
-
-  mojo::ScopedDataPipeProducerHandle ReleaseHandle() {
-    return std::move(handle_);
-  }
-
-  bool has_succeeded() const { return data_.size() == sent_bytes_; }
-
- private:
-  mojo::ScopedDataPipeProducerHandle handle_;
-  mojo::SimpleWatcher watcher_;
-  base::OnceClosure done_callback_;
-  std::string data_;
-  uint32_t sent_bytes_ = 0;
-};
-
-class MockDelegate : public URLLoaderThrottle::Delegate {
- public:
-  // Implements URLLoaderThrottle::Delegate.
-  void CancelWithError(int error_code,
-                       base::StringPiece custom_reason) override {
-    NOTIMPLEMENTED();
-  }
-  void Resume() override {
-    is_resumed_ = true;
-    // Resume from OnReceiveResponse() with a customized response header.
-    destination_loader_client()->OnReceiveResponse(
-        updated_response_head().value());
-  }
-
-  void SetPriority(net::RequestPriority priority) override { NOTIMPLEMENTED(); }
-  void UpdateDeferredResponseHead(
-      const network::ResourceResponseHead& new_response_head) override {
-    updated_response_head_ = new_response_head;
-  }
-  void PauseReadingBodyFromNet() override { NOTIMPLEMENTED(); }
-  void ResumeReadingBodyFromNet() override { NOTIMPLEMENTED(); }
-  void InterceptResponse(
-      network::mojom::URLLoaderPtr new_loader,
-      network::mojom::URLLoaderClientRequest new_client_request,
-      network::mojom::URLLoaderPtr* original_loader,
-      network::mojom::URLLoaderClientRequest* original_client_request)
-      override {
-    is_intercepted_ = true;
-
-    destination_loader_ptr_ = std::move(new_loader);
-    ASSERT_TRUE(mojo::FuseInterface(
-        std::move(new_client_request),
-        destination_loader_client_.CreateInterfacePtr().PassInterface()));
-    source_loader_request_ = mojo::MakeRequest(original_loader);
-    *original_client_request = mojo::MakeRequest(&source_loader_client_ptr_);
-  }
-
-  void LoadResponseBody(const std::string& body) {
-    if (!source_body_handle_.is_valid()) {
-      // Send OnStartLoadingResponseBody() if it's the first call.
-      mojo::ScopedDataPipeConsumerHandle consumer;
-      EXPECT_EQ(MOJO_RESULT_OK,
-                mojo::CreateDataPipe(nullptr, &source_body_handle_, &consumer));
-      source_loader_client()->OnStartLoadingResponseBody(std::move(consumer));
-    }
-
-    MojoDataPipeSender sender(std::move(source_body_handle_));
-    base::RunLoop loop;
-    sender.Start(body, loop.QuitClosure());
-    loop.Run();
-
-    EXPECT_TRUE(sender.has_succeeded());
-    source_body_handle_ = sender.ReleaseHandle();
-  }
-
-  void CompleteResponse() {
-    source_loader_client()->OnComplete(network::URLLoaderCompletionStatus());
-    source_body_handle_.reset();
-  }
-
-  uint32_t ReadResponseBody(uint32_t size) {
-    std::vector<uint8_t> buffer(size);
-    MojoResult result = destination_loader_client_.response_body().ReadData(
-        buffer.data(), &size, MOJO_READ_DATA_FLAG_NONE);
-    switch (result) {
-      case MOJO_RESULT_OK:
-        return size;
-      case MOJO_RESULT_FAILED_PRECONDITION:
-        return 0;
-      case MOJO_RESULT_SHOULD_WAIT:
-        return 0;
-      default:
-        NOTREACHED();
-    }
-    return 0;
-  }
-
-  bool is_intercepted() const { return is_intercepted_; }
-  bool is_resumed() const { return is_resumed_; }
-
-  const base::Optional<network::ResourceResponseHead>& updated_response_head()
-      const {
-    return updated_response_head_;
-  }
-
-  network::TestURLLoaderClient* destination_loader_client() {
-    return &destination_loader_client_;
-  }
-
-  network::mojom::URLLoaderClient* source_loader_client() {
-    return source_loader_client_ptr_.get();
-  }
-
- private:
-  bool is_intercepted_ = false;
-  bool is_resumed_ = false;
-  base::Optional<network::ResourceResponseHead> updated_response_head_;
-
-  // A pair of a loader and a loader client for destination of the response.
-  network::mojom::URLLoaderPtr destination_loader_ptr_;
-  network::TestURLLoaderClient destination_loader_client_;
-
-  // A pair of a loader and a loader client for source of the response.
-  network::mojom::URLLoaderClientPtr source_loader_client_ptr_;
-  network::mojom::URLLoaderRequest source_loader_request_;
-
-  mojo::ScopedDataPipeProducerHandle source_body_handle_;
-};
-
-}  // namespace
-
-class MimeSniffingThrottleTest : public testing::Test {
- protected:
-  // Be the first member so it is destroyed last.
-  base::test::ScopedTaskEnvironment scoped_task_environment_;
-};
-
-TEST_F(MimeSniffingThrottleTest, NoMimeTypeWithSniffableScheme) {
-  auto throttle = std::make_unique<MimeSniffingThrottle>();
-  auto delegate = std::make_unique<MockDelegate>();
-  throttle->set_delegate(delegate.get());
-
-  network::ResourceResponseHead response_head;
-  bool defer = false;
-  throttle->WillProcessResponse(GURL("https://example.com"), response_head,
-                                &defer);
-  EXPECT_TRUE(defer);
-  EXPECT_TRUE(delegate->is_intercepted());
-}
-
-TEST_F(MimeSniffingThrottleTest, SniffableMimeTypeWithSniffableScheme) {
-  auto throttle = std::make_unique<MimeSniffingThrottle>();
-  auto delegate = std::make_unique<MockDelegate>();
-  throttle->set_delegate(delegate.get());
-
-  network::ResourceResponseHead response_head;
-  response_head.mime_type = "text/plain";
-  bool defer = false;
-  throttle->WillProcessResponse(GURL("https://example.com"), response_head,
-                                &defer);
-  EXPECT_TRUE(defer);
-  EXPECT_TRUE(delegate->is_intercepted());
-}
-
-TEST_F(MimeSniffingThrottleTest, NotSniffableMimeTypeWithSniffableScheme) {
-  auto throttle = std::make_unique<MimeSniffingThrottle>();
-  auto delegate = std::make_unique<MockDelegate>();
-  throttle->set_delegate(delegate.get());
-
-  network::ResourceResponseHead response_head;
-  response_head.mime_type = "text/javascript";
-  bool defer = false;
-  throttle->WillProcessResponse(GURL("https://example.com"), response_head,
-                                &defer);
-  EXPECT_FALSE(defer);
-  EXPECT_FALSE(delegate->is_intercepted());
-}
-
-TEST_F(MimeSniffingThrottleTest, NoMimeTypeWithNotSniffableScheme) {
-  auto throttle = std::make_unique<MimeSniffingThrottle>();
-  auto delegate = std::make_unique<MockDelegate>();
-  throttle->set_delegate(delegate.get());
-
-  network::ResourceResponseHead response_head;
-  bool defer = false;
-  throttle->WillProcessResponse(GURL("wss://example.com"), response_head,
-                                &defer);
-  EXPECT_FALSE(defer);
-  EXPECT_FALSE(delegate->is_intercepted());
-}
-
-TEST_F(MimeSniffingThrottleTest, SniffableMimeTypeWithNotSniffableScheme) {
-  auto throttle = std::make_unique<MimeSniffingThrottle>();
-  auto delegate = std::make_unique<MockDelegate>();
-  throttle->set_delegate(delegate.get());
-
-  network::ResourceResponseHead response_head;
-  response_head.mime_type = "text/plain";
-  bool defer = false;
-  throttle->WillProcessResponse(GURL("wss://example.com"), response_head,
-                                &defer);
-  EXPECT_FALSE(defer);
-  EXPECT_FALSE(delegate->is_intercepted());
-}
-
-TEST_F(MimeSniffingThrottleTest, NotSniffableMimeTypeWithNotSniffableScheme) {
-  auto throttle = std::make_unique<MimeSniffingThrottle>();
-  auto delegate = std::make_unique<MockDelegate>();
-  throttle->set_delegate(delegate.get());
-
-  network::ResourceResponseHead response_head;
-  response_head.mime_type = "text/javascript";
-  bool defer = false;
-  throttle->WillProcessResponse(GURL("wss://example.com"), response_head,
-                                &defer);
-  EXPECT_FALSE(defer);
-  EXPECT_FALSE(delegate->is_intercepted());
-}
-
-TEST_F(MimeSniffingThrottleTest, SniffableButAlreadySniffed) {
-  auto throttle = std::make_unique<MimeSniffingThrottle>();
-  auto delegate = std::make_unique<MockDelegate>();
-  throttle->set_delegate(delegate.get());
-
-  network::ResourceResponseHead response_head;
-  response_head.mime_type = "text/plain";
-  response_head.did_mime_sniff = true;
-  bool defer = false;
-  throttle->WillProcessResponse(GURL("https://example.com"), response_head,
-                                &defer);
-  EXPECT_FALSE(defer);
-  EXPECT_FALSE(delegate->is_intercepted());
-}
-
-TEST_F(MimeSniffingThrottleTest, NoBody) {
-  auto throttle = std::make_unique<MimeSniffingThrottle>();
-  auto delegate = std::make_unique<MockDelegate>();
-  throttle->set_delegate(delegate.get());
-
-  GURL response_url("https://example.com");
-  network::ResourceResponseHead response_head;
-  bool defer = false;
-  throttle->WillProcessResponse(response_url, response_head, &defer);
-  EXPECT_TRUE(defer);
-  EXPECT_TRUE(delegate->is_intercepted());
-
-  // Call OnComplete() without sending body.
-  delegate->source_loader_client()->OnComplete(
-      network::URLLoaderCompletionStatus());
-  delegate->destination_loader_client()->RunUntilComplete();
-
-  // The mime type should be updated to the default mime type ("text/plain").
-  EXPECT_TRUE(delegate->destination_loader_client()->has_received_response());
-  EXPECT_EQ("text/plain",
-            delegate->destination_loader_client()->response_head().mime_type);
-}
-
-TEST_F(MimeSniffingThrottleTest, Body_PlainText) {
-  auto throttle = std::make_unique<MimeSniffingThrottle>();
-  auto delegate = std::make_unique<MockDelegate>();
-  throttle->set_delegate(delegate.get());
-
-  GURL response_url("https://example.com");
-  network::ResourceResponseHead response_head;
-  bool defer = false;
-  throttle->WillProcessResponse(response_url, response_head, &defer);
-  EXPECT_TRUE(defer);
-  EXPECT_TRUE(delegate->is_intercepted());
-
-  // Send the body and complete the response.
-  delegate->LoadResponseBody("This is a text.");
-  delegate->CompleteResponse();
-  delegate->destination_loader_client()->RunUntilComplete();
-
-  // The mime type should be updated.
-  EXPECT_TRUE(delegate->is_resumed());
-  EXPECT_EQ("text/plain",
-            delegate->destination_loader_client()->response_head().mime_type);
-}
-
-TEST_F(MimeSniffingThrottleTest, Body_Docx) {
-  auto throttle = std::make_unique<MimeSniffingThrottle>();
-  auto delegate = std::make_unique<MockDelegate>();
-  throttle->set_delegate(delegate.get());
-
-  GURL response_url("https://example.com/hogehoge.docx");
-  network::ResourceResponseHead response_head;
-  bool defer = false;
-  throttle->WillProcessResponse(response_url, response_head, &defer);
-  EXPECT_TRUE(defer);
-  EXPECT_TRUE(delegate->is_intercepted());
-
-  // Send the body and complete the response.
-  delegate->LoadResponseBody("\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1");
-  delegate->CompleteResponse();
-  delegate->destination_loader_client()->RunUntilComplete();
-
-  // The mime type should be updated.
-  EXPECT_TRUE(delegate->is_resumed());
-  EXPECT_EQ("application/msword",
-            delegate->destination_loader_client()->response_head().mime_type);
-}
-
-TEST_F(MimeSniffingThrottleTest, Body_PNG) {
-  auto throttle = std::make_unique<MimeSniffingThrottle>();
-  auto delegate = std::make_unique<MockDelegate>();
-  throttle->set_delegate(delegate.get());
-
-  GURL response_url("https://example.com/hogehoge.docx");
-  network::ResourceResponseHead response_head;
-  bool defer = false;
-  throttle->WillProcessResponse(response_url, response_head, &defer);
-  EXPECT_TRUE(defer);
-  EXPECT_TRUE(delegate->is_intercepted());
-
-  // Send the body and complete the response.
-  delegate->LoadResponseBody("\x89PNG\x0D\x0A\x1A\x0A");
-  delegate->CompleteResponse();
-  delegate->destination_loader_client()->RunUntilComplete();
-
-  // The mime type should be updated.
-  EXPECT_TRUE(delegate->is_resumed());
-  EXPECT_EQ("image/png",
-            delegate->destination_loader_client()->response_head().mime_type);
-}
-
-TEST_F(MimeSniffingThrottleTest, Body_LongPlainText) {
-  auto throttle = std::make_unique<MimeSniffingThrottle>();
-  auto delegate = std::make_unique<MockDelegate>();
-  throttle->set_delegate(delegate.get());
-
-  GURL response_url("https://example.com");
-  network::ResourceResponseHead response_head;
-  bool defer = false;
-  throttle->WillProcessResponse(response_url, response_head, &defer);
-  EXPECT_TRUE(defer);
-  EXPECT_TRUE(delegate->is_intercepted());
-
-  // 64KiB is coming from the default value used in
-  // mojo::core::Core::CreateDataPipe().
-  const uint32_t kDefaultDataPipeBufferSize = 64 * 1024;
-  std::string long_body(kDefaultDataPipeBufferSize * 2, 'x');
-
-  // Send the data to the MimeSniffingURLLoader.
-  // |delegate|'s MojoDataPipeSender sends the first
-  // |kDefaultDataPipeBufferSize| bytes to MimeSniffingURLLoader and
-  // MimeSniffingURLLoader will read the first |kDefaultDataPipeBufferSize|
-  // bytes of the body, so the MojoDataPipeSender can push the rest of
-  // |kDefaultDataPipeBufferSize| of the body soon and finishes sending the
-  // body. After this, MimeSniffingURLLoader is waiting to push the body to the
-  // destination data pipe since the pipe should be full until it's read.
-  delegate->LoadResponseBody(long_body);
-  scoped_task_environment_.RunUntilIdle();
-
-  // Read the half of the body. This unblocks MimeSniffingURLLoader to push the
-  // rest of the body to the data pipe.
-  uint32_t read_bytes = delegate->ReadResponseBody(long_body.size() / 2);
-  scoped_task_environment_.RunUntilIdle();
-
-  // Read the rest of the body.
-  read_bytes += delegate->ReadResponseBody(long_body.size() / 2);
-  scoped_task_environment_.RunUntilIdle();
-  delegate->CompleteResponse();
-  delegate->destination_loader_client()->RunUntilComplete();
-
-  // Check if all data has been read.
-  EXPECT_EQ(long_body.size(), read_bytes);
-
-  // The mime type should be updated.
-  EXPECT_TRUE(delegate->is_resumed());
-  EXPECT_EQ("text/plain",
-            delegate->destination_loader_client()->response_head().mime_type);
-}
-
-}  // namespace content
diff --git a/content/common/mime_sniffing_url_loader.cc b/content/common/mime_sniffing_url_loader.cc
deleted file mode 100644
index d7c2bce..0000000
--- a/content/common/mime_sniffing_url_loader.cc
+++ /dev/null
@@ -1,355 +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 "content/common/mime_sniffing_url_loader.h"
-
-#include "content/common/mime_sniffing_throttle.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "net/base/mime_sniffer.h"
-
-namespace content {
-
-// static
-const char MimeSniffingURLLoader::kDefaultMimeType[] = "text/plain";
-
-// static
-std::tuple<network::mojom::URLLoaderPtr,
-           network::mojom::URLLoaderClientRequest,
-           MimeSniffingURLLoader*>
-MimeSniffingURLLoader::CreateLoader(
-    base::WeakPtr<MimeSniffingThrottle> throttle,
-    const GURL& response_url,
-    const network::ResourceResponseHead& response_head) {
-  network::mojom::URLLoaderPtr url_loader;
-  network::mojom::URLLoaderClientPtr url_loader_client;
-  network::mojom::URLLoaderClientRequest url_loader_client_request =
-      mojo::MakeRequest(&url_loader_client);
-  auto loader = base::WrapUnique(
-      new MimeSniffingURLLoader(std::move(throttle), response_url,
-                                response_head, std::move(url_loader_client)));
-  MimeSniffingURLLoader* loader_rawptr = loader.get();
-  mojo::MakeStrongBinding(std::move(loader), mojo::MakeRequest(&url_loader));
-  return std::make_tuple(std::move(url_loader),
-                         std::move(url_loader_client_request), loader_rawptr);
-}
-
-MimeSniffingURLLoader::MimeSniffingURLLoader(
-    base::WeakPtr<MimeSniffingThrottle> throttle,
-    const GURL& response_url,
-    const network::ResourceResponseHead& response_head,
-    network::mojom::URLLoaderClientPtr destination_url_loader_client)
-    : throttle_(throttle),
-      source_url_client_binding_(this),
-      destination_url_loader_client_(std::move(destination_url_loader_client)),
-      response_url_(response_url),
-      response_head_(response_head),
-      body_consumer_watcher_(FROM_HERE,
-                             mojo::SimpleWatcher::ArmingPolicy::MANUAL),
-      body_producer_watcher_(FROM_HERE,
-                             mojo::SimpleWatcher::ArmingPolicy::MANUAL) {}
-
-MimeSniffingURLLoader::~MimeSniffingURLLoader() = default;
-
-void MimeSniffingURLLoader::Start(
-    network::mojom::URLLoaderPtr source_url_loader,
-    network::mojom::URLLoaderClientRequest source_url_loader_client_request) {
-  source_url_loader_ = std::move(source_url_loader);
-  source_url_client_binding_.Bind(std::move(source_url_loader_client_request));
-}
-
-void MimeSniffingURLLoader::OnReceiveResponse(
-    const network::ResourceResponseHead& response_head) {
-  // OnReceiveResponse() shouldn't be called because MimeSniffingURLLoader is
-  // created by MimeSniffingThrottle::WillProcessResponse(), which is equivalent
-  // to OnReceiveResponse().
-  NOTREACHED();
-}
-
-void MimeSniffingURLLoader::OnReceiveRedirect(
-    const net::RedirectInfo& redirect_info,
-    const network::ResourceResponseHead& response_head) {
-  // OnReceiveRedirect() shouldn't be called because MimeSniffingURLLoader is
-  // created by MimeSniffingThrottle::WillProcessResponse(), which is equivalent
-  // to OnReceiveResponse().
-  NOTREACHED();
-}
-
-void MimeSniffingURLLoader::OnUploadProgress(
-    int64_t current_position,
-    int64_t total_size,
-    OnUploadProgressCallback ack_callback) {
-  destination_url_loader_client_->OnUploadProgress(current_position, total_size,
-                                                   std::move(ack_callback));
-}
-
-void MimeSniffingURLLoader::OnReceiveCachedMetadata(
-    const std::vector<uint8_t>& data) {
-  destination_url_loader_client_->OnReceiveCachedMetadata(data);
-}
-
-void MimeSniffingURLLoader::OnTransferSizeUpdated(int32_t transfer_size_diff) {
-  destination_url_loader_client_->OnTransferSizeUpdated(transfer_size_diff);
-}
-
-void MimeSniffingURLLoader::OnStartLoadingResponseBody(
-    mojo::ScopedDataPipeConsumerHandle body) {
-  state_ = State::kSniffing;
-  body_consumer_handle_ = std::move(body);
-  body_consumer_watcher_.Watch(
-      body_consumer_handle_.get(),
-      MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
-      base::BindRepeating(&MimeSniffingURLLoader::OnBodyReadable,
-                          base::Unretained(this)));
-  body_consumer_watcher_.ArmOrNotify();
-}
-
-void MimeSniffingURLLoader::OnComplete(
-    const network::URLLoaderCompletionStatus& status) {
-  DCHECK(!complete_status_.has_value());
-  switch (state_) {
-    case State::kWaitForBody:
-      // OnComplete() is called without OnStartLoadingResponseBody(). There is
-      // no response body in this case. Use |kDefaultMimeType| as its mime type
-      // even though it's empty.
-      state_ = State::kCompleted;
-      response_head_.mime_type = kDefaultMimeType;
-      if (!throttle_) {
-        Abort();
-        return;
-      }
-      throttle_->ResumeWithNewResponseHead(response_head_);
-      destination_url_loader_client_->OnComplete(status);
-      return;
-    case State::kSniffing:
-      // Defer calling OnComplete() since we defer calling
-      // OnStartLoadingResponseBody() until mime sniffing has been finished.
-      complete_status_ = status;
-      return;
-    case State::kSending:
-    case State::kCompleted:
-      destination_url_loader_client_->OnComplete(status);
-      return;
-  }
-  NOTREACHED();
-}
-
-void MimeSniffingURLLoader::FollowRedirect(
-    const base::Optional<std::vector<std::string>>&
-        to_be_removed_request_headers,
-    const base::Optional<net::HttpRequestHeaders>& modified_request_headers) {
-  // MimeSniffingURLLoader starts handling the request after
-  // OnReceivedResponse(). A redirect response is not expected.
-  NOTREACHED();
-}
-
-void MimeSniffingURLLoader::ProceedWithResponse() {
-  source_url_loader_->ProceedWithResponse();
-}
-
-void MimeSniffingURLLoader::SetPriority(net::RequestPriority priority,
-                                        int32_t intra_priority_value) {
-  source_url_loader_->SetPriority(priority, intra_priority_value);
-}
-
-void MimeSniffingURLLoader::PauseReadingBodyFromNet() {
-  source_url_loader_->PauseReadingBodyFromNet();
-}
-
-void MimeSniffingURLLoader::ResumeReadingBodyFromNet() {
-  source_url_loader_->ResumeReadingBodyFromNet();
-}
-
-void MimeSniffingURLLoader::OnBodyReadable(MojoResult) {
-  if (state_ == State::kSending) {
-    // The pipe becoming readable when kSending means all buffered body has
-    // already been sent.
-    ForwardBodyToClient();
-    return;
-  }
-  DCHECK_EQ(State::kSniffing, state_);
-
-  size_t start_size = buffered_body_.size();
-  uint32_t read_bytes = net::kMaxBytesToSniff;
-  buffered_body_.resize(start_size + read_bytes);
-  MojoResult result =
-      body_consumer_handle_->ReadData(buffered_body_.data() + start_size,
-                                      &read_bytes, MOJO_READ_DATA_FLAG_NONE);
-  switch (result) {
-    case MOJO_RESULT_OK:
-      break;
-    case MOJO_RESULT_FAILED_PRECONDITION:
-      // Finished the body before mime type is completely decided.
-      buffered_body_.resize(start_size);
-      CompleteSniffing();
-      return;
-    case MOJO_RESULT_SHOULD_WAIT:
-      body_consumer_watcher_.ArmOrNotify();
-      return;
-    default:
-      NOTREACHED();
-      return;
-  }
-
-  DCHECK_EQ(MOJO_RESULT_OK, result);
-  buffered_body_.resize(start_size + read_bytes);
-  std::string new_type;
-  bool made_final_decision =
-      net::SniffMimeType(buffered_body_.data(), buffered_body_.size(),
-                         response_url_, response_head_.mime_type,
-                         net::ForceSniffFileUrlsForHtml::kDisabled, &new_type);
-  response_head_.mime_type = new_type;
-  response_head_.did_mime_sniff = true;
-  if (made_final_decision) {
-    CompleteSniffing();
-    return;
-  }
-  body_consumer_watcher_.ArmOrNotify();
-}
-
-void MimeSniffingURLLoader::OnBodyWritable(MojoResult) {
-  DCHECK_EQ(State::kSending, state_);
-  if (bytes_remaining_in_buffer_ > 0) {
-    SendReceivedBodyToClient();
-  } else {
-    ForwardBodyToClient();
-  }
-}
-
-void MimeSniffingURLLoader::CompleteSniffing() {
-  DCHECK_EQ(State::kSniffing, state_);
-  if (buffered_body_.empty()) {
-    // A data pipe for the body was received but no body was provided. Don't
-    // propagate OnStartLoadingResponseBody() in this case. We treat this
-    // situation as the same as when OnStartLoadingResponseBody() was not
-    // called.
-    //
-    // TODO(crbug.com/826868): Remove this once all loaders are aligned.
-    state_ = State::kWaitForBody;
-    if (complete_status_.has_value()) {
-      auto status = complete_status_.value();
-      complete_status_.reset();
-      OnComplete(status);
-    }
-    return;
-  }
-
-  state_ = State::kSending;
-  bytes_remaining_in_buffer_ = buffered_body_.size();
-  if (!throttle_) {
-    Abort();
-    return;
-  }
-  throttle_->ResumeWithNewResponseHead(response_head_);
-  mojo::ScopedDataPipeConsumerHandle body_to_send;
-  MojoResult result =
-      mojo::CreateDataPipe(nullptr, &body_producer_handle_, &body_to_send);
-  if (result != MOJO_RESULT_OK) {
-    Abort();
-    return;
-  }
-  // Set up the watcher for the producer handle.
-  body_producer_watcher_.Watch(
-      body_producer_handle_.get(),
-      MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
-      base::BindRepeating(&MimeSniffingURLLoader::OnBodyWritable,
-                          base::Unretained(this)));
-  // Send deferred messages.
-  destination_url_loader_client_->OnStartLoadingResponseBody(
-      std::move(body_to_send));
-  // Call OnComplete() if OnComplete() has already been called.
-  if (complete_status_.has_value())
-    destination_url_loader_client_->OnComplete(complete_status_.value());
-  SendReceivedBodyToClient();
-}
-
-void MimeSniffingURLLoader::CompleteSending() {
-  DCHECK_EQ(State::kSending, state_);
-  state_ = State::kCompleted;
-  body_consumer_watcher_.Cancel();
-  body_producer_watcher_.Cancel();
-  body_consumer_handle_.reset();
-  body_producer_handle_.reset();
-}
-
-void MimeSniffingURLLoader::SendReceivedBodyToClient() {
-  DCHECK_EQ(State::kSending, state_);
-  // Send the buffered data first.
-  DCHECK_GT(bytes_remaining_in_buffer_, 0u);
-  size_t start_position = buffered_body_.size() - bytes_remaining_in_buffer_;
-  uint32_t bytes_sent = bytes_remaining_in_buffer_;
-  MojoResult result =
-      body_producer_handle_->WriteData(buffered_body_.data() + start_position,
-                                       &bytes_sent, MOJO_WRITE_DATA_FLAG_NONE);
-  switch (result) {
-    case MOJO_RESULT_OK:
-      break;
-    case MOJO_RESULT_FAILED_PRECONDITION:
-      // The pipe is closed unexpectedly. |this| should be deleted once
-      // URLLoaderPtr on the destination is released.
-      Abort();
-      return;
-    case MOJO_RESULT_SHOULD_WAIT:
-      body_producer_watcher_.ArmOrNotify();
-      return;
-    default:
-      NOTREACHED();
-      return;
-  }
-  bytes_remaining_in_buffer_ -= bytes_sent;
-  body_producer_watcher_.ArmOrNotify();
-}
-
-void MimeSniffingURLLoader::ForwardBodyToClient() {
-  DCHECK_EQ(0u, bytes_remaining_in_buffer_);
-  // Send the body from the consumer to the producer.
-  const void* buffer;
-  uint32_t buffer_size = 0;
-  MojoResult result = body_consumer_handle_->BeginReadData(
-      &buffer, &buffer_size, MOJO_BEGIN_READ_DATA_FLAG_NONE);
-  switch (result) {
-    case MOJO_RESULT_OK:
-      break;
-    case MOJO_RESULT_SHOULD_WAIT:
-      body_consumer_watcher_.ArmOrNotify();
-      return;
-    case MOJO_RESULT_FAILED_PRECONDITION:
-      // All data has been sent.
-      CompleteSending();
-      return;
-    default:
-      NOTREACHED();
-      return;
-  }
-
-  result = body_producer_handle_->WriteData(buffer, &buffer_size,
-                                            MOJO_WRITE_DATA_FLAG_NONE);
-  switch (result) {
-    case MOJO_RESULT_OK:
-      break;
-    case MOJO_RESULT_FAILED_PRECONDITION:
-      // The pipe is closed unexpectedly. |this| should be deleted once
-      // URLLoaderPtr on the destination is released.
-      Abort();
-      return;
-    case MOJO_RESULT_SHOULD_WAIT:
-      body_consumer_handle_->EndReadData(0);
-      body_producer_watcher_.ArmOrNotify();
-      return;
-    default:
-      NOTREACHED();
-      return;
-  }
-
-  body_consumer_handle_->EndReadData(buffer_size);
-  body_consumer_watcher_.ArmOrNotify();
-}
-
-void MimeSniffingURLLoader::Abort() {
-  source_url_loader_.reset();
-  destination_url_loader_client_.reset();
-  // |this| should be removed since the owner will destroy |this| or the owner
-  // has already been destroyed by some reason.
-}
-
-}  // namespace content
diff --git a/content/common/mime_sniffing_url_loader.h b/content/common/mime_sniffing_url_loader.h
deleted file mode 100644
index 4e7a3c4..0000000
--- a/content/common/mime_sniffing_url_loader.h
+++ /dev/null
@@ -1,145 +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 CONTENT_COMMON_MIME_SNIFFING_URL_LOADER_H_
-#define CONTENT_COMMON_MIME_SNIFFING_URL_LOADER_H_
-
-#include <tuple>
-
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/strings/string_piece.h"
-#include "content/common/content_export.h"
-#include "content/common/possibly_associated_interface_ptr.h"
-#include "content/public/common/url_loader_throttle.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/system/data_pipe.h"
-#include "mojo/public/cpp/system/simple_watcher.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "services/network/public/mojom/url_loader.mojom.h"
-#include "services/network/public/mojom/url_loader_factory.mojom.h"
-
-namespace content {
-
-class MimeSniffingThrottle;
-
-// Reads the response body and determines its mime type. This url loader buffers
-// the response body until the mime type is decided. MimeSniffingURLLoader
-// is expected to be created just after receiving OnReceiveResponse(), so this
-// handles only OnStartLoadingResponseBody() and OnComplete() as a
-// network::mojom::URLLoaderClient.
-//
-// This loader has four state:
-// kWaitForBody: The initial state until the body is received (=
-//               OnStartLoadingResponseBody() is called) or the response is
-//               finished (= OnComplete() is called). When body is provided, the
-//               state is changed to kSniffing. Otherwise the state goes to
-//               kCompleted.
-// kSniffing: Receives the body from the source loader and estimate the mime
-//            type. The received body is kept in this loader until the mime type
-//            is decided. When the mime type is decided or all body has been
-//            received, this loader will dispatch queued messages like
-//            OnStartLoadingResponseBody() and OnComplete() to the destination
-//            loader client, and then the state is changed to kSending.
-// kSending: Receives the body and send it to the destination loader client. All
-//           data has been read by this loader, the state goes to kCompleted.
-// kCompleted: All data has been sent to the destination loader.
-class CONTENT_EXPORT MimeSniffingURLLoader
-    : public network::mojom::URLLoaderClient,
-      public network::mojom::URLLoader {
- public:
-  ~MimeSniffingURLLoader() override;
-
-  // Start waiting for the body.
-  void Start(
-      network::mojom::URLLoaderPtr source_url_loader,
-      network::mojom::URLLoaderClientRequest source_url_loader_client_request);
-
-  // network::mojom::URLLoaderPtr controls the lifetime of the loader.
-  static std::tuple<network::mojom::URLLoaderPtr,
-                    network::mojom::URLLoaderClientRequest,
-                    MimeSniffingURLLoader*>
-  CreateLoader(base::WeakPtr<MimeSniffingThrottle> throttle,
-               const GURL& response_url,
-               const network::ResourceResponseHead& response_head);
-
- private:
-  MimeSniffingURLLoader(
-      base::WeakPtr<MimeSniffingThrottle> throttle,
-      const GURL& response_url,
-      const network::ResourceResponseHead& response_head,
-      network::mojom::URLLoaderClientPtr destination_url_loader_client);
-
-  // network::mojom::URLLoaderClient implementation (called from the source of
-  // the response):
-  void OnReceiveResponse(
-      const network::ResourceResponseHead& response_head) override;
-  void OnReceiveRedirect(
-      const net::RedirectInfo& redirect_info,
-      const network::ResourceResponseHead& response_head) override;
-  void OnUploadProgress(int64_t current_position,
-                        int64_t total_size,
-                        OnUploadProgressCallback ack_callback) override;
-  void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override;
-  void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
-  void OnStartLoadingResponseBody(
-      mojo::ScopedDataPipeConsumerHandle body) override;
-  void OnComplete(const network::URLLoaderCompletionStatus& status) override;
-
-  // network::mojom::URLLoader implementation (called from the destination of
-  // the response):
-  void FollowRedirect(const base::Optional<std::vector<std::string>>&
-                          to_be_removed_request_headers,
-                      const base::Optional<net::HttpRequestHeaders>&
-                          modified_request_headers) override;
-  void ProceedWithResponse() override;
-  void SetPriority(net::RequestPriority priority,
-                   int32_t intra_priority_value) override;
-  void PauseReadingBodyFromNet() override;
-  void ResumeReadingBodyFromNet() override;
-
-  void OnBodyReadable(MojoResult);
-  void OnBodyWritable(MojoResult);
-  void CompleteSniffing();
-  void CompleteSending();
-  void SendReceivedBodyToClient();
-  void ForwardBodyToClient();
-
-  void Abort();
-
-  static const char kDefaultMimeType[];
-
-  base::WeakPtr<MimeSniffingThrottle> throttle_;
-
-  mojo::Binding<network::mojom::URLLoaderClient> source_url_client_binding_;
-  network::mojom::URLLoaderPtr source_url_loader_;
-  network::mojom::URLLoaderClientPtr destination_url_loader_client_;
-
-  GURL response_url_;
-
-  // Capture the response head to defer to send it to the destination until the
-  // mime type is decided.
-  network::ResourceResponseHead response_head_;
-
-  enum class State { kWaitForBody, kSniffing, kSending, kCompleted };
-  State state_ = State::kWaitForBody;
-
-  // Set if OnComplete() is called during sniffing.
-  base::Optional<network::URLLoaderCompletionStatus> complete_status_;
-
-  std::vector<char> buffered_body_;
-  size_t bytes_remaining_in_buffer_;
-
-  mojo::ScopedDataPipeConsumerHandle body_consumer_handle_;
-  mojo::ScopedDataPipeProducerHandle body_producer_handle_;
-  mojo::SimpleWatcher body_consumer_watcher_;
-  mojo::SimpleWatcher body_producer_watcher_;
-
-  DISALLOW_COPY_AND_ASSIGN(MimeSniffingURLLoader);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_COMMON_MIME_SNIFFING_URL_LOADER_H_
diff --git a/content/common/service_worker/service_worker_loader_helpers.cc b/content/common/service_worker/service_worker_loader_helpers.cc
index 431207de..b01b6825 100644
--- a/content/common/service_worker/service_worker_loader_helpers.cc
+++ b/content/common/service_worker/service_worker_loader_helpers.cc
@@ -64,11 +64,15 @@
       net::HttpUtil::AssembleRawHeaders(buf.c_str(), buf.size()));
 
   // Populate |out_head|'s MIME type with the value from the HTTP response
-  // headers.
+  // headers. If there is none, set a default value.
+  // TODO(crbug.com/771118): Make the MIME sniffer work for SW controlled page
+  // loads, so we don't need to set a simple default value.
   if (out_head->mime_type.empty()) {
     std::string mime_type;
-    if (out_head->headers->GetMimeType(&mime_type))
-      out_head->mime_type = mime_type;
+    out_head->headers->GetMimeType(&mime_type);
+    if (mime_type.empty())
+      mime_type = "text/plain";
+    out_head->mime_type = mime_type;
   }
 
   // Populate |out_head|'s charset with the value from the HTTP response
diff --git a/content/common/throttling_url_loader.cc b/content/common/throttling_url_loader.cc
index 7e49564..1a33248 100644
--- a/content/common/throttling_url_loader.cc
+++ b/content/common/throttling_url_loader.cc
@@ -44,14 +44,6 @@
     loader_->SetPriority(priority);
   }
 
-  void UpdateDeferredResponseHead(
-      const network::ResourceResponseHead& new_response_head) override {
-    if (!loader_)
-      return;
-    ScopedDelegateCall scoped_delegate_call(this);
-    loader_->UpdateDeferredResponseHead(new_response_head);
-  }
-
   void PauseReadingBodyFromNet() override {
     if (!loader_)
       return;
@@ -201,7 +193,7 @@
 void ThrottlingURLLoader::SetPriority(net::RequestPriority priority,
                                       int32_t intra_priority_value) {
   if (!url_loader_) {
-    if (!loader_completed_) {
+    if (!loader_cancelled_) {
       DCHECK_EQ(DEFERRED_START, deferred_stage_);
       priority_info_ =
           std::make_unique<PriorityInfo>(priority, intra_priority_value);
@@ -238,7 +230,7 @@
     network::ResourceRequest* url_request,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
-  DCHECK(!loader_completed_);
+  DCHECK(!loader_cancelled_);
 
   if (options & network::mojom::kURLLoadOptionSynchronous)
     is_synchronous_ = true;
@@ -302,7 +294,7 @@
                                                bool throttle_deferred,
                                                bool* should_defer) {
   DCHECK(!deferring_throttles_.count(throttle));
-  if (loader_completed_)
+  if (loader_cancelled_)
     return false;
   *should_defer |= throttle_deferred;
   if (throttle_deferred)
@@ -316,14 +308,14 @@
     return;
 
   deferring_throttles_.erase(throttle);
-  if (deferring_throttles_.empty() && !loader_completed_)
+  if (deferring_throttles_.empty() && !loader_cancelled_)
     Resume();
 }
 
 void ThrottlingURLLoader::OnReceiveResponse(
     const network::ResourceResponseHead& response_head) {
   DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
-  DCHECK(!loader_completed_);
+  DCHECK(!loader_cancelled_);
   DCHECK(deferring_throttles_.empty());
 
   if (!throttles_.empty()) {
@@ -352,7 +344,7 @@
     const net::RedirectInfo& redirect_info,
     const network::ResourceResponseHead& response_head) {
   DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
-  DCHECK(!loader_completed_);
+  DCHECK(!loader_cancelled_);
   DCHECK(deferring_throttles_.empty());
 
   if (!throttles_.empty()) {
@@ -394,7 +386,7 @@
     int64_t total_size,
     OnUploadProgressCallback ack_callback) {
   DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
-  DCHECK(!loader_completed_);
+  DCHECK(!loader_cancelled_);
 
   forwarding_client_->OnUploadProgress(current_position, total_size,
                                        std::move(ack_callback));
@@ -403,14 +395,14 @@
 void ThrottlingURLLoader::OnReceiveCachedMetadata(
     const std::vector<uint8_t>& data) {
   DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
-  DCHECK(!loader_completed_);
+  DCHECK(!loader_cancelled_);
 
   forwarding_client_->OnReceiveCachedMetadata(data);
 }
 
 void ThrottlingURLLoader::OnTransferSizeUpdated(int32_t transfer_size_diff) {
   DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
-  DCHECK(!loader_completed_);
+  DCHECK(!loader_cancelled_);
 
   forwarding_client_->OnTransferSizeUpdated(transfer_size_diff);
 }
@@ -418,7 +410,7 @@
 void ThrottlingURLLoader::OnStartLoadingResponseBody(
     mojo::ScopedDataPipeConsumerHandle body) {
   DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
-  DCHECK(!loader_completed_);
+  DCHECK(!loader_cancelled_);
 
   forwarding_client_->OnStartLoadingResponseBody(std::move(body));
 }
@@ -426,14 +418,12 @@
 void ThrottlingURLLoader::OnComplete(
     const network::URLLoaderCompletionStatus& status) {
   DCHECK_EQ(DEFERRED_NONE, deferred_stage_);
-  DCHECK(!loader_completed_);
+  DCHECK(!loader_cancelled_);
 
   // This is the last expected message. Pipe closure before this is an error
   // (see OnClientConnectionError). After this it is expected and should be
-  // ignored. The owner of |this| is expected to destroy |this| when
-  // OnComplete() and all data has been read. Destruction of |this| will
-  // destroy |url_loader_| appropriately.
-  loader_completed_ = true;
+  // ignored.
+  DisconnectClient(nullptr);
   forwarding_client_->OnComplete(status);
 }
 
@@ -447,7 +437,7 @@
 
 void ThrottlingURLLoader::CancelWithError(int error_code,
                                           base::StringPiece custom_reason) {
-  if (loader_completed_)
+  if (loader_cancelled_)
     return;
 
   network::URLLoaderCompletionStatus status;
@@ -460,7 +450,7 @@
 }
 
 void ThrottlingURLLoader::Resume() {
-  if (loader_completed_ || deferred_stage_ == DEFERRED_NONE)
+  if (loader_cancelled_ || deferred_stage_ == DEFERRED_NONE)
     return;
 
   auto prev_deferred_stage = deferred_stage_;
@@ -500,13 +490,6 @@
     url_loader_->SetPriority(priority, -1);
 }
 
-void ThrottlingURLLoader::UpdateDeferredResponseHead(
-    const network::ResourceResponseHead& new_response_head) {
-  DCHECK(response_info_);
-  DCHECK_EQ(DEFERRED_RESPONSE, deferred_stage_);
-  response_info_->response_head = new_response_head;
-}
-
 void ThrottlingURLLoader::PauseReadingBodyFromNet(URLLoaderThrottle* throttle) {
   if (pausing_reading_body_from_net_throttles_.empty() && url_loader_)
     url_loader_->PauseReadingBodyFromNet();
@@ -554,7 +537,7 @@
     url_loader_ = nullptr;
   }
 
-  loader_completed_ = true;
+  loader_cancelled_ = true;
 }
 
 ThrottlingURLLoader::ThrottleEntry::ThrottleEntry(
diff --git a/content/common/throttling_url_loader.h b/content/common/throttling_url_loader.h
index 7397d10..9fb0cdf 100644
--- a/content/common/throttling_url_loader.h
+++ b/content/common/throttling_url_loader.h
@@ -120,8 +120,6 @@
   void CancelWithError(int error_code, base::StringPiece custom_reason);
   void Resume();
   void SetPriority(net::RequestPriority priority);
-  void UpdateDeferredResponseHead(
-      const network::ResourceResponseHead& new_response_head);
   void PauseReadingBodyFromNet(URLLoaderThrottle* throttle);
   void ResumeReadingBodyFromNet(URLLoaderThrottle* throttle);
   void InterceptResponse(
@@ -140,7 +138,7 @@
     DEFERRED_RESPONSE
   };
   DeferredStage deferred_stage_ = DEFERRED_NONE;
-  bool loader_completed_ = false;
+  bool loader_cancelled_ = false;
   bool is_synchronous_ = false;
 
   struct ThrottleEntry {
diff --git a/content/public/common/url_loader_throttle.cc b/content/public/common/url_loader_throttle.cc
index 891164f..a919a363 100644
--- a/content/public/common/url_loader_throttle.cc
+++ b/content/public/common/url_loader_throttle.cc
@@ -9,8 +9,6 @@
 namespace content {
 
 void URLLoaderThrottle::Delegate::SetPriority(net::RequestPriority priority) {}
-void URLLoaderThrottle::Delegate::UpdateDeferredResponseHead(
-    const network::ResourceResponseHead& new_response_head) {}
 void URLLoaderThrottle::Delegate::PauseReadingBodyFromNet() {}
 void URLLoaderThrottle::Delegate::ResumeReadingBodyFromNet() {}
 
diff --git a/content/public/common/url_loader_throttle.h b/content/public/common/url_loader_throttle.h
index 5a263b53..37faba0 100644
--- a/content/public/common/url_loader_throttle.h
+++ b/content/public/common/url_loader_throttle.h
@@ -57,13 +57,6 @@
 
     virtual void SetPriority(net::RequestPriority priority);
 
-    // Updates the response head which is deferred to be sent. This method needs
-    // to be called when the response is deferred on
-    // URLLoaderThrottle::WillProcessResponse() and before calling
-    // Delegate::Resume().
-    virtual void UpdateDeferredResponseHead(
-        const network::ResourceResponseHead& new_response_head);
-
     // Pauses/resumes reading response body if the resource is fetched from
     // network.
     virtual void PauseReadingBodyFromNet();
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc
index 499fe2db..620ba63d 100644
--- a/content/public/test/mock_render_process_host.cc
+++ b/content/public/test/mock_render_process_host.cc
@@ -57,6 +57,7 @@
       child_identity_(mojom::kRendererServiceName,
                       BrowserContext::GetServiceUserIdFor(browser_context),
                       base::StringPrintf("%d", id_)),
+      url_loader_factory_(nullptr),
       weak_ptr_factory_(this) {
   // Child process security operations can't be unit tested unless we add
   // ourselves as an existing child process.
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 177147e..bce0c21 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -439,6 +439,8 @@
     "media/webrtc/webrtc_video_capturer_adapter.h",
     "media/webrtc/webrtc_video_frame_adapter.cc",
     "media/webrtc/webrtc_video_frame_adapter.h",
+    "media/webrtc/webrtc_video_utils.cc",
+    "media/webrtc/webrtc_video_utils.h",
     "media/webrtc_local_audio_source_provider.cc",
     "media/webrtc_local_audio_source_provider.h",
     "media/webrtc_logging.cc",
diff --git a/content/renderer/input/input_handler_manager_client.h b/content/renderer/input/input_handler_manager_client.h
index 6f91e63a3..7793a65 100644
--- a/content/renderer/input/input_handler_manager_client.h
+++ b/content/renderer/input/input_handler_manager_client.h
@@ -49,6 +49,7 @@
   // Otherwise |DidOverscroll| will be fired.
   virtual void DidOverscroll(int routing_id,
                              const ui::DidOverscrollParams& params) = 0;
+  virtual void DidStopFlinging(int routing_id) = 0;
   virtual void DidStartScrollingViewport(int routing_id) = 0;
   virtual void DispatchNonBlockingEventToMainThread(
       int routing_id,
diff --git a/content/renderer/loader/resource_dispatcher.cc b/content/renderer/loader/resource_dispatcher.cc
index 390de26..3d5bd290 100644
--- a/content/renderer/loader/resource_dispatcher.cc
+++ b/content/renderer/loader/resource_dispatcher.cc
@@ -22,7 +22,6 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "content/common/inter_process_time_ticks_converter.h"
-#include "content/common/mime_sniffing_throttle.h"
 #include "content/common/navigation_params.h"
 #include "content/common/net/record_load_histograms.h"
 #include "content/common/throttling_url_loader.h"
@@ -46,7 +45,6 @@
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/resource_response.h"
 #include "services/network/public/cpp/url_loader_completion_status.h"
-#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
 
 namespace content {
 
@@ -698,12 +696,10 @@
   uint32_t options = network::mojom::kURLLoadOptionNone;
   // TODO(jam): use this flag for ResourceDispatcherHost code path once
   // MojoLoading is the only IPC code path.
-  if ((blink::ServiceWorkerUtils::IsServicificationEnabled() ||
-       base::FeatureList::IsEnabled(network::features::kNetworkService)) &&
+  if (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
       request->fetch_request_context_type != REQUEST_CONTEXT_TYPE_FETCH) {
     // MIME sniffing should be disabled for a request initiated by fetch().
     options |= network::mojom::kURLLoadOptionSniffMimeType;
-    throttles.push_back(std::make_unique<MimeSniffingThrottle>());
   }
   if (is_sync) {
     options |= network::mojom::kURLLoadOptionSynchronous;
diff --git a/content/renderer/media/stream/media_stream_video_track.h b/content/renderer/media/stream/media_stream_video_track.h
index 09bc143..c46e29b 100644
--- a/content/renderer/media/stream/media_stream_video_track.h
+++ b/content/renderer/media/stream/media_stream_video_track.h
@@ -114,6 +114,8 @@
   friend class MediaStreamVideoSink;
   FRIEND_TEST_ALL_PREFIXES(MediaStreamRemoteVideoSourceTest, StartTrack);
   FRIEND_TEST_ALL_PREFIXES(MediaStreamRemoteVideoSourceTest, RemoteTrackStop);
+  FRIEND_TEST_ALL_PREFIXES(MediaStreamRemoteVideoSourceTest,
+                           PreservesColorSpace);
   FRIEND_TEST_ALL_PREFIXES(PepperToVideoTrackAdapterTest, PutFrame);
 
   // Add |sink| to receive state changes on the main render thread and video
diff --git a/content/renderer/media/webrtc/media_stream_remote_video_source.cc b/content/renderer/media/webrtc/media_stream_remote_video_source.cc
index 0e810df..a3869e8 100644
--- a/content/renderer/media/webrtc/media_stream_remote_video_source.cc
+++ b/content/renderer/media/webrtc/media_stream_remote_video_source.cc
@@ -13,6 +13,7 @@
 #include "base/trace_event/trace_event.h"
 #include "content/renderer/media/webrtc/track_observer.h"
 #include "content/renderer/media/webrtc/webrtc_video_frame_adapter.h"
+#include "content/renderer/media/webrtc/webrtc_video_utils.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/timestamp_constants.h"
 #include "media/base/video_frame.h"
@@ -22,25 +23,6 @@
 
 namespace content {
 
-namespace {
-
-media::VideoRotation WebRTCToMediaVideoRotation(
-    webrtc::VideoRotation rotation) {
-  switch (rotation) {
-    case webrtc::kVideoRotation_0:
-      return media::VIDEO_ROTATION_0;
-    case webrtc::kVideoRotation_90:
-      return media::VIDEO_ROTATION_90;
-    case webrtc::kVideoRotation_180:
-      return media::VIDEO_ROTATION_180;
-    case webrtc::kVideoRotation_270:
-      return media::VIDEO_ROTATION_270;
-  }
-  return media::VIDEO_ROTATION_0;
-}
-
-}  // anonymous namespace
-
 // Internal class used for receiving frames from the webrtc track on a
 // libjingle thread and forward it to the IO-thread.
 class MediaStreamRemoteVideoSource::RemoteVideoSourceDelegate
@@ -192,7 +174,13 @@
   if (incoming_frame.rotation() != webrtc::kVideoRotation_0) {
     video_frame->metadata()->SetRotation(
         media::VideoFrameMetadata::ROTATION,
-        WebRTCToMediaVideoRotation(incoming_frame.rotation()));
+        WebRtcToMediaVideoRotation(incoming_frame.rotation()));
+  }
+
+  if (incoming_frame.color_space().has_value()) {
+    video_frame->set_color_space(
+        WebRtcToMediaVideoColorSpace(incoming_frame.color_space().value())
+            .ToGfxColorSpace());
   }
 
   // Run render smoothness algorithm only when we don't have to render
diff --git a/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc b/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc
index e721651..89c42fff3 100644
--- a/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc
+++ b/content/renderer/media/webrtc/media_stream_remote_video_source_unittest.cc
@@ -22,7 +22,9 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/blink/public/web/web_heap.h"
+#include "third_party/webrtc/api/video/color_space.h"
 #include "third_party/webrtc/api/video/i420_buffer.h"
+#include "ui/gfx/color_space.h"
 
 namespace content {
 
@@ -37,6 +39,7 @@
       std::unique_ptr<TrackObserver> observer)
       : MediaStreamRemoteVideoSource(std::move(observer)) {}
   using MediaStreamRemoteVideoSource::SinkInterfaceForTesting;
+  using MediaStreamRemoteVideoSource::StartSourceImpl;
 };
 
 class MediaStreamRemoteVideoSourceTest
@@ -196,4 +199,39 @@
   track->RemoveSink(&sink);
 }
 
+TEST_F(MediaStreamRemoteVideoSourceTest, PreservesColorSpace) {
+  std::unique_ptr<MediaStreamVideoTrack> track(CreateTrack());
+  MockMediaStreamVideoSink sink;
+  track->AddSink(&sink, sink.GetDeliverFrameCB(), false);
+
+  base::RunLoop run_loop;
+  EXPECT_CALL(sink, OnVideoFrame())
+      .WillOnce(RunClosure(run_loop.QuitClosure()));
+  rtc::scoped_refptr<webrtc::I420Buffer> buffer(
+      new rtc::RefCountedObject<webrtc::I420Buffer>(320, 240));
+  webrtc::ColorSpace kColorSpace(webrtc::ColorSpace::PrimaryID::kSMPTE240M,
+                                 webrtc::ColorSpace::TransferID::kSMPTE240M,
+                                 webrtc::ColorSpace::MatrixID::kSMPTE240M,
+                                 webrtc::ColorSpace::RangeID::kLimited);
+  const webrtc::VideoFrame& input_frame =
+      webrtc::VideoFrame::Builder()
+          .set_video_frame_buffer(buffer)
+          .set_timestamp_ms(0)
+          .set_rotation(webrtc::kVideoRotation_0)
+          .set_color_space(kColorSpace)
+          .build();
+  source()->SinkInterfaceForTesting()->OnFrame(input_frame);
+  run_loop.Run();
+
+  EXPECT_EQ(1, sink.number_of_frames());
+  scoped_refptr<media::VideoFrame> output_frame = sink.last_frame();
+  EXPECT_TRUE(output_frame);
+  EXPECT_TRUE(output_frame->ColorSpace() ==
+              gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTE240M,
+                              gfx::ColorSpace::TransferID::SMPTE240M,
+                              gfx::ColorSpace::MatrixID::SMPTE240M,
+                              gfx::ColorSpace::RangeID::LIMITED));
+  track->RemoveSink(&sink);
+}
+
 }  // namespace content
diff --git a/content/renderer/media/webrtc/webrtc_video_utils.cc b/content/renderer/media/webrtc/webrtc_video_utils.cc
new file mode 100644
index 0000000..0c7662f4
--- /dev/null
+++ b/content/renderer/media/webrtc/webrtc_video_utils.cc
@@ -0,0 +1,177 @@
+// 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/webrtc_video_utils.h"
+
+namespace content {
+
+media::VideoRotation WebRtcToMediaVideoRotation(
+    webrtc::VideoRotation rotation) {
+  switch (rotation) {
+    case webrtc::kVideoRotation_0:
+      return media::VIDEO_ROTATION_0;
+    case webrtc::kVideoRotation_90:
+      return media::VIDEO_ROTATION_90;
+    case webrtc::kVideoRotation_180:
+      return media::VIDEO_ROTATION_180;
+    case webrtc::kVideoRotation_270:
+      return media::VIDEO_ROTATION_270;
+  }
+  return media::VIDEO_ROTATION_0;
+}
+
+media::VideoColorSpace WebRtcToMediaVideoColorSpace(
+    const webrtc::ColorSpace& color_space) {
+  media::VideoColorSpace::PrimaryID primaries =
+      media::VideoColorSpace::PrimaryID::INVALID;
+  switch (color_space.primaries()) {
+    case webrtc::ColorSpace::PrimaryID::kBT709:
+      primaries = media::VideoColorSpace::PrimaryID::BT709;
+      break;
+    case webrtc::ColorSpace::PrimaryID::kBT470M:
+      primaries = media::VideoColorSpace::PrimaryID::BT470M;
+      break;
+    case webrtc::ColorSpace::PrimaryID::kBT470BG:
+      primaries = media::VideoColorSpace::PrimaryID::BT470BG;
+      break;
+    case webrtc::ColorSpace::PrimaryID::kSMPTE170M:
+      primaries = media::VideoColorSpace::PrimaryID::SMPTE170M;
+      break;
+    case webrtc::ColorSpace::PrimaryID::kSMPTE240M:
+      primaries = media::VideoColorSpace::PrimaryID::SMPTE240M;
+      break;
+    case webrtc::ColorSpace::PrimaryID::kFILM:
+      primaries = media::VideoColorSpace::PrimaryID::FILM;
+      break;
+    case webrtc::ColorSpace::PrimaryID::kBT2020:
+      primaries = media::VideoColorSpace::PrimaryID::BT2020;
+      break;
+    case webrtc::ColorSpace::PrimaryID::kSMPTEST428:
+      primaries = media::VideoColorSpace::PrimaryID::SMPTEST428_1;
+      break;
+    case webrtc::ColorSpace::PrimaryID::kSMPTEST431:
+      primaries = media::VideoColorSpace::PrimaryID::SMPTEST431_2;
+      break;
+    case webrtc::ColorSpace::PrimaryID::kSMPTEST432:
+      primaries = media::VideoColorSpace::PrimaryID::SMPTEST432_1;
+      break;
+    case webrtc::ColorSpace::PrimaryID::kJEDECP22:
+      primaries = media::VideoColorSpace::PrimaryID::EBU_3213_E;
+      break;
+    case webrtc::ColorSpace::PrimaryID::kInvalid:
+    default:
+      break;
+  }
+
+  media::VideoColorSpace::TransferID transfer =
+      media::VideoColorSpace::TransferID::INVALID;
+  switch (color_space.transfer()) {
+    case webrtc::ColorSpace::TransferID::kBT709:
+      transfer = media::VideoColorSpace::TransferID::BT709;
+      break;
+    case webrtc::ColorSpace::TransferID::kGAMMA22:
+      transfer = media::VideoColorSpace::TransferID::GAMMA22;
+      break;
+    case webrtc::ColorSpace::TransferID::kGAMMA28:
+      transfer = media::VideoColorSpace::TransferID::GAMMA28;
+      break;
+    case webrtc::ColorSpace::TransferID::kSMPTE170M:
+      transfer = media::VideoColorSpace::TransferID::SMPTE170M;
+      break;
+    case webrtc::ColorSpace::TransferID::kSMPTE240M:
+      transfer = media::VideoColorSpace::TransferID::SMPTE240M;
+      break;
+    case webrtc::ColorSpace::TransferID::kLINEAR:
+      transfer = media::VideoColorSpace::TransferID::LINEAR;
+      break;
+    case webrtc::ColorSpace::TransferID::kLOG:
+      transfer = media::VideoColorSpace::TransferID::LOG;
+      break;
+    case webrtc::ColorSpace::TransferID::kLOG_SQRT:
+      transfer = media::VideoColorSpace::TransferID::LOG_SQRT;
+      break;
+    case webrtc::ColorSpace::TransferID::kIEC61966_2_4:
+      transfer = media::VideoColorSpace::TransferID::IEC61966_2_4;
+      break;
+    case webrtc::ColorSpace::TransferID::kBT1361_ECG:
+      transfer = media::VideoColorSpace::TransferID::BT1361_ECG;
+      break;
+    case webrtc::ColorSpace::TransferID::kIEC61966_2_1:
+      transfer = media::VideoColorSpace::TransferID::IEC61966_2_1;
+      break;
+    case webrtc::ColorSpace::TransferID::kBT2020_10:
+      transfer = media::VideoColorSpace::TransferID::BT2020_10;
+      break;
+    case webrtc::ColorSpace::TransferID::kBT2020_12:
+      transfer = media::VideoColorSpace::TransferID::BT2020_12;
+      break;
+    case webrtc::ColorSpace::TransferID::kSMPTEST2084:
+      transfer = media::VideoColorSpace::TransferID::SMPTEST2084;
+      break;
+    case webrtc::ColorSpace::TransferID::kSMPTEST428:
+      transfer = media::VideoColorSpace::TransferID::SMPTEST428_1;
+      break;
+    case webrtc::ColorSpace::TransferID::kARIB_STD_B67:
+      transfer = media::VideoColorSpace::TransferID::ARIB_STD_B67;
+      break;
+    case webrtc::ColorSpace::TransferID::kInvalid:
+    default:
+      break;
+  }
+
+  media::VideoColorSpace::MatrixID matrix =
+      media::VideoColorSpace::MatrixID::INVALID;
+  switch (color_space.matrix()) {
+    case webrtc::ColorSpace::MatrixID::kRGB:
+      matrix = media::VideoColorSpace::MatrixID::RGB;
+      break;
+    case webrtc::ColorSpace::MatrixID::kBT709:
+      matrix = media::VideoColorSpace::MatrixID::BT709;
+      break;
+    case webrtc::ColorSpace::MatrixID::kFCC:
+      matrix = media::VideoColorSpace::MatrixID::FCC;
+      break;
+    case webrtc::ColorSpace::MatrixID::kBT470BG:
+      matrix = media::VideoColorSpace::MatrixID::BT470BG;
+      break;
+    case webrtc::ColorSpace::MatrixID::kSMPTE170M:
+      matrix = media::VideoColorSpace::MatrixID::SMPTE170M;
+      break;
+    case webrtc::ColorSpace::MatrixID::kSMPTE240M:
+      matrix = media::VideoColorSpace::MatrixID::SMPTE240M;
+      break;
+    case webrtc::ColorSpace::MatrixID::kYCOCG:
+      matrix = media::VideoColorSpace::MatrixID::YCOCG;
+      break;
+    case webrtc::ColorSpace::MatrixID::kBT2020_NCL:
+      matrix = media::VideoColorSpace::MatrixID::BT2020_NCL;
+      break;
+    case webrtc::ColorSpace::MatrixID::kBT2020_CL:
+      matrix = media::VideoColorSpace::MatrixID::BT2020_CL;
+      break;
+    case webrtc::ColorSpace::MatrixID::kSMPTE2085:
+      matrix = media::VideoColorSpace::MatrixID::YDZDX;
+      break;
+    case webrtc::ColorSpace::MatrixID::kInvalid:
+    default:
+      break;
+  }
+
+  gfx::ColorSpace::RangeID range = gfx::ColorSpace::RangeID::INVALID;
+  switch (color_space.range()) {
+    case webrtc::ColorSpace::RangeID::kLimited:
+      range = gfx::ColorSpace::RangeID::LIMITED;
+      break;
+    case webrtc::ColorSpace::RangeID::kFull:
+      range = gfx::ColorSpace::RangeID::FULL;
+      break;
+    case webrtc::ColorSpace::RangeID::kInvalid:
+    default:
+      break;
+  }
+
+  return media::VideoColorSpace(primaries, transfer, matrix, range);
+}
+
+}  // namespace content
diff --git a/content/renderer/media/webrtc/webrtc_video_utils.h b/content/renderer/media/webrtc/webrtc_video_utils.h
new file mode 100644
index 0000000..1d91b2a4
--- /dev/null
+++ b/content/renderer/media/webrtc/webrtc_video_utils.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_RENDERER_MEDIA_WEBRTC_WEBRTC_VIDEO_UTILS_H_
+#define CONTENT_RENDERER_MEDIA_WEBRTC_WEBRTC_VIDEO_UTILS_H_
+
+#include "media/base/video_color_space.h"
+#include "media/base/video_rotation.h"
+#include "third_party/webrtc/api/video/color_space.h"
+#include "third_party/webrtc/api/video/video_rotation.h"
+
+namespace content {
+
+// This file has helper methods for conversion between chromium types and
+// webrtc/api/video types.
+
+media::VideoRotation WebRtcToMediaVideoRotation(webrtc::VideoRotation rotation);
+
+media::VideoColorSpace WebRtcToMediaVideoColorSpace(
+    const webrtc::ColorSpace& color_space);
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_MEDIA_WEBRTC_WEBRTC_VIDEO_UTILS_H_
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 413b97c3..e754e7e 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1603,7 +1603,6 @@
     "../common/mac/attributed_string_coder_unittest.mm",
     "../common/manifest_util_unittest.cc",
     "../common/media/media_devices_unittest.cc",
-    "../common/mime_sniffing_throttle_unittest.cc",
     "../common/notifications/notification_struct_traits_unittest.cc",
     "../common/origin_util_unittest.cc",
     "../common/page_state_serialization_unittest.cc",
diff --git a/content/test/data/accessibility/aria/dpub-roles-expected-auralinux.txt b/content/test/data/accessibility/aria/dpub-roles-expected-auralinux.txt
index 37d27c82..e0e10c8 100644
--- a/content/test/data/accessibility/aria/dpub-roles-expected-auralinux.txt
+++ b/content/test/data/accessibility/aria/dpub-roles-expected-auralinux.txt
@@ -1,40 +1,40 @@
-[document web] enabled focusable focused<newline>
-++[section] name='doc-abstract' enabled<newline>
-++[landmark] name='doc-acknowledgments' enabled<newline>
-++[landmark] name='doc-afterword' enabled<newline>
-++[landmark] name='doc-appendix' enabled<newline>
-++[link] name='doc-backlink' enabled<newline>
-++[list item] name='doc-biblioentry' enabled<newline>
-++[landmark] name='doc-bibliography' enabled<newline>
-++[link] name='doc-biblioref' enabled<newline>
-++[landmark] name='doc-chapter' enabled<newline>
-++[section] name='doc-colophon' enabled<newline>
-++[landmark] name='doc-conclusion' enabled<newline>
-++[image] name='doc-cover' enabled<newline>
-++[section] name='doc-credit' enabled<newline>
-++[landmark] name='doc-credits' enabled<newline>
-++[section] name='doc-dedication' enabled<newline>
-++[list item] name='doc-endnote' enabled<newline>
-++[landmark] name='doc-endnotes' enabled<newline>
-++[section] name='doc-epigraph' enabled<newline>
-++[landmark] name='doc-epilogue' enabled<newline>
-++[landmark] name='doc-errata' enabled<newline>
-++[section] name='doc-example' enabled<newline>
-++[footnote] name='doc-footnote' enabled<newline>
-++[landmark] name='doc-foreword' enabled<newline>
-++[landmark] name='doc-glossary' enabled<newline>
-++[link] name='doc-glossref' enabled<newline>
-++[landmark] name='doc-index' enabled<newline>
-++[landmark] name='doc-introduction' enabled<newline>
-++[link] name='doc-noteref' enabled<newline>
-++[comment] name='doc-notice' enabled<newline>
-++[separator] name='doc-pagebreak' enabled<newline>
-++[landmark] name='doc-pagelist' enabled<newline>
-++[landmark] name='doc-part' enabled<newline>
-++[landmark] name='doc-preface' enabled<newline>
-++[landmark] name='doc-prologue' enabled<newline>
-++[section] name='doc-pullquote' enabled<newline>
-++[section] name='doc-qna' enabled<newline>
-++[heading] name='doc-subtitle' enabled<newline>
-++[comment] name='doc-tip' enabled<newline>
-++[landmark] name='doc-toc' enabled<newline>
+[document web] enabled focusable focused sensitive showing visible<newline>
+++[section] name='doc-abstract' enabled sensitive showing visible<newline>
+++[landmark] name='doc-acknowledgments' enabled sensitive showing visible<newline>
+++[landmark] name='doc-afterword' enabled sensitive showing visible<newline>
+++[landmark] name='doc-appendix' enabled sensitive showing visible<newline>
+++[link] name='doc-backlink' enabled sensitive showing visible<newline>
+++[list item] name='doc-biblioentry' enabled sensitive showing visible<newline>
+++[landmark] name='doc-bibliography' enabled sensitive showing visible<newline>
+++[link] name='doc-biblioref' enabled sensitive showing visible<newline>
+++[landmark] name='doc-chapter' enabled sensitive showing visible<newline>
+++[section] name='doc-colophon' enabled sensitive showing visible<newline>
+++[landmark] name='doc-conclusion' enabled sensitive showing visible<newline>
+++[image] name='doc-cover' enabled sensitive showing visible<newline>
+++[section] name='doc-credit' enabled sensitive showing visible<newline>
+++[landmark] name='doc-credits' enabled sensitive showing visible<newline>
+++[section] name='doc-dedication' enabled sensitive showing visible<newline>
+++[list item] name='doc-endnote' enabled sensitive showing visible<newline>
+++[landmark] name='doc-endnotes' enabled sensitive showing visible<newline>
+++[section] name='doc-epigraph' enabled sensitive showing visible<newline>
+++[landmark] name='doc-epilogue' enabled sensitive showing visible<newline>
+++[landmark] name='doc-errata' enabled sensitive showing visible<newline>
+++[section] name='doc-example' enabled sensitive showing visible<newline>
+++[footnote] name='doc-footnote' enabled sensitive showing visible<newline>
+++[landmark] name='doc-foreword' enabled sensitive showing visible<newline>
+++[landmark] name='doc-glossary' enabled sensitive showing visible<newline>
+++[link] name='doc-glossref' enabled sensitive showing visible<newline>
+++[landmark] name='doc-index' enabled sensitive showing visible<newline>
+++[landmark] name='doc-introduction' enabled sensitive showing visible<newline>
+++[link] name='doc-noteref' enabled sensitive showing visible<newline>
+++[comment] name='doc-notice' enabled sensitive showing visible<newline>
+++[separator] name='doc-pagebreak' enabled sensitive showing visible<newline>
+++[landmark] name='doc-pagelist' enabled sensitive showing visible<newline>
+++[landmark] name='doc-part' enabled sensitive showing visible<newline>
+++[landmark] name='doc-preface' enabled sensitive showing visible<newline>
+++[landmark] name='doc-prologue' enabled sensitive showing visible<newline>
+++[section] name='doc-pullquote' enabled sensitive showing visible<newline>
+++[section] name='doc-qna' enabled sensitive showing visible<newline>
+++[heading] name='doc-subtitle' enabled sensitive showing visible<newline>
+++[comment] name='doc-tip' enabled sensitive showing visible<newline>
+++[landmark] name='doc-toc' enabled sensitive showing visible<newline>
diff --git a/content/test/data/accessibility/aria/graphics-roles-expected-auralinux.txt b/content/test/data/accessibility/aria/graphics-roles-expected-auralinux.txt
index 77b11860..9372606f 100644
--- a/content/test/data/accessibility/aria/graphics-roles-expected-auralinux.txt
+++ b/content/test/data/accessibility/aria/graphics-roles-expected-auralinux.txt
@@ -1,4 +1,4 @@
-[document web] enabled focusable focused<newline>
-++[document web] name='graphics-document' enabled<newline>
-++[panel] name='graphics-object' enabled<newline>
-++[image] name='graphics-symbol' enabled<newline>
+[document web] enabled focusable focused sensitive showing visible<newline>
+++[document web] name='graphics-document' enabled sensitive showing visible<newline>
+++[panel] name='graphics-object' enabled sensitive showing visible<newline>
+++[image] name='graphics-symbol' enabled sensitive showing visible<newline>
diff --git a/content/test/data/accessibility/html/a-expected-auralinux.txt b/content/test/data/accessibility/html/a-expected-auralinux.txt
index 4879349..cb5e5d3a 100644
--- a/content/test/data/accessibility/html/a-expected-auralinux.txt
+++ b/content/test/data/accessibility/html/a-expected-auralinux.txt
@@ -1,4 +1,4 @@
-[document web] enabled focusable focused<newline>
-++[panel] enabled<newline>
-++++[link] name='normal link' enabled focusable<newline>
-++++++[text] name='normal link' enabled<newline>
+[document web] enabled focusable focused sensitive showing visible<newline>
+++[panel] enabled sensitive showing visible<newline>
+++++[link] name='normal link' enabled focusable sensitive showing visible<newline>
+++++++[text] name='normal link' enabled sensitive showing visible<newline>
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index 16eb9d60..af2d4afd 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -57,6 +57,8 @@
         ['win', 'mac', 'linux', 'android'])
     self.Skip('WebglExtension_EXT_disjoint_timer_query',
         ['android'], bug=808744)
+    self.Fail('WebglExtension_EXT_disjoint_timer_query',
+        ['linux', 'intel'], bug=867675)
 
     # Extensions not available under D3D9
     self.Fail('WebglExtension_EXT_sRGB',
diff --git a/content/test/gpu/ipg_utils.py b/content/test/gpu/ipg_utils.py
new file mode 100644
index 0000000..749ea070
--- /dev/null
+++ b/content/test/gpu/ipg_utils.py
@@ -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.
+
+"""This script implements a few IntelPowerGadget related helper functions.
+
+This script only works on Windows with Intel CPU. Intel Power Gadget needs to
+be installed on the machine before this script works. The software can be
+downloaded from:
+  https://software.intel.com/en-us/articles/intel-power-gadget-20
+
+An easy way to use the APIs are:
+1) Launch your program.
+2) Call RunIPG() with no args. It will automatically locate the IPG installed
+   on the machine.
+3) Call AnalyzeIPGLogFile() with no args. It will analyze the default IPG log
+   file, which is PowerLog.csv at current dir; then it will print out the power
+   usage summary. If you want to skip a few seconds of the power log data, say,
+   5 seconds, call AnalyzeIPGLogFile(skip_in_sec=5).
+"""
+
+import logging
+import os
+import subprocess
+import datetime
+
+def LocateIPG():
+  ipg_dir = os.getenv('IPG_Dir')
+  if not ipg_dir:
+    logging.warning("No env IPG_Dir")
+    return None
+  gadget_path = os.path.join(ipg_dir, "PowerLog3.0.exe")
+  logging.debug("Try to locale Intel Power Gadget at " + gadget_path)
+  if os.path.isfile(gadget_path):
+    logging.debug("Intel Power Gadget Found")
+    return gadget_path
+  return None
+
+def GenerateIPGLogFilename(prefix='PowerLog', dir=None, current_run=1,
+                           total_runs=1, timestamp=False):
+  # If all args take default value, it is the IPG's default log path.
+  dir = dir or os.getcwd()
+  dir = os.path.abspath(dir)
+  if total_runs > 1:
+    prefix = "%s_%d_%d" % (prefix, current_run, total_runs)
+  if timestamp:
+    now = datetime.datetime.now()
+    prefix = "%s_%s" % (prefix, now.strftime('%Y%m%d%H%M%S'))
+  return os.path.join(dir, prefix + '.csv')
+
+def RunIPG(duration_in_s=60, resolution_in_ms=100, logfile=None):
+  intel_power_gadget_path = LocateIPG()
+  if not intel_power_gadget_path:
+    logging.warning("Can't locate Intel Power Gadget")
+    return
+  command = ('"%s" -duration %d -resolution %d' %
+             (intel_power_gadget_path, duration_in_s, resolution_in_ms))
+  if not logfile:
+    # It is not necessary but allows to print out the log path for debugging.
+    logfile = GenerateIPGLogFilename();
+  command = command + (' -file %s' %logfile)
+  logging.debug("Running: " + command)
+  try:
+    output = subprocess.check_output(command)
+    logging.debug("Running: DONE")
+    logging.debug(output)
+  except subprocess.CalledProcessError as err:
+    logging.warning(err)
+
+def AnalyzeIPGLogFile(logfile=None, skip_in_sec=0):
+  if not logfile:
+    logfile = GenerateIPGLogFilename()
+  if not os.path.isfile(logfile):
+    logging.warning("Can't locate logfile at " + logfile)
+    return {}
+  first_line = True
+  samples = 0
+  cols = 0
+  indices = []
+  labels = []
+  sums = []
+  col_time = None
+  for line in open(logfile):
+    tokens = line.split(',')
+    if first_line:
+      first_line = False
+      cols = len(tokens)
+      for ii in range(0, cols):
+        if tokens[ii].startswith('Elapsed Time'):
+          col_time = ii;
+        elif tokens[ii].endswith('(Watt)'):
+          indices.append(ii)
+          labels.append(tokens[ii][:-len('(Watt)')])
+          sums.append(0.0)
+      assert col_time
+      assert cols > 0
+      assert len(indices) > 0
+      continue
+    if len(tokens) != cols:
+      continue
+    if skip_in_sec > 0 and float(tokens[col_time]) < skip_in_sec:
+      continue
+    samples += 1
+    for ii in range(0, len(indices)):
+      index = indices[ii]
+      sums[ii] += float(tokens[index])
+  results = {'samples': samples}
+  if samples > 0:
+    for ii in range(0, len(indices)):
+      results[labels[ii]] = sums[ii] / samples
+  return results
diff --git a/content/test/gpu/measure_power_win_intel.py b/content/test/gpu/measure_power_win_intel.py
new file mode 100644
index 0000000..505ac52
--- /dev/null
+++ b/content/test/gpu/measure_power_win_intel.py
@@ -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.
+
+"""This script runs power measurements for browsers using Intel Power Gadget.
+
+This script only works on Windows with Intel CPU. Intel Power Gadget needs to
+be installed on the machine before this script works. The software can be
+downloaded from:
+  https://software.intel.com/en-us/articles/intel-power-gadget-20
+
+Sample runs:
+
+python measure_power_win_intel.py --browser=canary --duration=10 --delay=5
+  --verbose --url="https://www.youtube.com/watch?v=0XdS37Re1XQ"
+  --extra-browser-args="--no-sandbox --disable-features=UseSurfaceLayerForVideo"
+"""
+
+import ipg_utils
+import logging
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+import time
+import optparse
+
+CHROME_STABLE_PATH = (
+  "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe")
+CHROME_BETA_PATH = (
+  "C:\Program Files (x86)\Google\Chrome Beta\Application\chrome.exe")
+CHROME_DEV_PATH = (
+  "C:\Program Files (x86)\Google\Chrome Dev\Application\chrome.exe")
+# The following two paths are relative to the LOCALAPPDATA
+CHROME_CANARY_PATH = "Google\Chrome SxS\Application\chrome.exe"
+CHROMIUM_PATH = "Chromium\Application\chrome.exe"
+
+SUPPORTED_BROWSERS = ['stable', 'beta', 'dev', 'canary', 'chromium']
+
+def LocateBrowser(options_browser):
+  browser = None
+  if not options_browser or options_browser == 'stable':
+    browser = CHROME_STABLE_PATH
+  elif options_browser == 'beta':
+    browser = CHROME_BETA_PATH
+  elif options_browser == 'dev':
+    browser = CHROME_DEV_PATH
+  elif options_browser == 'canary':
+    browser = os.path.join(os.getenv('LOCALAPPDATA'), CHROME_CANARY_PATH)
+  elif options_browser == 'chromium':
+    browser = os.path.join(os.getenv('LOCALAPPDATA'), CHROMIUM_PATH)
+  elif options_browser.endswith(".exe"):
+    browser = options_browser
+  else:
+    logging.warning("Invalid value for --browser")
+    logging.warning(
+      "Supported values: %s, or a full path to a browser executable." %
+      ", ".join(SUPPORTED_BROWSERS))
+    return None
+  if not os.path.exists(browser):
+    logging.warning("Can't locate browser at " + browser)
+    logging.warning("Please pass full path to the executable in --browser")
+    return None
+  return browser
+
+def LaunchBrowser(browser, user_data_dir, url, extra_browser_args):
+  args = []
+  args.append(browser)
+  if url:
+    args.append(url)
+  if browser.endswith("chrome.exe"):
+    args.append('--user-data-dir=%s' % user_data_dir)
+    args.append('--no-first-run')
+    args.append('--no-default-browser-check')
+    args.append('--autoplay-policy=no-user-gesture-required')
+    if extra_browser_args:
+      args.extend(extra_browser_args.split(' '))
+  logging.debug(" ".join(args))
+  browser_proc = subprocess.Popen(args)
+  return browser_proc
+
+def MeasurePowerOnce(browser, logfile, duration, delay, resolution, url,
+                     extra_browser_args):
+  logging.debug("Logging into " + logfile)
+  user_data_dir = tempfile.mkdtemp()
+  browser_proc = LaunchBrowser(browser, user_data_dir, url, extra_browser_args)
+  ipg_utils.RunIPG(duration + delay, resolution, logfile)
+  browser_proc.kill()
+  for _ in range(100):
+    if browser_proc.poll() is not None:
+      break
+    logging.debug("Waiting for browser to exit")
+    time.sleep(0.05)
+  try:
+    shutil.rmtree(user_data_dir)
+  except Exception as err:
+    logging.warning("Failed to remove temporary folder: " + user_data_dir)
+    logging.warning("Please kill browser and remove it manually to avoid leak")
+  results = ipg_utils.AnalyzeIPGLogFile(logfile, delay)
+  return results
+
+
+def main(argv):
+  parser = optparse.OptionParser()
+  parser.add_option("--browser",
+                    help=("select which browser to run. Options include: " +
+                          ", ".join(SUPPORTED_BROWSERS) +
+                          ", or a full path to a browser executable. " +
+                          "By default, stable is selected."))
+  parser.add_option("--duration", default=60, type="int",
+                    help="specify how many seconds Intel Power Gadget "
+                    "measures. By default, 60 seconds is selected.")
+  parser.add_option("--delay", default=10, type="int",
+                    help="specify how many seconds we skip in the data "
+                    "Intel Power Gadget collects. This time is for starting "
+                    "video play, switching to fullscreen mode, etc. "
+                    "By default, 10 seconds is selected.")
+  parser.add_option("--resolution", default=100, type="int",
+                    help="specify how often Intel Power Gadget samples "
+                    "data in milliseconds. By default, 100 ms is selected.")
+  parser.add_option("--logdir",
+                    help="specify where Intel Power Gadget stores its log."
+                    "By default, it is the current path.")
+  parser.add_option("--logname",
+                    help="specify the prefix for Intel Power Gadget log "
+                    "filename. By default, it is PowerLog.")
+  parser.add_option("-v", "--verbose", action="store_true", default=False,
+                    help="print out debug information.")
+  parser.add_option("--repeat", default=1, type="int",
+                    help="specify how many times to run the measurements.")
+  parser.add_option("--url",
+                    help="specify the webpage URL the browser launches with.")
+  parser.add_option("--extra-browser-args", dest="extra_browser_args",
+                    help="specify extra commandline switches for the browser "
+                    "that are separated by ' '.")
+  # TODO(zmo): add an option --start-fullscreen
+  (options, _) = parser.parse_args(args=argv)
+  if options.verbose:
+    logging.basicConfig(level=logging.DEBUG)
+
+  browser = LocateBrowser(options.browser)
+  if not browser:
+    return
+
+  # TODO(zmo): Add code to disable a bunch of Windows services that might
+  # affect power consumption.
+
+  log_prefix = options.logname or 'PowerLog'
+
+  for run in range(0, options.repeat):
+    logfile = ipg_utils.GenerateIPGLogFilename(log_prefix, options.logdir,
+                                               run, options.repeat, True)
+    logging.info("Iteration #%d out of %d" % (run, options.repeat))
+    results = MeasurePowerOnce(browser, logfile, options.duration,
+                               options.delay, options.resolution, options.url,
+                               options.extra_browser_args)
+    logging.info(results)
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/content/test/proxy_service_mojo_unittest.cc b/content/test/proxy_service_mojo_unittest.cc
index 490b63d7..ece1669f 100644
--- a/content/test/proxy_service_mojo_unittest.cc
+++ b/content/test/proxy_service_mojo_unittest.cc
@@ -158,12 +158,11 @@
 TEST_F(ProxyServiceMojoTest, Basic) {
   net::ProxyInfo info;
   net::TestCompletionCallback callback;
+  std::unique_ptr<net::ProxyResolutionService::Request> request;
   EXPECT_EQ(net::ERR_IO_PENDING,
             proxy_resolution_service_->ResolveProxy(
-                GURL("http://foo"),
-                std::string(),
-                &info, callback.callback(), nullptr,
-                nullptr, net::NetLogWithSource()));
+                GURL("http://foo"), std::string(), &info, callback.callback(),
+                &request, nullptr, net::NetLogWithSource()));
 
   // PAC file fetcher should have a fetch triggered by the first
   // |ResolveProxy()| request.
@@ -181,11 +180,11 @@
   net::ProxyInfo info;
   net::TestCompletionCallback callback;
   net::BoundTestNetLog test_net_log;
+  std::unique_ptr<net::ProxyResolutionService::Request> request;
   EXPECT_EQ(net::ERR_IO_PENDING,
             proxy_resolution_service_->ResolveProxy(
-                GURL("http://foo"), std::string(),
-                &info, callback.callback(), nullptr,
-                nullptr, test_net_log.bound()));
+                GURL("http://foo"), std::string(), &info, callback.callback(),
+                &request, nullptr, test_net_log.bound()));
 
   // PAC file fetcher should have a fetch triggered by the first
   // |ResolveProxy()| request.
@@ -214,11 +213,11 @@
   net::ProxyInfo info;
   net::TestCompletionCallback callback;
   net::BoundTestNetLog test_net_log;
+  std::unique_ptr<net::ProxyResolutionService::Request> request;
   EXPECT_EQ(net::ERR_IO_PENDING,
             proxy_resolution_service_->ResolveProxy(
-                GURL("http://foo"), std::string(),
-                &info, callback.callback(), nullptr,
-                nullptr, test_net_log.bound()));
+                GURL("http://foo"), std::string(), &info, callback.callback(),
+                &request, nullptr, test_net_log.bound()));
 
   // PAC file fetcher should have a fetch triggered by the first
   // |ResolveProxy()| request.
@@ -244,11 +243,11 @@
 TEST_F(ProxyServiceMojoTest, ErrorOnInitialization) {
   net::ProxyInfo info;
   net::TestCompletionCallback callback;
+  std::unique_ptr<net::ProxyResolutionService::Request> request;
   EXPECT_EQ(net::ERR_IO_PENDING,
             proxy_resolution_service_->ResolveProxy(
-                GURL("http://foo"), std::string(),
-                &info, callback.callback(), nullptr,
-                nullptr, net::NetLogWithSource()));
+                GURL("http://foo"), std::string(), &info, callback.callback(),
+                &request, nullptr, net::NetLogWithSource()));
 
   // PAC file fetcher should have a fetch triggered by the first
   // |ResolveProxy()| request.
diff --git a/device/fido/device_response_converter.cc b/device/fido/device_response_converter.cc
index b5ba0f7..e39fa693 100644
--- a/device/fido/device_response_converter.cc
+++ b/device/fido/device_response_converter.cc
@@ -169,8 +169,8 @@
 
     auto protocol = ConvertStringToProtocolVersion(version.GetString());
     if (protocol == ProtocolVersion::kUnknown) {
-      DLOG(ERROR) << "Unexpected protocol version received.";
-      return base::nullopt;
+      VLOG(2) << "Unexpected protocol version received.";
+      continue;
     }
 
     if (!protocol_versions.insert(protocol).second)
diff --git a/gpu/command_buffer/common/buffer.cc b/gpu/command_buffer/common/buffer.cc
index 1aa3bffe..4682400 100644
--- a/gpu/command_buffer/common/buffer.cc
+++ b/gpu/command_buffer/common/buffer.cc
@@ -24,6 +24,19 @@
   return base::UnguessableToken();
 }
 
+MemoryBufferBacking::MemoryBufferBacking(size_t size)
+    : memory_(new char[size]), size_(size) {}
+
+MemoryBufferBacking::~MemoryBufferBacking() = default;
+
+void* MemoryBufferBacking::GetMemory() const {
+  return memory_.get();
+}
+
+size_t MemoryBufferBacking::GetSize() const {
+  return size_;
+}
+
 SharedMemoryBufferBacking::SharedMemoryBufferBacking(
     base::UnsafeSharedMemoryRegion shared_memory_region,
     base::WritableSharedMemoryMapping shared_memory_mapping)
diff --git a/gpu/command_buffer/common/buffer.h b/gpu/command_buffer/common/buffer.h
index db89809..e7c3198 100644
--- a/gpu/command_buffer/common/buffer.h
+++ b/gpu/command_buffer/common/buffer.h
@@ -27,6 +27,20 @@
   virtual size_t GetSize() const = 0;
 };
 
+class GPU_EXPORT MemoryBufferBacking : public BufferBacking {
+ public:
+  explicit MemoryBufferBacking(size_t size);
+  ~MemoryBufferBacking() override;
+  void* GetMemory() const override;
+  size_t GetSize() const override;
+
+ private:
+  std::unique_ptr<char[]> memory_;
+  size_t size_;
+  DISALLOW_COPY_AND_ASSIGN(MemoryBufferBacking);
+};
+
+
 class GPU_EXPORT SharedMemoryBufferBacking : public BufferBacking {
  public:
   SharedMemoryBufferBacking(
@@ -82,10 +96,15 @@
 static inline scoped_refptr<Buffer> MakeBufferFromSharedMemory(
     base::UnsafeSharedMemoryRegion shared_memory_region,
     base::WritableSharedMemoryMapping shared_memory_mapping) {
-  return new Buffer(MakeBackingFromSharedMemory(
+  return base::MakeRefCounted<Buffer>(MakeBackingFromSharedMemory(
       std::move(shared_memory_region), std::move(shared_memory_mapping)));
 }
 
+static inline scoped_refptr<Buffer> MakeMemoryBuffer(size_t size) {
+  return base::MakeRefCounted<Buffer>(
+      std::make_unique<MemoryBufferBacking>(size));
+}
+
 // Generates GUID which can be used to trace buffer using an Id.
 GPU_EXPORT base::trace_event::MemoryAllocatorDumpGuid GetBufferGUIDForTracing(
     uint64_t tracing_process_id,
diff --git a/gpu/command_buffer/service/command_buffer_service.cc b/gpu/command_buffer/service/command_buffer_service.cc
index 453e59d..04eaddd1 100644
--- a/gpu/command_buffer/service/command_buffer_service.cc
+++ b/gpu/command_buffer/service/command_buffer_service.cc
@@ -18,24 +18,6 @@
 
 namespace gpu {
 
-namespace {
-
-class MemoryBufferBacking : public BufferBacking {
- public:
-  explicit MemoryBufferBacking(size_t size)
-      : memory_(new char[size]), size_(size) {}
-  ~MemoryBufferBacking() override = default;
-  void* GetMemory() const override { return memory_.get(); }
-  size_t GetSize() const override { return size_; }
-
- private:
-  std::unique_ptr<char[]> memory_;
-  size_t size_;
-  DISALLOW_COPY_AND_ASSIGN(MemoryBufferBacking);
-};
-
-}  // anonymous namespace
-
 CommandBufferService::CommandBufferService(
     CommandBufferServiceClient* client,
     TransferBufferManager* transfer_buffer_manager)
@@ -183,7 +165,7 @@
 
 bool CommandBufferService::RegisterTransferBuffer(
     int32_t id,
-    std::unique_ptr<BufferBacking> buffer) {
+    scoped_refptr<Buffer> buffer) {
   return transfer_buffer_manager_->RegisterTransferBuffer(id,
                                                           std::move(buffer));
 }
@@ -191,13 +173,13 @@
 scoped_refptr<Buffer> CommandBufferService::CreateTransferBufferWithId(
     size_t size,
     int32_t id) {
-  if (!RegisterTransferBuffer(id,
-                              std::make_unique<MemoryBufferBacking>(size))) {
+  scoped_refptr<Buffer> buffer = MakeMemoryBuffer(size);
+  if (!RegisterTransferBuffer(id, buffer)) {
     SetParseError(gpu::error::kOutOfBounds);
     return nullptr;
   }
 
-  return GetTransferBuffer(id);
+  return buffer;
 }
 
 void CommandBufferService::SetToken(int32_t token) {
diff --git a/gpu/command_buffer/service/command_buffer_service.h b/gpu/command_buffer/service/command_buffer_service.h
index 8028d0e..b6bfb5c 100644
--- a/gpu/command_buffer/service/command_buffer_service.h
+++ b/gpu/command_buffer/service/command_buffer_service.h
@@ -97,10 +97,9 @@
   // Sets the get buffer and call the GetBufferChangeCallback.
   void SetGetBuffer(int32_t transfer_buffer_id);
 
-  // Registers an existing shared memory object with a given ID that can be used
-  // to identify it in the command buffer.
-  bool RegisterTransferBuffer(int32_t id,
-                              std::unique_ptr<BufferBacking> buffer);
+  // Registers an existing Buffer object with a given ID that can be used to
+  // identify it in the command buffer.
+  bool RegisterTransferBuffer(int32_t id, scoped_refptr<Buffer> buffer);
 
   // Unregisters and destroys the transfer buffer associated with the given id.
   void DestroyTransferBuffer(int32_t id);
diff --git a/gpu/command_buffer/service/transfer_buffer_manager.cc b/gpu/command_buffer/service/transfer_buffer_manager.cc
index 6f70b40..c4a3a45 100644
--- a/gpu/command_buffer/service/transfer_buffer_manager.cc
+++ b/gpu/command_buffer/service/transfer_buffer_manager.cc
@@ -51,7 +51,7 @@
 
 bool TransferBufferManager::RegisterTransferBuffer(
     int32_t id,
-    std::unique_ptr<BufferBacking> buffer_backing) {
+    scoped_refptr<Buffer> buffer) {
   if (id <= 0) {
     DVLOG(0) << "Cannot register transfer buffer with non-positive ID.";
     return false;
@@ -63,16 +63,13 @@
     return false;
   }
 
-  // Register the shared memory with the ID.
-  scoped_refptr<Buffer> buffer(new gpu::Buffer(std::move(buffer_backing)));
-
   // Check buffer alignment is sane.
   DCHECK(!(reinterpret_cast<uintptr_t>(buffer->memory()) &
            (kCommandBufferEntrySize - 1)));
 
   shared_memory_bytes_allocated_ += buffer->size();
 
-  registered_buffers_[id] = buffer;
+  registered_buffers_[id] = std::move(buffer);
 
   return true;
 }
diff --git a/gpu/command_buffer/service/transfer_buffer_manager.h b/gpu/command_buffer/service/transfer_buffer_manager.h
index efe7631..78ce317 100644
--- a/gpu/command_buffer/service/transfer_buffer_manager.h
+++ b/gpu/command_buffer/service/transfer_buffer_manager.h
@@ -17,7 +17,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/trace_event/memory_dump_provider.h"
-#include "gpu/command_buffer/common/command_buffer_shared.h"
+#include "gpu/command_buffer/common/command_buffer.h"
 
 namespace gpu {
 namespace gles2 {
@@ -34,8 +34,7 @@
   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
                     base::trace_event::ProcessMemoryDump* pmd) override;
 
-  bool RegisterTransferBuffer(int32_t id,
-                              std::unique_ptr<BufferBacking> buffer_backing);
+  bool RegisterTransferBuffer(int32_t id, scoped_refptr<Buffer> buffer);
   void DestroyTransferBuffer(int32_t id);
   scoped_refptr<Buffer> GetTransferBuffer(int32_t id);
 
diff --git a/gpu/command_buffer/service/transfer_buffer_manager_unittest.cc b/gpu/command_buffer/service/transfer_buffer_manager_unittest.cc
index 71047e82..08e3439d 100644
--- a/gpu/command_buffer/service/transfer_buffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/transfer_buffer_manager_unittest.cc
@@ -45,8 +45,8 @@
       std::move(shm_region), std::move(shm_mapping));
   SharedMemoryBufferBacking* backing_raw_ptr = backing.get();
 
-  EXPECT_TRUE(
-      transfer_buffer_manager_->RegisterTransferBuffer(1, std::move(backing)));
+  EXPECT_TRUE(transfer_buffer_manager_->RegisterTransferBuffer(
+      1, base::MakeRefCounted<Buffer>(std::move(backing))));
   scoped_refptr<Buffer> registered =
       transfer_buffer_manager_->GetTransferBuffer(1);
 
@@ -55,20 +55,9 @@
   EXPECT_EQ(shm_guid, backing_raw_ptr->GetGUID());
 }
 
-class FakeBufferBacking : public BufferBacking {
- public:
-  void* GetMemory() const override {
-    return reinterpret_cast<void*>(0xBADF00D0);
-  }
-  size_t GetSize() const override { return 42; }
-  static std::unique_ptr<BufferBacking> Make() {
-    return std::unique_ptr<BufferBacking>(new FakeBufferBacking);
-  }
-};
-
 TEST_F(TransferBufferManagerTest, CanDestroyTransferBuffer) {
   EXPECT_TRUE(transfer_buffer_manager_->RegisterTransferBuffer(
-      1, std::unique_ptr<BufferBacking>(new FakeBufferBacking)));
+      1, MakeMemoryBuffer(42)));
   transfer_buffer_manager_->DestroyTransferBuffer(1);
   scoped_refptr<Buffer> registered =
       transfer_buffer_manager_->GetTransferBuffer(1);
@@ -79,19 +68,19 @@
 
 TEST_F(TransferBufferManagerTest, CannotRegregisterTransferBufferId) {
   EXPECT_TRUE(transfer_buffer_manager_->RegisterTransferBuffer(
-      1, FakeBufferBacking::Make()));
+      1, MakeMemoryBuffer(42)));
   EXPECT_FALSE(transfer_buffer_manager_->RegisterTransferBuffer(
-      1, FakeBufferBacking::Make()));
+      1, MakeMemoryBuffer(42)));
   EXPECT_FALSE(transfer_buffer_manager_->RegisterTransferBuffer(
-      1, FakeBufferBacking::Make()));
+      1, MakeMemoryBuffer(42)));
 }
 
 TEST_F(TransferBufferManagerTest, CanReuseTransferBufferIdAfterDestroying) {
   EXPECT_TRUE(transfer_buffer_manager_->RegisterTransferBuffer(
-      1, FakeBufferBacking::Make()));
+      1, MakeMemoryBuffer(42)));
   transfer_buffer_manager_->DestroyTransferBuffer(1);
   EXPECT_TRUE(transfer_buffer_manager_->RegisterTransferBuffer(
-      1, FakeBufferBacking::Make()));
+      1, MakeMemoryBuffer(42)));
 }
 
 TEST_F(TransferBufferManagerTest, DestroyUnusedTransferBufferIdDoesNotCrash) {
@@ -100,12 +89,12 @@
 
 TEST_F(TransferBufferManagerTest, CannotRegisterNullTransferBuffer) {
   EXPECT_FALSE(transfer_buffer_manager_->RegisterTransferBuffer(
-      0, FakeBufferBacking::Make()));
+      0, MakeMemoryBuffer(42)));
 }
 
 TEST_F(TransferBufferManagerTest, CannotRegisterNegativeTransferBufferId) {
   EXPECT_FALSE(transfer_buffer_manager_->RegisterTransferBuffer(
-      -1, FakeBufferBacking::Make()));
+      -1, MakeMemoryBuffer(42)));
 }
 
 }  // namespace gpu
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index bfd783e..0469214e 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -206,7 +206,6 @@
 
 bool InProcessCommandBuffer::MakeCurrent() {
   CheckSequencedThread();
-  command_buffer_lock_.AssertAcquired();
 
   if (error::IsError(command_buffer_->GetState().error)) {
     DLOG(ERROR) << "MakeCurrent failed because context lost.";
@@ -691,7 +690,6 @@
 
 void InProcessCommandBuffer::UpdateLastStateOnGpuThread() {
   CheckSequencedThread();
-  command_buffer_lock_.AssertAcquired();
   base::AutoLock lock(last_state_lock_);
   command_buffer_->UpdateState();
   State state = command_buffer_->GetState();
@@ -702,7 +700,6 @@
 void InProcessCommandBuffer::FlushOnGpuThread(int32_t put_offset) {
   CheckSequencedThread();
   ScopedEvent handle_flush(&flush_event_);
-  base::AutoLock lock(command_buffer_lock_);
 
   if (!MakeCurrent())
     return;
@@ -727,7 +724,6 @@
 void InProcessCommandBuffer::PerformDelayedWorkOnGpuThread() {
   CheckSequencedThread();
   delayed_work_pending_ = false;
-  base::AutoLock lock(command_buffer_lock_);
   // TODO(sunnyps): Should this use ScopedCrashKey instead?
   crash_keys::gpu_gl_context_is_virtual.Set(use_virtualized_gl_context_ ? "1"
                                                                         : "0");
@@ -818,7 +814,6 @@
 void InProcessCommandBuffer::SetGetBufferOnGpuThread(
     int32_t shm_id,
     base::WaitableEvent* completion) {
-  base::AutoLock lock(command_buffer_lock_);
   command_buffer_->SetGetBuffer(shm_id);
   UpdateLastStateOnGpuThread();
   completion->Signal();
@@ -828,8 +823,20 @@
     size_t size,
     int32_t* id) {
   CheckSequencedThread();
-  base::AutoLock lock(command_buffer_lock_);
-  return command_buffer_->CreateTransferBuffer(size, id);
+  scoped_refptr<Buffer> buffer = MakeMemoryBuffer(size);
+  *id = ++next_transfer_buffer_id_;
+  base::OnceClosure task =
+      base::BindOnce(&InProcessCommandBuffer::RegisterTransferBufferOnGpuThread,
+                     base::Unretained(this), *id, buffer);
+
+  QueueOnceTask(false, std::move(task));
+  return buffer;
+}
+
+void InProcessCommandBuffer::RegisterTransferBufferOnGpuThread(
+    int32_t id,
+    scoped_refptr<Buffer> buffer) {
+  command_buffer_->RegisterTransferBuffer(id, std::move(buffer));
 }
 
 void InProcessCommandBuffer::DestroyTransferBuffer(int32_t id) {
@@ -842,7 +849,6 @@
 }
 
 void InProcessCommandBuffer::DestroyTransferBufferOnGpuThread(int32_t id) {
-  base::AutoLock lock(command_buffer_lock_);
   command_buffer_->DestroyTransferBuffer(id);
 }
 
diff --git a/gpu/ipc/in_process_command_buffer.h b/gpu/ipc/in_process_command_buffer.h
index d6ff473..aa1b3d4e 100644
--- a/gpu/ipc/in_process_command_buffer.h
+++ b/gpu/ipc/in_process_command_buffer.h
@@ -246,6 +246,8 @@
   void SignalSyncTokenOnGpuThread(const SyncToken& sync_token,
                                   base::OnceClosure callback);
   void SignalQueryOnGpuThread(unsigned query_id, base::OnceClosure callback);
+  void RegisterTransferBufferOnGpuThread(int32_t id,
+                                         scoped_refptr<Buffer> buffer);
   void DestroyTransferBufferOnGpuThread(int32_t id);
   void CreateImageOnGpuThread(int32_t id,
                               gfx::GpuMemoryBufferHandle handle,
@@ -278,6 +280,7 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
   std::unique_ptr<TransferBufferManager> transfer_buffer_manager_;
+  std::unique_ptr<CommandBufferService> command_buffer_;
   std::unique_ptr<DecoderContext> decoder_;
   base::Optional<raster::GrCacheController> gr_cache_controller_;
   scoped_refptr<gl::GLContext> context_;
@@ -299,12 +302,11 @@
   int32_t last_put_offset_ = -1;
   Capabilities capabilities_;
   GpuMemoryBufferManager* gpu_memory_buffer_manager_ = nullptr;
+  int32_t  next_transfer_buffer_id_ = 1;
   uint64_t next_fence_sync_release_ = 1;
   uint64_t flushed_fence_sync_release_ = 0;
 
   // Accessed on both threads:
-  std::unique_ptr<CommandBufferService> command_buffer_;
-  base::Lock command_buffer_lock_;
   base::WaitableEvent flush_event_;
   scoped_refptr<CommandBufferTaskExecutor> task_executor_;
 
diff --git a/gpu/ipc/service/command_buffer_stub.cc b/gpu/ipc/service/command_buffer_stub.cc
index 9f05111..e91476a 100644
--- a/gpu/ipc/service/command_buffer_stub.cc
+++ b/gpu/ipc/service/command_buffer_stub.cc
@@ -644,8 +644,8 @@
 
   if (command_buffer_) {
     command_buffer_->RegisterTransferBuffer(
-        id, MakeBackingFromSharedMemory(std::move(transfer_buffer),
-                                        std::move(mapping)));
+        id, MakeBufferFromSharedMemory(std::move(transfer_buffer),
+                                       std::move(mapping)));
   }
 }
 
diff --git a/headless/BUILD.gn b/headless/BUILD.gn
index ad0ee65..7ab88b7b 100644
--- a/headless/BUILD.gn
+++ b/headless/BUILD.gn
@@ -346,14 +346,10 @@
     "public/internal/headless_devtools_client_impl.h",
     "public/internal/message_dispatcher.h",
     "public/internal/value_conversions.h",
-    "public/util/compositor_controller.cc",
-    "public/util/compositor_controller.h",
     "public/util/error_reporter.cc",
     "public/util/error_reporter.h",
     "public/util/user_agent.cc",
     "public/util/user_agent.h",
-    "public/util/virtual_time_controller.cc",
-    "public/util/virtual_time_controller.h",
   ]
 
   if (!is_fuchsia) {
@@ -557,9 +553,7 @@
 test("headless_unittests") {
   sources = [
     "public/domains/types_unittest.cc",
-    "public/util/compositor_controller_unittest.cc",
     "public/util/error_reporter_unittest.cc",
-    "public/util/virtual_time_controller_test.cc",
   ]
 
   if (!is_component_build) {
@@ -686,7 +680,6 @@
     "lib/headless_browser_context_browsertest.cc",
     "lib/headless_devtools_client_browsertest.cc",
     "lib/headless_web_contents_browsertest.cc",
-    "public/util/compositor_controller_browsertest.cc",
     "test/headless_browser_test.cc",
     "test/headless_browser_test.h",
     "test/headless_client_browsertest.cc",
@@ -745,12 +738,7 @@
   if (is_linux) {
     # Only include this if we built the js_binary
     data += [ "$root_out_dir/headless_browser_tests.pak" ]
-    sources += [
-      "test/headless_js_bindings_browsertest.cc",
-      "test/headless_render_browsertest.cc",
-      "test/headless_render_test.cc",
-      "test/headless_render_test.h",
-    ]
+    sources += [ "test/headless_js_bindings_browsertest.cc" ]
     deps += [
       ":headless_browser_tests_pak",
       "//ui/gfx:geometry_skia",
diff --git a/headless/public/util/DEPS b/headless/public/util/DEPS
index 5d54b89..e5ed6729 100644
--- a/headless/public/util/DEPS
+++ b/headless/public/util/DEPS
@@ -1,9 +1,3 @@
 specific_include_rules = {
-  "compositor_controller_browsertest.cc": [
-    "+cc/base/switches.h",
-    "+components/viz/common/features.h",
-    "+components/viz/common/switches.h",
-    "+third_party/skia/include",
-  ]
 }
 
diff --git a/headless/public/util/compositor_controller.cc b/headless/public/util/compositor_controller.cc
deleted file mode 100644
index 0cd424d..0000000
--- a/headless/public/util/compositor_controller.cc
+++ /dev/null
@@ -1,261 +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 "headless/public/util/compositor_controller.h"
-
-#include <memory>
-
-#include "base/base64.h"
-#include "base/bind.h"
-#include "base/cancelable_callback.h"
-#include "base/logging.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/trace_event/trace_event.h"
-#include "headless/public/util/virtual_time_controller.h"
-
-namespace headless {
-
-// Sends BeginFrames to advance animations while virtual time advances in
-// intervals.
-class CompositorController::AnimationBeginFrameTask
-    : public VirtualTimeController::RepeatingTask,
-      public VirtualTimeController::ResumeDeferrer {
- public:
-  explicit AnimationBeginFrameTask(CompositorController* compositor_controller)
-      : RepeatingTask(StartPolicy::START_IMMEDIATELY, -1),
-        compositor_controller_(compositor_controller),
-        weak_ptr_factory_(this) {}
-
-  // VirtualTimeController::RepeatingTask implementation:
-  void IntervalElapsed(
-      base::TimeDelta virtual_time_offset,
-      base::OnceCallback<void(ContinuePolicy)> continue_callback) override {
-    needs_begin_frame_on_virtual_time_resume_ = true;
-    std::move(continue_callback).Run(ContinuePolicy::NOT_REQUIRED);
-  }
-
-  // VirtualTimeController::ResumeDeferrer implementation:
-  void DeferResume(base::OnceClosure continue_callback) override {
-    // Run a BeginFrame if we scheduled one in the last interval and no other
-    // BeginFrame was sent while virtual time was paused.
-    if (needs_begin_frame_on_virtual_time_resume_) {
-      continue_callback_ = std::move(continue_callback);
-      IssueAnimationBeginFrame();
-      return;
-    }
-    std::move(continue_callback).Run();
-  }
-
-  void CompositorControllerIssuingScreenshotBeginFrame() {
-    TRACE_EVENT0("headless",
-                 "CompositorController::AnimationBeginFrameTask::"
-                 "CompositorControllerIssuingScreenshotBeginFrame");
-    // The screenshotting BeginFrame will replace our animation-only BeginFrame.
-    // We cancel any pending animation BeginFrame to avoid sending two
-    // BeginFrames within the same virtual time pause.
-    needs_begin_frame_on_virtual_time_resume_ = false;
-  }
-
- private:
-  void IssueAnimationBeginFrame() {
-    TRACE_EVENT0("headless",
-                 "CompositorController::AnimationBeginFrameTask::"
-                 "IssueAnimationBeginFrame");
-    needs_begin_frame_on_virtual_time_resume_ = false;
-
-    bool update_display =
-        compositor_controller_->update_display_for_animations_;
-    // Display needs to be updated for first BeginFrame. Otherwise, the
-    // RenderWidget's surface may not be created and the root surface may block
-    // waiting for it forever.
-    update_display |=
-        compositor_controller_->last_begin_frame_time_ == base::TimeTicks();
-
-    compositor_controller_->PostBeginFrame(
-        base::BindOnce(&AnimationBeginFrameTask::BeginFrameComplete,
-                       weak_ptr_factory_.GetWeakPtr()),
-        !update_display);
-  }
-
-  void BeginFrameComplete(std::unique_ptr<BeginFrameResult>) {
-    TRACE_EVENT0(
-        "headless",
-        "CompositorController::AnimationBeginFrameTask::BeginFrameComplete");
-    DCHECK(continue_callback_);
-    std::move(continue_callback_).Run();
-  }
-
-  CompositorController* compositor_controller_;  // NOT OWNED
-  bool needs_begin_frame_on_virtual_time_resume_ = true;
-  base::CancelableClosure begin_frame_task_;
-
-  base::OnceClosure continue_callback_;
-  base::WeakPtrFactory<AnimationBeginFrameTask> weak_ptr_factory_;
-};
-
-CompositorController::CompositorController(
-    scoped_refptr<base::SequencedTaskRunner> task_runner,
-    HeadlessDevToolsClient* devtools_client,
-    VirtualTimeController* virtual_time_controller,
-    base::TimeDelta animation_begin_frame_interval,
-    bool update_display_for_animations)
-    : task_runner_(std::move(task_runner)),
-      devtools_client_(devtools_client),
-      virtual_time_controller_(virtual_time_controller),
-      animation_task_(std::make_unique<AnimationBeginFrameTask>(this)),
-      animation_begin_frame_interval_(animation_begin_frame_interval),
-      update_display_for_animations_(update_display_for_animations),
-      weak_ptr_factory_(this) {
-  devtools_client_->GetHeadlessExperimental()->GetExperimental()->AddObserver(
-      this);
-  // No need to wait for completion of this, since we are waiting for the
-  // setNeedsBeginFramesChanged event instead, which will be sent at some point
-  // after enabling the domain.
-  devtools_client_->GetHeadlessExperimental()->GetExperimental()->Enable(
-      headless_experimental::EnableParams::Builder().Build());
-  virtual_time_controller_->ScheduleRepeatingTask(
-      animation_task_.get(), animation_begin_frame_interval_);
-  virtual_time_controller_->SetResumeDeferrer(animation_task_.get());
-}
-
-CompositorController::~CompositorController() {
-  virtual_time_controller_->CancelRepeatingTask(animation_task_.get());
-  virtual_time_controller_->SetResumeDeferrer(nullptr);
-  devtools_client_->GetHeadlessExperimental()
-      ->GetExperimental()
-      ->RemoveObserver(this);
-}
-
-void CompositorController::PostBeginFrame(
-    base::OnceCallback<void(std::unique_ptr<BeginFrameResult>)>
-        begin_frame_complete_callback,
-    bool no_display_updates,
-    std::unique_ptr<ScreenshotParams> screenshot) {
-  // In certain nesting situations, we should not issue a BeginFrame immediately
-  // - for example, issuing a new BeginFrame within a BeginFrameCompleted or
-  // NeedsBeginFramesChanged event can upset the compositor. We avoid these
-  // situations by issuing our BeginFrames from a separately posted task.
-  task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&CompositorController::BeginFrame,
-                                weak_ptr_factory_.GetWeakPtr(),
-                                std::move(begin_frame_complete_callback),
-                                no_display_updates, std::move(screenshot)));
-}
-
-void CompositorController::BeginFrame(
-    base::OnceCallback<void(std::unique_ptr<BeginFrameResult>)>
-        begin_frame_complete_callback,
-    bool no_display_updates,
-    std::unique_ptr<ScreenshotParams> screenshot) {
-  DCHECK(!begin_frame_complete_callback_);
-  begin_frame_complete_callback_ = std::move(begin_frame_complete_callback);
-  if (needs_begin_frames_ || screenshot) {
-    auto params_builder = headless_experimental::BeginFrameParams::Builder();
-
-    // Use virtual time for frame time, so that rendering of animations etc. is
-    // aligned with virtual time progression.
-    base::TimeTicks frame_time =
-        virtual_time_controller_->GetCurrentVirtualTime();
-    if (frame_time <= last_begin_frame_time_) {
-      // Frame time cannot go backwards or stop, so we issue another BeginFrame
-      // with a small time offset from the last BeginFrame's time instead.
-      frame_time =
-          last_begin_frame_time_ + base::TimeDelta::FromMicroseconds(1);
-    }
-    params_builder.SetFrameTimeTicks(
-        (frame_time - base::TimeTicks()).InMillisecondsF());
-    DCHECK_GT(frame_time, last_begin_frame_time_);
-    last_begin_frame_time_ = frame_time;
-
-    params_builder.SetInterval(
-        animation_begin_frame_interval_.InMillisecondsF());
-
-    params_builder.SetNoDisplayUpdates(no_display_updates);
-
-    if (screenshot)
-      params_builder.SetScreenshot(std::move(screenshot));
-
-    devtools_client_->GetHeadlessExperimental()->GetExperimental()->BeginFrame(
-        params_builder.Build(),
-        base::BindOnce(&CompositorController::BeginFrameComplete,
-                       weak_ptr_factory_.GetWeakPtr()));
-  } else {
-    BeginFrameComplete(nullptr);
-  }
-}
-
-void CompositorController::BeginFrameComplete(
-    std::unique_ptr<BeginFrameResult> result) {
-  std::move(begin_frame_complete_callback_).Run(std::move(result));
-  if (idle_callback_)
-    std::move(idle_callback_).Run();
-}
-
-void CompositorController::OnNeedsBeginFramesChanged(
-    const NeedsBeginFramesChangedParams& params) {
-  needs_begin_frames_ = params.GetNeedsBeginFrames();
-}
-
-void CompositorController::WaitUntilIdle(base::OnceClosure idle_callback) {
-  TRACE_EVENT_INSTANT1("headless", "CompositorController::WaitUntilIdle",
-                       TRACE_EVENT_SCOPE_THREAD, "begin_frame_in_flight",
-                       !!begin_frame_complete_callback_);
-  DCHECK(!idle_callback_);
-
-  if (!begin_frame_complete_callback_) {
-    std::move(idle_callback).Run();
-    return;
-  }
-
-  idle_callback_ = std::move(idle_callback);
-}
-
-void CompositorController::CaptureScreenshot(
-    ScreenshotParamsFormat format,
-    int quality,
-    base::OnceCallback<void(const std::string&)> screenshot_captured_callback) {
-  TRACE_EVENT0("headless", "CompositorController::CaptureScreenshot");
-  DCHECK(!begin_frame_complete_callback_);
-  DCHECK(!screenshot_captured_callback_);
-
-  screenshot_captured_callback_ = std::move(screenshot_captured_callback);
-
-  // Let AnimationBeginFrameTask know that it doesn't need to issue an
-  // animation BeginFrame for the current virtual time pause.
-  animation_task_->CompositorControllerIssuingScreenshotBeginFrame();
-
-  const bool no_display_updates = false;
-  PostBeginFrame(
-      base::BindOnce(&CompositorController::CaptureScreenshotBeginFrameComplete,
-                     weak_ptr_factory_.GetWeakPtr()),
-      no_display_updates,
-      ScreenshotParams::Builder()
-          .SetFormat(format)
-          .SetQuality(quality)
-          .Build());
-}
-
-void CompositorController::CaptureScreenshotBeginFrameComplete(
-    std::unique_ptr<BeginFrameResult> result) {
-  TRACE_EVENT1(
-      "headless", "CompositorController::CaptureScreenshotBeginFrameComplete",
-      "hasScreenshotData",
-      result ? std::to_string(result->HasScreenshotData()) : "invalid");
-  DCHECK(screenshot_captured_callback_);
-  if (result && result->HasScreenshotData()) {
-    // TODO(eseckler): Look into returning binary screenshot data via DevTools.
-    std::string decoded_data;
-    base::Base64Decode(result->GetScreenshotData(), &decoded_data);
-    std::move(screenshot_captured_callback_).Run(decoded_data);
-  } else {
-    LOG(ERROR) << "Screenshotting failed, BeginFrameResult has no data and "
-                  "hasDamage is "
-               << (result ? std::to_string(result->HasScreenshotData())
-                          : "invalid");
-    std::move(screenshot_captured_callback_).Run(std::string());
-  }
-}
-
-}  // namespace headless
diff --git a/headless/public/util/compositor_controller.h b/headless/public/util/compositor_controller.h
deleted file mode 100644
index 338a732..0000000
--- a/headless/public/util/compositor_controller.h
+++ /dev/null
@@ -1,102 +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 HEADLESS_PUBLIC_UTIL_COMPOSITOR_CONTROLLER_H_
-#define HEADLESS_PUBLIC_UTIL_COMPOSITOR_CONTROLLER_H_
-
-#include "base/callback.h"
-#include "base/cancelable_callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequenced_task_runner.h"
-#include "base/time/time.h"
-#include "headless/public/devtools/domains/headless_experimental.h"
-#include "headless/public/headless_devtools_client.h"
-
-namespace headless {
-
-class VirtualTimeController;
-
-// Issues BeginFrames (Chromium's vsync signal) while virtual time advances and
-// and takes screenshots.
-class HEADLESS_EXPORT CompositorController
-    : public headless_experimental::ExperimentalObserver {
- public:
-  using BeginFrameResult = headless_experimental::BeginFrameResult;
-  using NeedsBeginFramesChangedParams =
-      headless_experimental::NeedsBeginFramesChangedParams;
-  using ScreenshotParams = headless_experimental::ScreenshotParams;
-  using ScreenshotParamsFormat = headless_experimental::ScreenshotParamsFormat;
-
-  // |animation_begin_frame_interval| specifies the virtual time between
-  // individual BeginFrames while virtual time advances.
-  // If |update_display_for_animations| is false, animation BeginFrames will not
-  // commit or draw visual updates to the display. This can be used to reduce
-  // the overhead of such BeginFrames in the common case that screenshots will
-  // be taken from separate BeginFrames.
-  CompositorController(
-      scoped_refptr<base::SequencedTaskRunner> task_runner,
-      HeadlessDevToolsClient* devtools_client,
-      VirtualTimeController* virtual_time_controller,
-      base::TimeDelta animation_begin_frame_interval,
-      bool update_display_for_animations = true);
-  ~CompositorController() override;
-
-  // Executes |idle_callback| when no BeginFrames are in flight.
-  void WaitUntilIdle(base::OnceClosure idle_callback);
-
-  // Captures a screenshot by issuing a BeginFrame. |quality| is only valid for
-  // jpeg format screenshots, in range 0..100. Should not be called again until
-  // |screenshot_captured_callback| was run. Should only be called while no
-  // other BeginFrame is in flight and after the compositor is ready.
-  void CaptureScreenshot(ScreenshotParamsFormat format,
-                         int quality,
-                         base::OnceCallback<void(const std::string&)>
-                             screenshot_captured_callback);
-
- private:
-  class AnimationBeginFrameTask;
-
-  // headless_experimental_::Observer implementation:
-  void OnNeedsBeginFramesChanged(
-      const NeedsBeginFramesChangedParams& params) override;
-
-  // Posts a BeginFrame as a new task to avoid nesting it inside the current
-  // callstack, which can upset the compositor.
-  void PostBeginFrame(
-      base::OnceCallback<void(std::unique_ptr<BeginFrameResult>)>
-          begin_frame_complete_callback,
-      bool no_display_updates = false,
-      std::unique_ptr<ScreenshotParams> screenshot = nullptr);
-  // Issues a BeginFrame synchronously and runs |begin_frame_complete_callback|
-  // when done. Should not be called again until |begin_frame_complete_callback|
-  // was run.
-  void BeginFrame(base::OnceCallback<void(std::unique_ptr<BeginFrameResult>)>
-                      begin_frame_complete_callback,
-                  bool no_display_updates = false,
-                  std::unique_ptr<ScreenshotParams> screenshot = nullptr);
-  // Runs the |begin_frame_complete_callback_| and the |idle_callback_| if set.
-  void BeginFrameComplete(std::unique_ptr<BeginFrameResult>);
-
-  void CaptureScreenshotBeginFrameComplete(
-      std::unique_ptr<BeginFrameResult> result);
-
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
-  HeadlessDevToolsClient* devtools_client_;         // NOT OWNED
-  VirtualTimeController* virtual_time_controller_;  // NOT OWNED
-  std::unique_ptr<AnimationBeginFrameTask> animation_task_;
-  base::OnceClosure idle_callback_;
-  base::OnceCallback<void(const std::string&)> screenshot_captured_callback_;
-  base::OnceCallback<void(std::unique_ptr<BeginFrameResult>)>
-      begin_frame_complete_callback_;
-  base::TimeDelta animation_begin_frame_interval_;
-  bool update_display_for_animations_;
-  bool needs_begin_frames_ = false;
-  base::TimeTicks last_begin_frame_time_;
-  base::WeakPtrFactory<CompositorController> weak_ptr_factory_;
-};
-
-}  // namespace headless
-
-#endif  // HEADLESS_PUBLIC_UTIL_COMPOSITOR_CONTROLLER_H_
diff --git a/headless/public/util/compositor_controller_browsertest.cc b/headless/public/util/compositor_controller_browsertest.cc
deleted file mode 100644
index 994f73c..0000000
--- a/headless/public/util/compositor_controller_browsertest.cc
+++ /dev/null
@@ -1,715 +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 "headless/public/util/compositor_controller.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/test/scoped_feature_list.h"
-#include "build/build_config.h"
-#include "cc/base/switches.h"
-#include "components/viz/common/features.h"
-#include "components/viz/common/switches.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/test/browser_test.h"
-#include "content/public/test/browser_test_utils.h"
-#include "headless/lib/browser/headless_web_contents_impl.h"
-#include "headless/public/devtools/domains/emulation.h"
-#include "headless/public/devtools/domains/runtime.h"
-#include "headless/public/headless_browser.h"
-#include "headless/public/headless_devtools_client.h"
-#include "headless/public/util/virtual_time_controller.h"
-#include "headless/test/headless_browser_test.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/codec/png_codec.h"
-
-using testing::ElementsAre;
-
-#define EXPECT_SCOPED(statements) \
-  {                               \
-    SCOPED_TRACE("");             \
-    statements;                   \
-  }
-
-namespace headless {
-
-// BeginFrameControl is not supported on Mac.
-#if !defined(OS_MACOSX)
-
-namespace {
-
-class BeginFrameCounter : HeadlessDevToolsClient::RawProtocolListener {
- public:
-  BeginFrameCounter(HeadlessDevToolsClient* client) : client_(client) {
-    client_->SetRawProtocolListener(this);
-  }
-
-  ~BeginFrameCounter() override { client_->SetRawProtocolListener(nullptr); }
-
-  bool OnProtocolMessage(const std::string& json_message,
-                         const base::DictionaryValue& parsed_message) override {
-    const base::Value* id_value = parsed_message.FindKey("id");
-    if (!id_value)
-      return false;
-
-    const base::DictionaryValue* result_dict;
-    if (parsed_message.GetDictionary("result", &result_dict)) {
-      bool has_damage;
-      if (result_dict->GetBoolean("hasDamage", &has_damage))
-        ++begin_frame_count_;
-    }
-    return false;
-  }
-
-  int begin_frame_count() const { return begin_frame_count_; }
-
- private:
-  HeadlessDevToolsClient* client_;  // NOT OWNED.
-  int begin_frame_count_ = 0;
-};
-
-bool DecodePNG(std::string png_data, SkBitmap* bitmap) {
-  return gfx::PNGCodec::Decode(
-      reinterpret_cast<unsigned const char*>(png_data.data()), png_data.size(),
-      bitmap);
-}
-
-}  // namespace
-
-class CompositorControllerBrowserTest
-    : public HeadlessAsyncDevTooledBrowserTest,
-      public ::testing::WithParamInterface<bool> {
- public:
-  class AdditionalVirtualTimeBudget
-      : public VirtualTimeController::RepeatingTask,
-        public VirtualTimeController::Observer {
-   public:
-    AdditionalVirtualTimeBudget(
-        VirtualTimeController* virtual_time_controller,
-        StartPolicy start_policy,
-        base::TimeDelta budget,
-        base::OnceClosure budget_expired_callback,
-        base::OnceClosure virtual_time_started_callback = base::OnceClosure())
-        : RepeatingTask(start_policy, 0),
-          virtual_time_controller_(virtual_time_controller),
-          budget_expired_callback_(std::move(budget_expired_callback)),
-          virtual_time_started_callback_(
-              std::move(virtual_time_started_callback)) {
-      virtual_time_controller_->ScheduleRepeatingTask(this, budget);
-      virtual_time_controller_->AddObserver(this);
-      virtual_time_controller_->StartVirtualTime();
-    }
-
-    ~AdditionalVirtualTimeBudget() override {
-      virtual_time_controller_->RemoveObserver(this);
-      virtual_time_controller_->CancelRepeatingTask(this);
-    }
-
-    // headless::VirtualTimeController::RepeatingTask implementation:
-    void IntervalElapsed(
-        base::TimeDelta virtual_time,
-        base::OnceCallback<void(ContinuePolicy)> continue_callback) override {
-      std::move(continue_callback).Run(ContinuePolicy::NOT_REQUIRED);
-    }
-
-    // headless::VirtualTimeController::Observer:
-    void VirtualTimeStarted(base::TimeDelta virtual_time_offset) override {
-      if (virtual_time_started_callback_)
-        std::move(virtual_time_started_callback_).Run();
-    }
-
-    void VirtualTimeStopped(base::TimeDelta virtual_time_offset) override {
-      std::move(budget_expired_callback_).Run();
-      delete this;
-    }
-
-   private:
-    headless::VirtualTimeController* const virtual_time_controller_;
-    base::OnceClosure budget_expired_callback_;
-    base::OnceClosure virtual_time_started_callback_;
-  };
-
-  void SetUp() override {
-    EnablePixelOutput();
-    if (GetParam()) {
-      UseSoftwareCompositing();
-      SetUpWithoutGPU();
-    } else {
-      HeadlessAsyncDevTooledBrowserTest::SetUp();
-    }
-  }
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    HeadlessAsyncDevTooledBrowserTest::SetUpCommandLine(command_line);
-    // See bit.ly/headless-rendering for why we use these flags.
-    command_line->AppendSwitch(switches::kRunAllCompositorStagesBeforeDraw);
-    command_line->AppendSwitch(switches::kDisableNewContentRenderingTimeout);
-    command_line->AppendSwitch(cc::switches::kDisableCheckerImaging);
-    command_line->AppendSwitch(cc::switches::kDisableThreadedAnimation);
-    command_line->AppendSwitch(switches::kDisableImageAnimationResync);
-    command_line->AppendSwitch(switches::kDisableThreadedScrolling);
-
-    scoped_feature_list_.InitAndEnableFeature(
-        features::kEnableSurfaceSynchronization);
-  }
-
-  bool GetEnableBeginFrameControl() override { return true; }
-
-  void RunDevTooledTest() override {
-    EXPECT_TRUE(embedded_test_server()->Start());
-
-    virtual_time_controller_ =
-        std::make_unique<VirtualTimeController>(devtools_client_.get());
-    const bool update_display_for_animations = false;
-    compositor_controller_ = std::make_unique<CompositorController>(
-        browser()->BrowserMainThread(), devtools_client_.get(),
-        virtual_time_controller_.get(), GetAnimationFrameInterval(),
-        update_display_for_animations);
-
-    // Initially pause virtual time.
-    devtools_client_->GetEmulation()->GetExperimental()->SetVirtualTimePolicy(
-        emulation::SetVirtualTimePolicyParams::Builder()
-            .SetPolicy(emulation::VirtualTimePolicy::PAUSE)
-            .SetInitialVirtualTime(100)
-            .Build(),
-        base::BindRepeating(
-            &CompositorControllerBrowserTest::SetVirtualTimePolicyDone,
-            base::Unretained(this)));
-  }
-
- protected:
-  virtual base::TimeDelta GetAnimationFrameInterval() const {
-    return base::TimeDelta::FromMilliseconds(16);
-  }
-
-  virtual std::string GetTestFile() const { return "/blank.html"; }
-
-  void SetVirtualTimePolicyDone(
-      std::unique_ptr<emulation::SetVirtualTimePolicyResult>) {
-    // Run a first BeginFrame to initialize surface. Wait a while before doing
-    // so, since it takes a while before the compositor is ready for a
-    // RenderFrameSubmissionObserver.
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE,
-        base::BindOnce(&CompositorControllerBrowserTest::RunFirstBeginFrame,
-                       base::Unretained(this)),
-        base::TimeDelta::FromSeconds(1));
-  }
-
-  void RunFirstBeginFrame() {
-    begin_frame_counter_ =
-        std::make_unique<BeginFrameCounter>(devtools_client_.get());
-    render_frame_submission_observer_ =
-        std::make_unique<content::RenderFrameSubmissionObserver>(
-            HeadlessWebContentsImpl::From(web_contents_)->web_contents());
-    // AdditionalVirtualTimeBudget will self delete.
-    new AdditionalVirtualTimeBudget(
-        virtual_time_controller_.get(),
-        AdditionalVirtualTimeBudget::StartPolicy::WAIT_FOR_NAVIGATION,
-        GetAnimationFrameInterval(),
-        base::BindOnce(
-            &CompositorControllerBrowserTest::OnFirstBeginFrameComplete,
-            base::Unretained(this)),
-        base::BindOnce(&CompositorControllerBrowserTest::Navigate,
-                       base::Unretained(this)));
-  }
-
-  void Navigate() {
-    // Navigate (after the first BeginFrame) to start virtual time.
-    devtools_client_->GetPage()->Navigate(
-        embedded_test_server()->GetURL(GetTestFile()).spec());
-  }
-
-  virtual void OnFirstBeginFrameComplete() {
-    // With surface sync enabled, we should have waited for the renderer's
-    // CompositorFrame in the first BeginFrame.
-    EXPECT_SCOPED(ExpectAdditionalFrameCounts(1, 1));
-  }
-
-  void FinishCompositorControllerTest() {
-    render_frame_submission_observer_.reset();
-    FinishAsynchronousTest();
-  }
-
-  void ExpectAdditionalFrameCounts(int additional_begin_frame_count,
-                                   int additional_render_frame_count) {
-    expected_begin_frame_count_ += additional_begin_frame_count;
-    expected_render_frame_count_ += additional_render_frame_count;
-    EXPECT_EQ(expected_begin_frame_count_,
-              begin_frame_counter_->begin_frame_count());
-    EXPECT_EQ(expected_render_frame_count_,
-              render_frame_submission_observer_->render_frame_count());
-  }
-
-  base::test::ScopedFeatureList scoped_feature_list_;
-
-  std::unique_ptr<VirtualTimeController> virtual_time_controller_;
-  std::unique_ptr<CompositorController> compositor_controller_;
-
-  std::unique_ptr<BeginFrameCounter> begin_frame_counter_;
-  std::unique_ptr<content::RenderFrameSubmissionObserver>
-      render_frame_submission_observer_;
-
-  int expected_begin_frame_count_ = 0;
-  int expected_render_frame_count_ = 0;
-};
-
-// Runs requestAnimationFrame three times without updating display for
-// animations and takes a screenshot.
-class CompositorControllerRafBrowserTest
-    : public CompositorControllerBrowserTest,
-      public runtime::Observer {
- private:
-  void OnFirstBeginFrameComplete() override {
-    CompositorControllerBrowserTest::OnFirstBeginFrameComplete();
-
-    devtools_client_->GetRuntime()->AddObserver(this);
-    devtools_client_->GetRuntime()->Enable(
-        base::BindRepeating(&CompositorControllerRafBrowserTest::RuntimeEnabled,
-                            base::Unretained(this)));
-  }
-
-  void RuntimeEnabled() {
-    // Request animation frames in the main frame. Each frame changes the body
-    // background color.
-    devtools_client_->GetRuntime()->Evaluate(
-        "window.rafCount = 0;"
-        "function onRaf(timestamp) {"
-        "  console.log('rAF timestamp ' + timestamp + 'ms'); "
-        "  window.rafCount++;"
-        "  document.body.style.backgroundColor = '#' + window.rafCount * 100;"
-        "  window.requestAnimationFrame(onRaf);"
-        "};"
-        "window.requestAnimationFrame(onRaf);",
-        base::BindRepeating(&CompositorControllerRafBrowserTest::OnRafReady,
-                            base::Unretained(this)));
-  }
-
-  // runtime::Observer implementation:
-  void OnConsoleAPICalled(
-      const runtime::ConsoleAPICalledParams& params) override {
-    // We expect the arguments always to be a single string.
-    const std::vector<std::unique_ptr<runtime::RemoteObject>>& args =
-        *params.GetArgs();
-    if (args.size() == 1u && args[0]->HasValue())
-      log_.push_back(args[0]->GetValue()->GetString());
-  }
-
-  void OnRafReady(std::unique_ptr<runtime::EvaluateResult> result) {
-    EXPECT_NE(nullptr, result);
-    EXPECT_FALSE(result->HasExceptionDetails());
-
-    // AdditionalVirtualTimeBudget will self delete.
-    new AdditionalVirtualTimeBudget(
-        virtual_time_controller_.get(),
-        AdditionalVirtualTimeBudget::StartPolicy::START_IMMEDIATELY,
-        kNumFrames * GetAnimationFrameInterval(),
-        base::BindOnce(&CompositorControllerRafBrowserTest::OnRafBudgetExpired,
-                       base::Unretained(this)));
-  }
-
-  void OnRafBudgetExpired() {
-    // Even though the rAF made a change to the frame's background color, no
-    // further CompositorFrames should have been produced for animations,
-    // because update_display_for_animations is false.
-    EXPECT_SCOPED(ExpectAdditionalFrameCounts(kNumFrames, 0));
-
-    // Get animation frame count.
-    devtools_client_->GetRuntime()->Evaluate(
-        "window.rafCount",
-        base::BindRepeating(&CompositorControllerRafBrowserTest::OnGetRafCount,
-                            base::Unretained(this)));
-  }
-
-  void OnGetRafCount(std::unique_ptr<runtime::EvaluateResult> result) {
-    EXPECT_NE(nullptr, result);
-    EXPECT_FALSE(result->HasExceptionDetails());
-
-    EXPECT_EQ(kNumFrames, result->GetResult()->GetValue()->GetInt());
-
-    compositor_controller_->CaptureScreenshot(
-        headless_experimental::ScreenshotParamsFormat::PNG, 100,
-        base::BindRepeating(&CompositorControllerRafBrowserTest::OnScreenshot,
-                            base::Unretained(this)));
-  }
-
-  void OnScreenshot(const std::string& screenshot_data) {
-    // Screenshot should have incurred a new CompositorFrame from renderer.
-    EXPECT_SCOPED(ExpectAdditionalFrameCounts(1, 1));
-    EXPECT_LT(0U, screenshot_data.length());
-
-    if (screenshot_data.length()) {
-      SkBitmap result_bitmap;
-      EXPECT_TRUE(DecodePNG(screenshot_data, &result_bitmap));
-
-      EXPECT_EQ(800, result_bitmap.width());
-      EXPECT_EQ(600, result_bitmap.height());
-      SkColor actual_color = result_bitmap.getColor(200, 200);
-      // Screenshot was the forth frame, so background color should be #400.
-      SkColor expected_color = SkColorSetRGB(0x44, 0x00, 0x00);
-      EXPECT_EQ(expected_color, actual_color);
-    }
-
-    EXPECT_THAT(log_, ElementsAre("rAF timestamp 16ms", "rAF timestamp 32ms",
-                                  "rAF timestamp 48ms", "rAF timestamp 64ms"));
-
-    FinishCompositorControllerTest();
-  }
-
-  static constexpr int kNumFrames = 3;
-  std::vector<std::string> log_;
-};
-
-/* static */
-constexpr int CompositorControllerRafBrowserTest::kNumFrames;
-
-HEADLESS_ASYNC_DEVTOOLED_TEST_P(CompositorControllerRafBrowserTest);
-
-// Instantiate test case for both software and gpu compositing modes.
-INSTANTIATE_TEST_CASE_P(CompositorControllerRafBrowserTests,
-                        CompositorControllerRafBrowserTest,
-                        ::testing::Bool());
-
-// Loads an animated GIF and verifies that:
-// - animate_only BeginFrames don't produce CompositorFrames,
-// - first screenshot starts the GIF animation,
-// - animation is advanced according to virtual time.
-// - the animation is not resynced after the first iteration.
-class CompositorControllerImageAnimationBrowserTest
-    : public CompositorControllerBrowserTest {
- private:
-  base::TimeDelta GetAnimationFrameInterval() const override {
-    return base::TimeDelta::FromMilliseconds(500);
-  }
-
-  std::string GetTestFile() const override {
-    // GIF: 1 second blue, 1 second red, 1 second yellow (100x100px).
-    return "/animated_gif.html";
-  }
-
-  void OnFirstBeginFrameComplete() override {
-    CompositorControllerBrowserTest::OnFirstBeginFrameComplete();
-
-    // Post a task to grant more virtual time as we can't do this synchronously
-    // from within VirtualTimeStopped().
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(&CompositorControllerImageAnimationBrowserTest::
-                           GrantFirstIterationBudget,
-                       base::Unretained(this)));
-  }
-
-  void GrantFirstIterationBudget() {
-    // AdditionalVirtualTimeBudget will self delete.
-    new AdditionalVirtualTimeBudget(
-        virtual_time_controller_.get(),
-        AdditionalVirtualTimeBudget::StartPolicy::START_IMMEDIATELY,
-        kNumFramesFirstIteration * GetAnimationFrameInterval(),
-        base::BindOnce(&CompositorControllerImageAnimationBrowserTest::
-                           OnFirstBudgetExpired,
-                       base::Unretained(this)));
-  }
-
-  void OnFirstBudgetExpired() {
-    // The GIF should not have started animating yet, even though we advanced
-    // virtual time. It only starts animating when first painted, i.e. when the
-    // first screenshot is taken.
-    EXPECT_SCOPED(ExpectAdditionalFrameCounts(kNumFramesFirstIteration, 0));
-
-    compositor_controller_->CaptureScreenshot(
-        headless_experimental::ScreenshotParamsFormat::PNG, 100,
-        base::BindRepeating(&CompositorControllerImageAnimationBrowserTest::
-                                OnScreenshotAfterFirstIteration,
-                            base::Unretained(this)));
-  }
-
-  void OnScreenshotAfterFirstIteration(const std::string& screenshot_data) {
-    // Screenshot should have incurred a new CompositorFrame from renderer.
-    EXPECT_SCOPED(ExpectAdditionalFrameCounts(1, 1));
-    EXPECT_LT(0U, screenshot_data.length());
-
-    if (screenshot_data.length()) {
-      SkBitmap result_bitmap;
-      EXPECT_TRUE(DecodePNG(screenshot_data, &result_bitmap));
-
-      EXPECT_EQ(800, result_bitmap.width());
-      EXPECT_EQ(600, result_bitmap.height());
-      SkColor actual_color = result_bitmap.getColor(50, 50);
-      // Animation starts when first screenshot is taken, so should be blue.
-      SkColor expected_color = SkColorSetRGB(0x00, 0x00, 0xff);
-      EXPECT_EQ(expected_color, actual_color);
-    }
-
-    // Advance another iteration and check again that no CompositorFrames are
-    // produced. AdditionalVirtualTimeBudget will self delete.
-    new AdditionalVirtualTimeBudget(
-        virtual_time_controller_.get(),
-        AdditionalVirtualTimeBudget::StartPolicy::START_IMMEDIATELY,
-        kNumFramesSecondIteration * GetAnimationFrameInterval(),
-        base::BindOnce(&CompositorControllerImageAnimationBrowserTest::
-                           OnSecondBudgetExpired,
-                       base::Unretained(this)));
-  }
-
-  void OnSecondBudgetExpired() {
-    // Even though the GIF animated, no further CompositorFrames should have
-    // been produced, because update_display_for_animations is false. The second
-    // iteration only produces kNumFramesSecondIteration - 1 BeginFrames since
-    // the first animation frame is skipped because of the prior screenshot.
-    EXPECT_SCOPED(
-        ExpectAdditionalFrameCounts(kNumFramesSecondIteration - 1, 0));
-
-    compositor_controller_->CaptureScreenshot(
-        headless_experimental::ScreenshotParamsFormat::PNG, 100,
-        base::BindRepeating(&CompositorControllerImageAnimationBrowserTest::
-                                OnScreenshotAfterSecondIteration,
-                            base::Unretained(this)));
-  }
-
-  void OnScreenshotAfterSecondIteration(const std::string& screenshot_data) {
-    // Screenshot should have incurred a new CompositorFrame from renderer.
-    EXPECT_SCOPED(ExpectAdditionalFrameCounts(1, 1));
-
-    EXPECT_LT(0U, screenshot_data.length());
-
-    if (screenshot_data.length()) {
-      SkBitmap result_bitmap;
-      EXPECT_TRUE(DecodePNG(screenshot_data, &result_bitmap));
-
-      EXPECT_EQ(800, result_bitmap.width());
-      EXPECT_EQ(600, result_bitmap.height());
-      SkColor actual_color = result_bitmap.getColor(50, 50);
-      // We advanced two animation frames, so animation should now be yellow.
-      SkColor expected_color = SkColorSetRGB(0xff, 0xff, 0x00);
-      EXPECT_EQ(expected_color, actual_color);
-    }
-
-    // Advance a full animation iteration and check that animation doesn't reset
-    // to the beginning, because of kDisableImageAnimationResync.
-    new AdditionalVirtualTimeBudget(
-        virtual_time_controller_.get(),
-        AdditionalVirtualTimeBudget::StartPolicy::START_IMMEDIATELY,
-        kNumFramesThirdIteration * GetAnimationFrameInterval(),
-        base::BindOnce(&CompositorControllerImageAnimationBrowserTest::
-                           OnThirdBudgetExpired,
-                       base::Unretained(this)));
-  }
-
-  void OnThirdBudgetExpired() {
-    // Even though the GIF animated, no further CompositorFrames should have
-    // been produced, because update_display_for_animations is false. The third
-    // iteration only produces kNumFramesThirdIteration - 1 BeginFrames since
-    // the first animation frame is skipped because of the prior screenshot.
-    EXPECT_SCOPED(ExpectAdditionalFrameCounts(kNumFramesThirdIteration - 1, 0));
-
-    compositor_controller_->CaptureScreenshot(
-        headless_experimental::ScreenshotParamsFormat::PNG, 100,
-        base::BindRepeating(&CompositorControllerImageAnimationBrowserTest::
-                                OnScreenshotAfterThirdIteration,
-                            base::Unretained(this)));
-  }
-
-  void OnScreenshotAfterThirdIteration(const std::string& screenshot_data) {
-    // Screenshot should have incurred no new CompositorFrame from renderer
-    // since animation frame didn't change, but a new BeginFrame.
-    EXPECT_SCOPED(ExpectAdditionalFrameCounts(1, 0));
-    EXPECT_LT(0U, screenshot_data.length());
-
-    if (screenshot_data.length()) {
-      SkBitmap result_bitmap;
-      EXPECT_TRUE(DecodePNG(screenshot_data, &result_bitmap));
-
-      EXPECT_EQ(800, result_bitmap.width());
-      EXPECT_EQ(600, result_bitmap.height());
-      SkColor actual_color = result_bitmap.getColor(50, 50);
-      // We advanced a full iteration, so animation should be yellow again.
-      SkColor expected_color = SkColorSetRGB(0xff, 0xff, 0x00);
-      EXPECT_EQ(expected_color, actual_color);
-    }
-
-    FinishCompositorControllerTest();
-  }
-
-  // Enough to cover a full animation iteration.
-  static constexpr int kNumFramesFirstIteration = 7;
-  // Advances two animation frames only.
-  static constexpr int kNumFramesSecondIteration = 5;
-  // Advances a full animation iteration.
-  static constexpr int kNumFramesThirdIteration = 6;
-};
-
-/* static */
-constexpr int
-    CompositorControllerImageAnimationBrowserTest::kNumFramesFirstIteration;
-/* static */
-constexpr int
-    CompositorControllerImageAnimationBrowserTest::kNumFramesSecondIteration;
-/* static */
-constexpr int
-    CompositorControllerImageAnimationBrowserTest::kNumFramesThirdIteration;
-
-HEADLESS_ASYNC_DEVTOOLED_TEST_P(CompositorControllerImageAnimationBrowserTest);
-
-// Instantiate test case for both software and gpu compositing modes.
-INSTANTIATE_TEST_CASE_P(CompositorControllerImageAnimationBrowserTests,
-                        CompositorControllerImageAnimationBrowserTest,
-                        ::testing::Bool());
-
-// Loads a CSS animation and verifies that:
-// - animate_only BeginFrames don't produce CompositorFrames,
-// - animate_only BeginFrames advance animations and trigger itersection events,
-// - animation is advanced according to virtual time.
-class CompositorControllerCssAnimationBrowserTest
-    : public CompositorControllerBrowserTest,
-      public runtime::Observer {
- private:
-  base::TimeDelta GetAnimationFrameInterval() const override {
-    return base::TimeDelta::FromMilliseconds(500);
-  }
-
-  std::string GetTestFile() const override {
-    // Animates opacity of a blue 100px square on red blackground over 4
-    // seconds (100% -> 0% -> 100% four times). Logs events to console.
-    //
-    // Timeline:
-    //      0 ms:  --- animation starts at 500ms ---
-    //    500 ms:  100% opacity  -> blue background.
-    //   1000 ms:    0% opacity  ->  red background.
-    //   1500 ms:  100% opacity  -> blue background.
-    //   2000 ms:    0% opacity  ->  red background.
-    //   2500 ms:  100% opacity  -> blue background.
-    //   3000 ms:    0% opacity  ->  red background.
-    //   3500 ms:  100% opacity  -> blue background.
-    //   4000 ms:    0% opacity  ->  red background.
-    //   4500 ms:  100% opacity  -> blue background.
-    //
-    // The animation will start with the first BeginFrame after load.
-    return "/css_animation.html";
-  }
-
-  void OnFirstBeginFrameComplete() override {
-    CompositorControllerBrowserTest::OnFirstBeginFrameComplete();
-
-    // First frame advanced one BeginFrame interval.
-    elapsed_time_ += GetAnimationFrameInterval();
-
-    // First BeginFrame advanced by one interval.
-    devtools_client_->GetRuntime()->AddObserver(this);
-    devtools_client_->GetRuntime()->Enable(base::BindRepeating(
-        &CompositorControllerCssAnimationBrowserTest::RuntimeEnabled,
-        base::Unretained(this)));
-  }
-
-  void RuntimeEnabled() {
-    // Animation starts with the first BeginFrame of this budget. Advance five
-    // frames to reach 3000ms, at which point the background should be red.
-    GrantBudget(GetAnimationFrameInterval() * 5);
-  }
-
-  void GrantBudget(base::TimeDelta budget) {
-    // Grant the budget in two halves, with screenshots at the end of each.
-    // AdditionalVirtualTimeBudget will self delete.
-    new AdditionalVirtualTimeBudget(
-        virtual_time_controller_.get(),
-        AdditionalVirtualTimeBudget::StartPolicy::START_IMMEDIATELY, budget,
-        base::BindOnce(
-            &CompositorControllerCssAnimationBrowserTest::OnBudgetExpired,
-            base::Unretained(this), budget));
-  }
-
-  void OnBudgetExpired(base::TimeDelta budget) {
-    elapsed_time_ += budget;
-
-    EXPECT_THAT(
-        elapsed_time_,
-        testing::AnyOf(testing::Eq(base::TimeDelta::FromMilliseconds(3000)),
-                       testing::Eq(base::TimeDelta::FromMilliseconds(4500))));
-
-    if (elapsed_time_ == base::TimeDelta::FromMilliseconds(3000)) {
-      // We should have advanced five BeginFrames. No CompositorFrames from
-      // renderer because update_display_for_animations is false.
-      EXPECT_SCOPED(ExpectAdditionalFrameCounts(5, 0));
-    } else {
-      // We should have advanced two more BeginFrames since the second budget
-      // was preceded by a screenshot. No CompositorFrames from renderer
-      // because update_display_for_animations is false.
-      EXPECT_SCOPED(ExpectAdditionalFrameCounts(2, 0));
-    }
-
-    compositor_controller_->CaptureScreenshot(
-        headless_experimental::ScreenshotParamsFormat::PNG, 100,
-        base::BindRepeating(
-            &CompositorControllerCssAnimationBrowserTest::OnScreenshot,
-            base::Unretained(this)));
-  }
-
-  void OnScreenshot(const std::string& screenshot_data) {
-    // Screenshot should have incurred a new CompositorFrame from renderer.
-    EXPECT_SCOPED(ExpectAdditionalFrameCounts(1, 1));
-    EXPECT_LT(0U, screenshot_data.length());
-
-    if (screenshot_data.length()) {
-      SkBitmap result_bitmap;
-      EXPECT_TRUE(DecodePNG(screenshot_data, &result_bitmap));
-
-      EXPECT_EQ(800, result_bitmap.width());
-      EXPECT_EQ(600, result_bitmap.height());
-      SkColor actual_color = result_bitmap.getColor(50, 50);
-
-      // First screenshot should be red, because box is not visible.
-      SkColor expected_color = SkColorSetRGB(0xff, 0x00, 0x00);
-      if (elapsed_time_ == base::TimeDelta::FromMilliseconds(4500)) {
-        // Box is visible in second screenshot, so it should be blue.
-        expected_color = SkColorSetRGB(0x00, 0x00, 0xff);
-      }
-
-      EXPECT_EQ(expected_color, actual_color);
-    }
-
-    if (elapsed_time_ == base::TimeDelta::FromMilliseconds(3000)) {
-      // Advance to the end of the animation.
-      GrantBudget(base::TimeDelta::FromMilliseconds(1500));
-    } else {
-      EXPECT_THAT(log_, testing::ElementsAre(
-                            // Animation actually started at 500ms, but the
-                            // event is executed a BeginFrame later.
-                            "event animationstart at 101000ms",
-                            "event animationiteration at 101500ms",
-                            "event animationiteration at 102500ms",
-                            "event animationiteration at 103500ms",
-                            "event animationend at 104500ms"));
-      FinishCompositorControllerTest();
-    }
-  }
-
-  // runtime::Observer implementation:
-  void OnConsoleAPICalled(
-      const runtime::ConsoleAPICalledParams& params) override {
-    // We expect the arguments always to be a single string.
-    const std::vector<std::unique_ptr<runtime::RemoteObject>>& args =
-        *params.GetArgs();
-    if (args.size() == 1u && args[0]->HasValue())
-      log_.push_back(args[0]->GetValue()->GetString());
-  }
-
-  base::TimeDelta elapsed_time_;
-  std::vector<std::string> log_;
-};
-
-HEADLESS_ASYNC_DEVTOOLED_TEST_P(CompositorControllerCssAnimationBrowserTest);
-
-// Instantiate test case for both software and gpu compositing modes.
-INSTANTIATE_TEST_CASE_P(CompositorControllerCssAnimationBrowserTests,
-                        CompositorControllerCssAnimationBrowserTest,
-                        ::testing::Bool());
-
-#endif  // !defined(OS_MACOSX)
-
-}  // namespace headless
diff --git a/headless/public/util/compositor_controller_unittest.cc b/headless/public/util/compositor_controller_unittest.cc
deleted file mode 100644
index 016ee8f..0000000
--- a/headless/public/util/compositor_controller_unittest.cc
+++ /dev/null
@@ -1,415 +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 "headless/public/util/compositor_controller.h"
-
-#include <memory>
-
-#include "base/base64.h"
-#include "base/bind.h"
-#include "base/json/json_writer.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "base/test/test_simple_task_runner.h"
-#include "headless/public/internal/headless_devtools_client_impl.h"
-#include "headless/public/util/virtual_time_controller.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace headless {
-
-namespace {
-static constexpr base::TimeDelta kAnimationFrameInterval =
-    base::TimeDelta::FromMilliseconds(16);
-
-class MockChannel : public HeadlessDevToolsChannel {
- public:
-  MockChannel() {}
-  ~MockChannel() override {}
-  MOCK_METHOD1(SetClient, void(HeadlessDevToolsChannel::Client*));
-  MOCK_METHOD1(SendProtocolMessage, void(const std::string&));
-};
-
-}  // namespace
-
-using testing::_;
-using testing::Return;
-
-class TestVirtualTimeController : public VirtualTimeController {
- public:
-  TestVirtualTimeController(HeadlessDevToolsClient* devtools_client)
-      : VirtualTimeController(devtools_client) {}
-  ~TestVirtualTimeController() override = default;
-
-  MOCK_METHOD0(StartVirtualTime, void());
-  MOCK_METHOD2(ScheduleRepeatingTask,
-               void(RepeatingTask* task, base::TimeDelta interval));
-  MOCK_METHOD1(CancelRepeatingTask, void(RepeatingTask* task));
-  MOCK_METHOD1(AddObserver, void(Observer* observer));
-  MOCK_METHOD1(RemoveObserver, void(Observer* observer));
-  MOCK_METHOD1(SetResumeDeferrer, void(ResumeDeferrer* deferrer));
-
-  MOCK_CONST_METHOD0(GetVirtualTimeBase, base::TimeTicks());
-  MOCK_CONST_METHOD0(GetCurrentVirtualTimeOffset, base::TimeDelta());
-};
-
-class CompositorControllerTest : public ::testing::Test {
- protected:
-  CompositorControllerTest(bool update_display_for_animations = true) {
-    task_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>();
-    auto channel = std::make_unique<MockChannel>();
-    mock_channel_ = channel.get();
-    client_.AttachToChannel(std::move(channel));
-    client_.SetTaskRunnerForTests(task_runner_);
-
-    virtual_time_controller_ =
-        std::make_unique<TestVirtualTimeController>(&client_);
-    EXPECT_CALL(*virtual_time_controller_,
-                ScheduleRepeatingTask(_, kAnimationFrameInterval))
-        .WillOnce(testing::SaveArg<0>(&task_));
-    EXPECT_CALL(*virtual_time_controller_, SetResumeDeferrer(_))
-        .WillOnce(testing::SaveArg<0>(&deferrer_));
-    ExpectHeadlessExperimentalEnable();
-    controller_ = std::make_unique<CompositorController>(
-        task_runner_, &client_, virtual_time_controller_.get(),
-        kAnimationFrameInterval, update_display_for_animations);
-    EXPECT_NE(nullptr, task_);
-  }
-
-  ~CompositorControllerTest() override {
-    EXPECT_CALL(*virtual_time_controller_, CancelRepeatingTask(_));
-    EXPECT_CALL(*virtual_time_controller_, SetResumeDeferrer(_));
-  }
-
-  void ExpectHeadlessExperimentalEnable() {
-    last_command_id_ += 2;
-    EXPECT_CALL(*mock_channel_,
-                SendProtocolMessage(base::StringPrintf(
-                    "{\"id\":%d,\"method\":\"HeadlessExperimental.enable\","
-                    "\"params\":{}}",
-                    last_command_id_)));
-  }
-
-  void ExpectVirtualTime(double base, double offset) {
-    auto base_time_ticks =
-        base::TimeTicks() + base::TimeDelta::FromMillisecondsD(base);
-    auto offset_delta = base::TimeDelta::FromMilliseconds(offset);
-    EXPECT_CALL(*virtual_time_controller_, GetVirtualTimeBase())
-        .WillOnce(Return(base_time_ticks));
-    EXPECT_CALL(*virtual_time_controller_, GetCurrentVirtualTimeOffset())
-        .WillOnce(Return(offset_delta));
-
-    // Next BeginFrame's time should be the virtual time provided it has
-    // progressed.
-    base::TimeTicks virtual_time = base_time_ticks + offset_delta;
-    if (virtual_time > next_begin_frame_time_)
-      next_begin_frame_time_ = virtual_time;
-  }
-
-  void ExpectBeginFrame(bool no_display_updates = false,
-                        std::unique_ptr<headless_experimental::ScreenshotParams>
-                            screenshot_params = nullptr) {
-    last_command_id_ += 2;
-    base::DictionaryValue params;
-    auto builder = std::move(
-        headless_experimental::BeginFrameParams::Builder()
-            .SetFrameTimeTicks(
-                (next_begin_frame_time_ - base::TimeTicks()).InMillisecondsF())
-            .SetInterval(kAnimationFrameInterval.InMillisecondsF())
-            .SetNoDisplayUpdates(no_display_updates));
-    if (screenshot_params)
-      builder.SetScreenshot(std::move(screenshot_params));
-    // Subsequent BeginFrames should have a later timestamp.
-    next_begin_frame_time_ += base::TimeDelta::FromMicroseconds(1);
-
-    std::string params_json;
-    auto params_value = builder.Build()->Serialize();
-    base::JSONWriter::Write(*params_value, &params_json);
-
-    EXPECT_CALL(*mock_channel_,
-                SendProtocolMessage(base::StringPrintf(
-                    "{\"id\":%d,\"method\":\"HeadlessExperimental.beginFrame\","
-                    "\"params\":%s}",
-                    last_command_id_, params_json.c_str())));
-  }
-
-  void SendBeginFrameReply(bool has_damage,
-                           const std::string& screenshot_data) {
-    auto result = headless_experimental::BeginFrameResult::Builder()
-                      .SetHasDamage(has_damage)
-                      .Build();
-    if (screenshot_data.length())
-      result->SetScreenshotData(screenshot_data);
-    std::string result_json;
-    auto result_value = result->Serialize();
-    base::JSONWriter::Write(*result_value, &result_json);
-
-    client_.ReceiveProtocolMessage(base::StringPrintf(
-        "{\"id\":%d,\"result\":%s}", last_command_id_, result_json.c_str()));
-    task_runner_->RunPendingTasks();
-  }
-
-  void SendNeedsBeginFramesEvent(bool needs_begin_frames) {
-    client_.ReceiveProtocolMessage(
-        base::StringPrintf("{\"method\":\"HeadlessExperimental."
-                           "needsBeginFramesChanged\",\"params\":{"
-                           "\"needsBeginFrames\":%s}}",
-                           needs_begin_frames ? "true" : "false"));
-    // Events are dispatched asynchronously.
-    task_runner_->RunPendingTasks();
-  }
-
-  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
-  HeadlessDevToolsClientImpl client_;
-  MockChannel* mock_channel_ = nullptr;
-  std::unique_ptr<TestVirtualTimeController> virtual_time_controller_;
-  std::unique_ptr<CompositorController> controller_;
-  int last_command_id_ = -2;
-  TestVirtualTimeController::RepeatingTask* task_ = nullptr;
-  TestVirtualTimeController::Observer* observer_ = nullptr;
-  TestVirtualTimeController::ResumeDeferrer* deferrer_ = nullptr;
-  base::TimeTicks next_begin_frame_time_ =
-      base::TimeTicks() + base::TimeDelta::FromMicroseconds(1);
-};
-
-TEST_F(CompositorControllerTest, CaptureScreenshot) {
-  bool done = false;
-  controller_->CaptureScreenshot(
-      headless_experimental::ScreenshotParamsFormat::PNG, 100,
-      base::BindRepeating(
-          [](bool* done, const std::string& screenshot_data) {
-            *done = true;
-            EXPECT_EQ("test", screenshot_data);
-          },
-          &done));
-
-  EXPECT_TRUE(task_runner_->HasPendingTask());
-  ExpectVirtualTime(0, 0);
-  ExpectBeginFrame(
-      false, headless_experimental::ScreenshotParams::Builder()
-                 .SetFormat(headless_experimental::ScreenshotParamsFormat::PNG)
-                 .SetQuality(100)
-                 .Build());
-  task_runner_->RunPendingTasks();
-
-  std::string base64;
-  base::Base64Encode("test", &base64);
-  SendBeginFrameReply(true, base64);
-  EXPECT_FALSE(task_runner_->HasPendingTask());
-  EXPECT_TRUE(done);
-}
-
-TEST_F(CompositorControllerTest, SendsAnimationFrames) {
-  base::Optional<VirtualTimeController::RepeatingTask::ContinuePolicy>
-      continue_policy;
-  auto continue_callback = base::BindRepeating(
-      [](base::Optional<VirtualTimeController::RepeatingTask::ContinuePolicy>*
-             continue_policy,
-         VirtualTimeController::RepeatingTask::ContinuePolicy policy) {
-        *continue_policy = policy;
-      },
-      &continue_policy);
-
-  // Doesn't send BeginFrames before virtual time started.
-  SendNeedsBeginFramesEvent(true);
-  EXPECT_FALSE(task_runner_->HasPendingTask());
-
-  bool can_continue = false;
-  auto defer_callback = base::BindRepeating(
-      [](bool* can_continue) { *can_continue = true; }, &can_continue);
-
-  // Sends a BeginFrame at start of interval.
-  deferrer_->DeferResume(defer_callback);
-  EXPECT_TRUE(task_runner_->HasPendingTask());
-
-  ExpectVirtualTime(1000, 0);
-  ExpectBeginFrame();
-  task_runner_->RunPendingTasks();
-  EXPECT_FALSE(can_continue);
-
-  // Lets virtual time continue after BeginFrame was completed.
-  SendBeginFrameReply(false, std::string());
-  EXPECT_FALSE(task_runner_->HasPendingTask());
-  EXPECT_TRUE(can_continue);
-  can_continue = false;
-
-  // Sends a BeginFrame after interval elapsed, but only just before virtual
-  // time resumes.
-  task_->IntervalElapsed(kAnimationFrameInterval, continue_callback);
-  EXPECT_EQ(VirtualTimeController::RepeatingTask::ContinuePolicy::NOT_REQUIRED,
-            *continue_policy);
-  continue_policy = base::nullopt;
-  EXPECT_FALSE(task_runner_->HasPendingTask());
-
-  deferrer_->DeferResume(defer_callback);
-  EXPECT_TRUE(task_runner_->HasPendingTask());
-
-  ExpectVirtualTime(1000, kAnimationFrameInterval.InMillisecondsF());
-  ExpectBeginFrame();
-  task_runner_->RunPendingTasks();
-  EXPECT_FALSE(can_continue);
-
-  // Lets virtual time continue after BeginFrame was completed.
-  SendBeginFrameReply(false, std::string());
-  EXPECT_FALSE(task_runner_->HasPendingTask());
-  EXPECT_TRUE(can_continue);
-  can_continue = false;
-
-  // Doesn't send a BeginFrame if another task pauses and resumes virtual time.
-  deferrer_->DeferResume(defer_callback);
-  EXPECT_FALSE(task_runner_->HasPendingTask());
-  EXPECT_TRUE(can_continue);
-  can_continue = false;
-
-  // Sends another BeginFrame after next animation interval elapsed.
-  task_->IntervalElapsed(kAnimationFrameInterval, continue_callback);
-  EXPECT_EQ(VirtualTimeController::RepeatingTask::ContinuePolicy::NOT_REQUIRED,
-            *continue_policy);
-  continue_policy = base::nullopt;
-  EXPECT_FALSE(task_runner_->HasPendingTask());
-
-  deferrer_->DeferResume(defer_callback);
-  EXPECT_TRUE(task_runner_->HasPendingTask());
-
-  ExpectVirtualTime(1000, kAnimationFrameInterval.InMillisecondsF() * 2);
-  ExpectBeginFrame();
-  task_runner_->RunPendingTasks();
-  EXPECT_FALSE(can_continue);
-
-  // Lets virtual time continue after BeginFrame was completed.
-  SendBeginFrameReply(false, std::string());
-  EXPECT_FALSE(task_runner_->HasPendingTask());
-  EXPECT_TRUE(can_continue);
-  can_continue = false;
-}
-
-TEST_F(CompositorControllerTest, WaitUntilIdle) {
-  bool idle = false;
-  auto idle_callback =
-      base::BindRepeating([](bool* idle) { *idle = true; }, &idle);
-
-  SendNeedsBeginFramesEvent(true);
-  EXPECT_FALSE(task_runner_->HasPendingTask());
-
-  // WaitUntilIdle executes callback immediately if no BeginFrame is active.
-  controller_->WaitUntilIdle(idle_callback);
-  EXPECT_TRUE(idle);
-  idle = false;
-
-  // Send a BeginFrame.
-  task_->IntervalElapsed(
-      kAnimationFrameInterval,
-      base::BindRepeating(
-          [](VirtualTimeController::RepeatingTask::ContinuePolicy) {}));
-  EXPECT_FALSE(task_runner_->HasPendingTask());
-
-  bool can_continue = false;
-  auto defer_callback = base::BindRepeating(
-      [](bool* can_continue) { *can_continue = true; }, &can_continue);
-
-  deferrer_->DeferResume(defer_callback);
-  EXPECT_TRUE(task_runner_->HasPendingTask());
-
-  ExpectVirtualTime(1000, kAnimationFrameInterval.InMillisecondsF());
-  ExpectBeginFrame();
-  task_runner_->RunPendingTasks();
-  EXPECT_FALSE(can_continue);
-
-  // WaitUntilIdle only executes callback after BeginFrame was completed.
-  controller_->WaitUntilIdle(idle_callback);
-  EXPECT_FALSE(idle);
-
-  SendBeginFrameReply(false, std::string());
-  EXPECT_FALSE(task_runner_->HasPendingTask());
-  EXPECT_TRUE(idle);
-  idle = false;
-  EXPECT_TRUE(can_continue);
-  can_continue = false;
-}
-
-class CompositorControllerNoDisplayUpdateTest
-    : public CompositorControllerTest {
- protected:
-  CompositorControllerNoDisplayUpdateTest() : CompositorControllerTest(false) {}
-};
-
-TEST_F(CompositorControllerNoDisplayUpdateTest,
-       SkipsDisplayUpdateOnlyForAnimationFrames) {
-  base::Optional<VirtualTimeController::RepeatingTask::ContinuePolicy>
-      continue_policy;
-  auto continue_callback = base::BindRepeating(
-      [](base::Optional<VirtualTimeController::RepeatingTask::ContinuePolicy>*
-             continue_policy,
-         VirtualTimeController::RepeatingTask::ContinuePolicy policy) {
-        *continue_policy = policy;
-      },
-      &continue_policy);
-
-  SendNeedsBeginFramesEvent(true);
-  EXPECT_FALSE(task_runner_->HasPendingTask());
-
-  bool can_continue = false;
-  auto defer_callback = base::BindRepeating(
-      [](bool* can_continue) { *can_continue = true; }, &can_continue);
-
-  // Initial animation-BeginFrame always updates display (see comment in
-  // compositor_controller.cc).
-  deferrer_->DeferResume(defer_callback);
-  EXPECT_TRUE(task_runner_->HasPendingTask());
-
-  ExpectVirtualTime(1000, 0);
-  ExpectBeginFrame();
-  task_runner_->RunPendingTasks();
-  EXPECT_FALSE(can_continue);
-
-  // Lets virtual time continue after BeginFrame was completed.
-  SendBeginFrameReply(false, std::string());
-  EXPECT_FALSE(task_runner_->HasPendingTask());
-  EXPECT_TRUE(can_continue);
-  can_continue = false;
-
-  // Sends an animation BeginFrame without display update after interval
-  // elapsed.
-  task_->IntervalElapsed(kAnimationFrameInterval, continue_callback);
-  EXPECT_EQ(VirtualTimeController::RepeatingTask::ContinuePolicy::NOT_REQUIRED,
-            *continue_policy);
-  continue_policy = base::nullopt;
-  EXPECT_FALSE(task_runner_->HasPendingTask());
-
-  deferrer_->DeferResume(defer_callback);
-  EXPECT_TRUE(task_runner_->HasPendingTask());
-
-  ExpectVirtualTime(1000, kAnimationFrameInterval.InMillisecondsF());
-  ExpectBeginFrame(true);
-  task_runner_->RunPendingTasks();
-  EXPECT_FALSE(can_continue);
-
-  // Lets virtual time continue after BeginFrame was completed.
-  SendBeginFrameReply(false, std::string());
-  EXPECT_FALSE(task_runner_->HasPendingTask());
-  EXPECT_TRUE(can_continue);
-  can_continue = false;
-
-  // Screenshots update display.
-  task_->IntervalElapsed(kAnimationFrameInterval, continue_callback);
-  EXPECT_EQ(VirtualTimeController::RepeatingTask::ContinuePolicy::NOT_REQUIRED,
-            *continue_policy);
-  continue_policy = base::nullopt;
-  EXPECT_FALSE(task_runner_->HasPendingTask());
-
-  controller_->CaptureScreenshot(
-      headless_experimental::ScreenshotParamsFormat::PNG, 100,
-      base::BindRepeating([](const std::string&) {}));
-
-  EXPECT_TRUE(task_runner_->HasPendingTask());
-  ExpectVirtualTime(1000, kAnimationFrameInterval.InMillisecondsF() * 2);
-  ExpectBeginFrame(
-      false, headless_experimental::ScreenshotParams::Builder()
-                 .SetFormat(headless_experimental::ScreenshotParamsFormat::PNG)
-                 .SetQuality(100)
-                 .Build());
-  task_runner_->RunPendingTasks();
-}
-
-}  // namespace headless
diff --git a/headless/public/util/virtual_time_controller.cc b/headless/public/util/virtual_time_controller.cc
deleted file mode 100644
index 2a871bf7..0000000
--- a/headless/public/util/virtual_time_controller.cc
+++ /dev/null
@@ -1,229 +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 "headless/public/util/virtual_time_controller.h"
-
-#include "base/auto_reset.h"
-#include "base/bind.h"
-#include "base/logging.h"
-
-namespace headless {
-
-using base::TimeDelta;
-
-VirtualTimeController::VirtualTimeController(
-    HeadlessDevToolsClient* devtools_client,
-    int max_task_starvation_count)
-    : devtools_client_(devtools_client),
-      max_task_starvation_count_(max_task_starvation_count),
-      weak_ptr_factory_(this) {
-  devtools_client_->GetEmulation()->GetExperimental()->AddObserver(this);
-}
-
-VirtualTimeController::~VirtualTimeController() {
-  devtools_client_->GetEmulation()->GetExperimental()->RemoveObserver(this);
-}
-
-void VirtualTimeController::StartVirtualTime() {
-  if (virtual_time_started_)
-    return;
-
-  TimeDelta next_budget;
-  bool wait_for_navigation = false;
-  for (auto& entry_pair : tasks_) {
-    entry_pair.second.ready_to_advance = true;
-    if (entry_pair.first->start_policy() ==
-        RepeatingTask::StartPolicy::WAIT_FOR_NAVIGATION) {
-      wait_for_navigation = true;
-    }
-    if (next_budget.is_zero()) {
-      next_budget =
-          entry_pair.second.next_execution_time - total_elapsed_time_offset_;
-    } else {
-      next_budget =
-          std::min(next_budget, entry_pair.second.next_execution_time -
-                                    total_elapsed_time_offset_);
-    }
-  }
-
-  // If there's no budget, then don't do anything!
-  if (next_budget.is_zero())
-    return;
-
-  virtual_time_started_ = true;
-  should_send_start_notification_ = true;
-
-  if (resume_deferrer_) {
-    resume_deferrer_->DeferResume(base::BindOnce(
-        &VirtualTimeController::SetVirtualTimePolicy,
-        weak_ptr_factory_.GetWeakPtr(), next_budget, wait_for_navigation));
-  } else {
-    SetVirtualTimePolicy(next_budget, wait_for_navigation);
-  }
-}
-
-void VirtualTimeController::NotifyTasksAndAdvance() {
-  // The task may call its continue callback synchronously. Prevent re-entrance.
-  if (in_notify_tasks_and_advance_)
-    return;
-
-  base::AutoReset<bool> reset(&in_notify_tasks_and_advance_, true);
-
-  for (auto iter = tasks_.begin(); iter != tasks_.end();) {
-    auto entry_pair = iter++;
-    if (entry_pair->second.next_execution_time <= total_elapsed_time_offset_) {
-      entry_pair->second.ready_to_advance = false;
-      entry_pair->second.next_execution_time =
-          total_elapsed_time_offset_ + entry_pair->second.interval;
-
-      // This may delete itself.
-      entry_pair->first->IntervalElapsed(
-          total_elapsed_time_offset_,
-          base::BindOnce(&VirtualTimeController::TaskReadyToAdvance,
-                         weak_ptr_factory_.GetWeakPtr(),
-                         base::Unretained(&entry_pair->second)));
-    }
-  }
-
-  // Give at most as much virtual time as available until the next callback.
-  bool advance_virtual_time = false;
-  bool stop_virtual_time = false;
-  bool ready_to_advance = true;
-  TimeDelta next_budget;
-  for (const auto& entry_pair : tasks_) {
-    ready_to_advance &= entry_pair.second.ready_to_advance;
-    if (next_budget.is_zero()) {
-      next_budget =
-          entry_pair.second.next_execution_time - total_elapsed_time_offset_;
-    } else {
-      next_budget =
-          std::min(next_budget, entry_pair.second.next_execution_time -
-                                    total_elapsed_time_offset_);
-    }
-    if (entry_pair.second.continue_policy ==
-        RepeatingTask::ContinuePolicy::CONTINUE_MORE_TIME_NEEDED) {
-      advance_virtual_time = true;
-    } else if (entry_pair.second.continue_policy ==
-               RepeatingTask::ContinuePolicy::STOP) {
-      stop_virtual_time = true;
-    }
-  }
-
-  if (!ready_to_advance)
-    return;
-
-  if (!advance_virtual_time || stop_virtual_time) {
-    for (auto& entry_pair : tasks_) {
-      entry_pair.second.ready_to_advance = false;
-    }
-
-    for (auto iter = observers_.begin(); iter != observers_.end();) {
-      Observer* observer = *iter++;
-      // |observer| may delete itself.
-      observer->VirtualTimeStopped(total_elapsed_time_offset_);
-    }
-    virtual_time_started_ = false;
-    return;
-  }
-
-  DCHECK(!next_budget.is_zero());
-  if (resume_deferrer_) {
-    resume_deferrer_->DeferResume(
-        base::BindOnce(&VirtualTimeController::SetVirtualTimePolicy,
-                       weak_ptr_factory_.GetWeakPtr(), next_budget,
-                       false /* wait_for_navigation */));
-  } else {
-    SetVirtualTimePolicy(next_budget, false /* wait_for_navigation */);
-  }
-}
-
-void VirtualTimeController::TaskReadyToAdvance(
-    TaskEntry* entry,
-    RepeatingTask::ContinuePolicy continue_policy) {
-  entry->ready_to_advance = true;
-  entry->continue_policy = continue_policy;
-  NotifyTasksAndAdvance();
-}
-
-void VirtualTimeController::SetVirtualTimePolicy(base::TimeDelta next_budget,
-                                                 bool wait_for_navigation) {
-  last_budget_ = next_budget;
-  devtools_client_->GetEmulation()->GetExperimental()->SetVirtualTimePolicy(
-      emulation::SetVirtualTimePolicyParams::Builder()
-          .SetPolicy(
-              emulation::VirtualTimePolicy::PAUSE_IF_NETWORK_FETCHES_PENDING)
-          .SetBudget(next_budget.InMillisecondsF())
-          .SetMaxVirtualTimeTaskStarvationCount(max_task_starvation_count_)
-          .SetWaitForNavigation(wait_for_navigation)
-          .Build(),
-      base::BindOnce(&VirtualTimeController::SetVirtualTimePolicyDone,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void VirtualTimeController::SetVirtualTimePolicyDone(
-    std::unique_ptr<emulation::SetVirtualTimePolicyResult> result) {
-  if (result) {
-    virtual_time_base_ =
-        base::TimeTicks() +
-        base::TimeDelta::FromMillisecondsD(result->GetVirtualTimeTicksBase());
-  } else {
-    LOG(WARNING) << "SetVirtualTimePolicy did not succeed";
-  }
-
-  if (should_send_start_notification_) {
-    should_send_start_notification_ = false;
-    for (auto iter = observers_.begin(); iter != observers_.end();) {
-      Observer* observer = *iter++;
-      // |observer| may delete itself.
-      observer->VirtualTimeStarted(total_elapsed_time_offset_);
-    }
-  }
-}
-
-void VirtualTimeController::OnVirtualTimeBudgetExpired(
-    const emulation::VirtualTimeBudgetExpiredParams& params) {
-  total_elapsed_time_offset_ += last_budget_;
-  virtual_time_paused_ = true;
-  NotifyTasksAndAdvance();
-}
-
-void VirtualTimeController::ScheduleRepeatingTask(RepeatingTask* task,
-                                                  base::TimeDelta interval) {
-  if (!virtual_time_paused_) {
-    // We cannot accurately modify any previously granted virtual time budget.
-    LOG(WARNING) << "VirtualTimeController tasks should be added while "
-                    "virtual time is paused.";
-  }
-
-  TaskEntry entry;
-  entry.interval = interval;
-  entry.next_execution_time = total_elapsed_time_offset_ + entry.interval;
-  tasks_.insert(std::make_pair(task, entry));
-}
-
-void VirtualTimeController::CancelRepeatingTask(RepeatingTask* task) {
-  tasks_.erase(task);
-}
-
-void VirtualTimeController::AddObserver(Observer* observer) {
-  observers_.insert(observer);
-}
-
-void VirtualTimeController::RemoveObserver(Observer* observer) {
-  observers_.erase(observer);
-}
-
-base::TimeTicks VirtualTimeController::GetVirtualTimeBase() const {
-  return virtual_time_base_;
-}
-
-base::TimeDelta VirtualTimeController::GetCurrentVirtualTimeOffset() const {
-  return total_elapsed_time_offset_;
-}
-
-void VirtualTimeController::SetResumeDeferrer(ResumeDeferrer* resume_deferrer) {
-  resume_deferrer_ = resume_deferrer;
-}
-
-}  // namespace headless
diff --git a/headless/public/util/virtual_time_controller.h b/headless/public/util/virtual_time_controller.h
deleted file mode 100644
index 8df73ef6..0000000
--- a/headless/public/util/virtual_time_controller.h
+++ /dev/null
@@ -1,182 +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 HEADLESS_PUBLIC_UTIL_VIRTUAL_TIME_CONTROLLER_H_
-#define HEADLESS_PUBLIC_UTIL_VIRTUAL_TIME_CONTROLLER_H_
-
-#include "base/callback.h"
-#include "base/time/time.h"
-#include "headless/public/devtools/domains/emulation.h"
-#include "headless/public/headless_devtools_client.h"
-#include "headless/public/headless_export.h"
-
-namespace headless {
-
-// Controls how virtual time progresses. RepeatingTasks can register their
-// interest to be periodically notified about changes to the current virtual
-// time.
-class HEADLESS_EXPORT VirtualTimeController
-    : public emulation::ExperimentalObserver {
- public:
-  VirtualTimeController(HeadlessDevToolsClient* devtools_client,
-                        int max_task_starvation_count = 0);
-  ~VirtualTimeController() override;
-
-  // Signals that virtual time should start advancing. If virtual time is
-  // already running, this does nothing.  When virtual time is ready to start
-  // the observers will be notified.
-  virtual void StartVirtualTime();
-
-  class RepeatingTask {
-   public:
-    // This policy controls whether or not StartVirtualTime() should wait for a
-    // navigation first.
-    enum StartPolicy {
-      WAIT_FOR_NAVIGATION,
-      START_IMMEDIATELY,
-    };
-
-    explicit RepeatingTask(StartPolicy start_policy, int priority)
-        : start_policy_(start_policy), priority_(priority) {}
-
-    virtual ~RepeatingTask() {}
-
-    enum class ContinuePolicy {
-      CONTINUE_MORE_TIME_NEEDED,
-      NOT_REQUIRED,
-      STOP,  // Note STOP trumps CONTINUE_MORE_TIME_NEEDED.
-    };
-
-    // Called when the tasks's requested virtual time interval has elapsed.
-    // |virtual_time_offset| is the virtual time duration that has advanced
-    // since the page started loading (millisecond granularity). When the task
-    // has completed it's perioodic work it should call |continue_callback|
-    // with CONTINUE_MORE_TIME_NEEDED if it wants virtual time to continue
-    // advancing, or NOT_REQUIRED otherwise.  Virtual time will continue to
-    // advance until all RepeatingTasks want it to stop.
-    virtual void IntervalElapsed(
-        base::TimeDelta virtual_time_offset,
-        base::OnceCallback<void(ContinuePolicy policy)> continue_callback) = 0;
-
-    StartPolicy start_policy() const { return start_policy_; }
-
-    int priority() const { return priority_; }
-
-   private:
-    const StartPolicy start_policy_;
-
-    // If more than one RepeatingTask is scheduled to run at any instant they
-    // are run in order of ascending |priority_|.
-    const int priority_;
-  };
-
-  // An API used by the CompositorController to defer the start and resumption
-  // of virtual time until it's ready.
-  class ResumeDeferrer {
-   public:
-    virtual ~ResumeDeferrer() {}
-
-    // Called before virtual time progression resumes after it was stopped or
-    // paused to execute repeating tasks.
-    virtual void DeferResume(base::OnceClosure ready_callback) = 0;
-  };
-
-  class Observer {
-   public:
-    virtual ~Observer() {}
-
-    // Called when StartVirtualTime was called. May be delayed by a
-    // StartDeferrer.
-    virtual void VirtualTimeStarted(base::TimeDelta virtual_time_offset) = 0;
-
-    // Called when all RepeatingTasks have either voted for virtual time to stop
-    // advancing, or all have been removed.
-    virtual void VirtualTimeStopped(base::TimeDelta virtual_time_offset) = 0;
-  };
-
-  // Interleaves execution of the provided |task| with progression of virtual
-  // time. The task will be notified whenever another |interval| of virtual time
-  // have elapsed, as well as when the last granted budget has been used up.
-  //
-  // To ensure that the task is notified of elapsed intervals accurately, it
-  // should be added while virtual time is paused.
-  virtual void ScheduleRepeatingTask(RepeatingTask* task,
-                                     base::TimeDelta interval);
-  virtual void CancelRepeatingTask(RepeatingTask* task);
-
-  // Adds an observer which is notified when virtual time starts and stops.
-  virtual void AddObserver(Observer* observer);
-  virtual void RemoveObserver(Observer* observer);
-
-  // Returns the time that virtual time offsets are relative to.
-  virtual base::TimeTicks GetVirtualTimeBase() const;
-
-  // Returns the current virtual time offset. Only accurate while virtual time
-  // is paused.
-  virtual base::TimeDelta GetCurrentVirtualTimeOffset() const;
-
-  // Returns the current virtual time stamp. Only accurate while virtual time
-  // is paused.
-  base::TimeTicks GetCurrentVirtualTime() const {
-    return GetVirtualTimeBase() + GetCurrentVirtualTimeOffset();
-  }
-
-  virtual void SetResumeDeferrer(ResumeDeferrer* resume_deferrer);
-
- private:
-  struct TaskEntry {
-    base::TimeDelta interval;
-    base::TimeDelta next_execution_time;
-    bool ready_to_advance = true;
-    RepeatingTask::ContinuePolicy continue_policy =
-        RepeatingTask::ContinuePolicy::CONTINUE_MORE_TIME_NEEDED;
-  };
-
-  void ObserverReadyToStart();
-
-  // emulation::Observer implementation:
-  void OnVirtualTimeBudgetExpired(
-      const emulation::VirtualTimeBudgetExpiredParams& params) override;
-
-  void NotifyTasksAndAdvance();
-  void NotifyTaskIntervalElapsed(TaskEntry* entry);
-  void NotifyTaskVirtualTimeStarted(TaskEntry* entry);
-  void TaskReadyToAdvance(TaskEntry* entry,
-                          RepeatingTask::ContinuePolicy continue_policy);
-
-  void SetVirtualTimePolicy(base::TimeDelta next_budget,
-                            bool wait_for_navigation);
-  void SetVirtualTimePolicyDone(
-      std::unique_ptr<emulation::SetVirtualTimePolicyResult>);
-
-  HeadlessDevToolsClient* const devtools_client_;  // NOT OWNED
-  ResumeDeferrer* resume_deferrer_ = nullptr;      // NOT OWNED
-  const int max_task_starvation_count_;
-
-  base::TimeDelta total_elapsed_time_offset_;
-  base::TimeDelta last_budget_;
-  // Initial virtual time that virtual time offsets are relative to.
-  base::TimeTicks virtual_time_base_;
-
-  struct RepeatingTaskOrdering {
-    bool operator()(RepeatingTask* a, RepeatingTask* b) const {
-      if (a->priority() == b->priority())
-        return a < b;
-      return a->priority() < b->priority();
-    };
-  };
-
-  std::map<RepeatingTask*, TaskEntry, RepeatingTaskOrdering> tasks_;
-  std::set<Observer*> observers_;
-  bool in_notify_tasks_and_advance_ = false;
-  bool virtual_time_started_ = false;
-  bool virtual_time_paused_ = true;
-  bool should_send_start_notification_ = false;
-
-  base::WeakPtrFactory<VirtualTimeController> weak_ptr_factory_;
-};
-
-}  // namespace headless
-
-#endif  // HEADLESS_PUBLIC_UTIL_VIRTUAL_TIME_CONTROLLER_H_
diff --git a/headless/public/util/virtual_time_controller_test.cc b/headless/public/util/virtual_time_controller_test.cc
deleted file mode 100644
index 2f3b286..0000000
--- a/headless/public/util/virtual_time_controller_test.cc
+++ /dev/null
@@ -1,858 +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 "headless/public/util/virtual_time_controller.h"
-
-#include <memory>
-#include <tuple>
-
-#include "base/bind.h"
-#include "base/memory/ref_counted.h"
-#include "base/strings/stringprintf.h"
-#include "base/test/test_simple_task_runner.h"
-#include "headless/public/internal/headless_devtools_client_impl.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace headless {
-
-using testing::ElementsAre;
-using testing::Mock;
-using testing::Return;
-using testing::_;
-
-namespace {
-
-class MockChannel : public HeadlessDevToolsChannel {
- public:
-  MockChannel() {}
-  ~MockChannel() override {}
-  MOCK_METHOD1(SetClient, void(HeadlessDevToolsChannel::Client*));
-  MOCK_METHOD1(SendProtocolMessage, void(const std::string&));
-};
-
-}  // namespace
-
-class VirtualTimeControllerTest : public ::testing::Test {
- protected:
-  VirtualTimeControllerTest() {
-    task_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>();
-    auto channel = std::make_unique<MockChannel>();
-    mock_channel_ = channel.get();
-    client_.AttachToChannel(std::move(channel));
-    client_.SetTaskRunnerForTests(task_runner_);
-    controller_ = std::make_unique<VirtualTimeController>(&client_, 0);
-  }
-
-  ~VirtualTimeControllerTest() override = default;
-
-  // TODO(alexclarke): This is a common pattern add a helper.
-  class AdditionalVirtualTimeBudget
-      : public VirtualTimeController::RepeatingTask,
-        public VirtualTimeController::Observer {
-   public:
-    AdditionalVirtualTimeBudget(VirtualTimeController* virtual_time_controller,
-                                VirtualTimeControllerTest* test,
-                                base::TimeDelta budget)
-        : RepeatingTask(StartPolicy::START_IMMEDIATELY, 0),
-          virtual_time_controller_(virtual_time_controller),
-          test_(test) {
-      virtual_time_controller_->ScheduleRepeatingTask(this, budget);
-      virtual_time_controller_->AddObserver(this);
-      virtual_time_controller_->StartVirtualTime();
-    }
-
-    ~AdditionalVirtualTimeBudget() override {
-      virtual_time_controller_->RemoveObserver(this);
-      virtual_time_controller_->CancelRepeatingTask(this);
-    }
-
-    // headless::VirtualTimeController::RepeatingTask implementation:
-    void IntervalElapsed(
-        base::TimeDelta virtual_time,
-        base::OnceCallback<void(ContinuePolicy)> continue_callback) override {
-      std::move(continue_callback).Run(ContinuePolicy::NOT_REQUIRED);
-    }
-
-    // headless::VirtualTimeController::Observer:
-    void VirtualTimeStarted(base::TimeDelta virtual_time_offset) override {
-      EXPECT_FALSE(test_->set_up_complete_);
-      test_->set_up_complete_ = true;
-    }
-
-    void VirtualTimeStopped(base::TimeDelta virtual_time_offset) override {
-      EXPECT_FALSE(test_->budget_expired_);
-      test_->budget_expired_ = true;
-      delete this;
-    }
-
-   private:
-    headless::VirtualTimeController* const virtual_time_controller_;
-    VirtualTimeControllerTest* test_;
-  };
-
-  void GrantVirtualTimeBudget(int budget_ms) {
-    ASSERT_FALSE(set_up_complete_);
-    ASSERT_FALSE(budget_expired_);
-
-    // AdditionalVirtualTimeBudget will self delete
-    new AdditionalVirtualTimeBudget(
-        controller_.get(), this, base::TimeDelta::FromMilliseconds(budget_ms));
-
-    EXPECT_FALSE(set_up_complete_);
-    EXPECT_FALSE(budget_expired_);
-  }
-
-  void SendVirtualTimeBudgetExpiredEvent() {
-    client_.ReceiveProtocolMessage(
-        "{\"method\":\"Emulation.virtualTimeBudgetExpired\",\"params\":{}}");
-    // Events are dispatched asynchronously.
-    task_runner_->RunPendingTasks();
-  }
-
-  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
-  HeadlessDevToolsClientImpl client_;
-  MockChannel* mock_channel_ = nullptr;
-  std::unique_ptr<VirtualTimeController> controller_;
-
-  bool set_up_complete_ = false;
-  bool budget_expired_ = false;
-};
-
-TEST_F(VirtualTimeControllerTest, DoesNotAdvanceTimeWithoutTasks) {
-  controller_ = std::make_unique<VirtualTimeController>(&client_, 1000);
-
-  EXPECT_CALL(*mock_channel_, SendProtocolMessage(_)).Times(0);
-
-  controller_->StartVirtualTime();
-}
-
-TEST_F(VirtualTimeControllerTest, MaxVirtualTimeTaskStarvationCount) {
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":0,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":5000.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-
-  GrantVirtualTimeBudget(5000);
-
-  client_.ReceiveProtocolMessage(
-      "{\"id\":0,\"result\":{\"virtualTimeBase\":1."
-      "0,\"virtualTimeTicksBase\":1.0}}");
-  task_runner_->RunPendingTasks();
-
-  EXPECT_TRUE(set_up_complete_);
-  EXPECT_FALSE(budget_expired_);
-
-  SendVirtualTimeBudgetExpiredEvent();
-
-  EXPECT_TRUE(budget_expired_);
-}
-
-namespace {
-class MockTask : public VirtualTimeController::RepeatingTask {
- public:
-  MockTask() : RepeatingTask(StartPolicy::START_IMMEDIATELY, 0) {}
-
-  MockTask(StartPolicy start_policy, int priority)
-      : RepeatingTask(start_policy, priority) {}
-
-  ~MockTask() override { EXPECT_TRUE(!expected_virtual_time_offset_); }
-
-  // GMock doesn't support move only types
-  void IntervalElapsed(
-      base::TimeDelta virtual_time_offset,
-      base::OnceCallback<void(ContinuePolicy)> continue_callback) override {
-    EXPECT_EQ(*expected_virtual_time_offset_, virtual_time_offset);
-    expected_virtual_time_offset_ = base::nullopt;
-    std::move(continue_callback).Run(policy_);
-    interval_elapsed_ = true;
-  }
-
-  void ExpectCallOnceWithOffsetAndReturn(base::TimeDelta virtual_time_offset,
-                                         ContinuePolicy policy) {
-    expected_virtual_time_offset_ = virtual_time_offset;
-    policy_ = policy;
-  }
-
- private:
-  base::Optional<base::TimeDelta> expected_virtual_time_offset_;
-  ContinuePolicy policy_ = ContinuePolicy::NOT_REQUIRED;
-  bool interval_elapsed_ = false;
-};
-
-class MockDeferrer : public VirtualTimeController::ResumeDeferrer {
- public:
-  // GMock doesn't support move only types
-  void DeferResume(base::OnceCallback<void()> continue_callback) override {
-    continue_callback_ = std::move(continue_callback);
-  }
-
-  base::OnceCallback<void()> continue_callback_;
-};
-
-class MockObserver : public VirtualTimeController::Observer {
- public:
-  MOCK_METHOD1(VirtualTimeStarted, void(base::TimeDelta virtual_time_offset));
-
-  MOCK_METHOD1(VirtualTimeStopped, void(base::TimeDelta virtual_time_offset));
-};
-
-ACTION_TEMPLATE(RunClosure,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_0_VALUE_PARAMS()) {
-  std::get<k>(args).Run();
-}
-
-ACTION_P(RunClosure, closure) {
-  closure.Run();
-};
-}  // namespace
-
-TEST_F(VirtualTimeControllerTest, InterleavesTasksWithVirtualTime) {
-  MockTask task;
-  MockObserver observer;
-  controller_->AddObserver(&observer);
-  controller_->ScheduleRepeatingTask(&task,
-                                     base::TimeDelta::FromMilliseconds(1000));
-
-  EXPECT_CALL(observer,
-              VirtualTimeStarted(base::TimeDelta::FromMilliseconds(0)));
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":0,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":1000.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-
-  GrantVirtualTimeBudget(3000);
-
-  EXPECT_FALSE(set_up_complete_);
-  EXPECT_FALSE(budget_expired_);
-
-  client_.ReceiveProtocolMessage(
-      "{\"id\":0,\"result\":{\"virtualTimeBase\":1."
-      "0,\"virtualTimeTicksBase\":1.0}}");
-  task_runner_->RunPendingTasks();
-
-  EXPECT_TRUE(set_up_complete_);
-  EXPECT_FALSE(budget_expired_);
-
-  // We check that set_up_complete_callback is only run once, so reset it here.
-  set_up_complete_ = false;
-
-  for (int i = 1; i < 3; i++) {
-    task.ExpectCallOnceWithOffsetAndReturn(
-        base::TimeDelta::FromMilliseconds(1000 * i),
-        MockTask::ContinuePolicy::NOT_REQUIRED);
-
-    EXPECT_CALL(*mock_channel_,
-                SendProtocolMessage(base::StringPrintf(
-                    "{\"id\":%d,\"method\":\"Emulation.setVirtualTimePolicy\","
-                    "\"params\":{\"budget\":1000.0,"
-                    "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                    "\"pauseIfNetworkFetchesPending\","
-                    "\"waitForNavigation\":false}}",
-                    i * 2)));
-
-    SendVirtualTimeBudgetExpiredEvent();
-
-    EXPECT_FALSE(set_up_complete_);
-    EXPECT_FALSE(budget_expired_);
-
-    client_.ReceiveProtocolMessage(
-        base::StringPrintf("{\"id\":%d,\"result\":{\"virtualTimeBase\":1.0,"
-                           "\"virtualTimeTicksBase\":1.0}}",
-                           i * 2));
-
-    EXPECT_FALSE(set_up_complete_);
-    EXPECT_FALSE(budget_expired_);
-  }
-
-  task.ExpectCallOnceWithOffsetAndReturn(
-      base::TimeDelta::FromMilliseconds(3000),
-      MockTask::ContinuePolicy::NOT_REQUIRED);
-  EXPECT_CALL(observer,
-              VirtualTimeStopped(base::TimeDelta::FromMilliseconds(3000)));
-  SendVirtualTimeBudgetExpiredEvent();
-
-  EXPECT_FALSE(set_up_complete_);
-  EXPECT_TRUE(budget_expired_);
-}
-
-TEST_F(VirtualTimeControllerTest, CanceledTask) {
-  MockTask task;
-  controller_->ScheduleRepeatingTask(&task,
-                                     base::TimeDelta::FromMilliseconds(1000));
-
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":0,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":1000.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-
-  GrantVirtualTimeBudget(5000);
-
-  EXPECT_FALSE(set_up_complete_);
-  EXPECT_FALSE(budget_expired_);
-
-  client_.ReceiveProtocolMessage(
-      "{\"id\":0,\"result\":{\"virtualTimeBase\":1."
-      "0,\"virtualTimeTicksBase\":1.0}}");
-  task_runner_->RunPendingTasks();
-
-  EXPECT_TRUE(set_up_complete_);
-  EXPECT_FALSE(budget_expired_);
-
-  // We check that set_up_complete_callback is only run once, so reset it here.
-  set_up_complete_ = false;
-
-  task.ExpectCallOnceWithOffsetAndReturn(
-      base::TimeDelta::FromMilliseconds(1000),
-      MockTask::ContinuePolicy::NOT_REQUIRED);
-
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":2,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":1000.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-
-  SendVirtualTimeBudgetExpiredEvent();
-
-  EXPECT_FALSE(set_up_complete_);
-  EXPECT_FALSE(budget_expired_);
-
-  client_.ReceiveProtocolMessage(
-      base::StringPrintf("{\"id\":2,\"result\":{\"virtualTimeBase\":1.0,"
-                         "\"virtualTimeTicksBase\":1.0}}"));
-
-  EXPECT_FALSE(set_up_complete_);
-  EXPECT_FALSE(budget_expired_);
-
-  controller_->CancelRepeatingTask(&task);
-
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":4,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":3000.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-
-  SendVirtualTimeBudgetExpiredEvent();
-
-  EXPECT_FALSE(set_up_complete_);
-  EXPECT_FALSE(budget_expired_);
-
-  client_.ReceiveProtocolMessage(
-      base::StringPrintf("{\"id\":4,\"result\":{\"virtualTimeBase\":1.0,"
-                         "\"virtualTimeTicksBase\":1.0}}"));
-
-  EXPECT_FALSE(set_up_complete_);
-  EXPECT_FALSE(budget_expired_);
-
-  SendVirtualTimeBudgetExpiredEvent();
-
-  EXPECT_FALSE(set_up_complete_);
-  EXPECT_TRUE(budget_expired_);
-}
-
-TEST_F(VirtualTimeControllerTest, MultipleTasks) {
-  MockTask task1;
-  MockTask task2;
-  controller_->ScheduleRepeatingTask(&task1,
-                                     base::TimeDelta::FromMilliseconds(1000));
-  controller_->ScheduleRepeatingTask(&task2,
-                                     base::TimeDelta::FromMilliseconds(1000));
-
-  // We should only get one call to Emulation.setVirtualTimePolicy despite
-  // having two tasks.
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":0,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":1000.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-
-  GrantVirtualTimeBudget(2000);
-  EXPECT_FALSE(set_up_complete_);
-  EXPECT_FALSE(budget_expired_);
-
-  client_.ReceiveProtocolMessage(
-      base::StringPrintf("{\"id\":0,\"result\":{\"virtualTimeBase\":1.0,"
-                         "\"virtualTimeTicksBase\":1.0}}"));
-
-  task_runner_->RunPendingTasks();
-  EXPECT_TRUE(set_up_complete_);
-  EXPECT_FALSE(budget_expired_);
-}
-
-TEST_F(VirtualTimeControllerTest, StartPolicy) {
-  MockTask task1(MockTask::StartPolicy::START_IMMEDIATELY, 0);
-  MockTask task2(MockTask::StartPolicy::START_IMMEDIATELY, 0);
-  MockTask task3(MockTask::StartPolicy::WAIT_FOR_NAVIGATION, 0);
-  controller_->ScheduleRepeatingTask(&task1,
-                                     base::TimeDelta::FromMilliseconds(1000));
-  controller_->ScheduleRepeatingTask(&task2,
-                                     base::TimeDelta::FromMilliseconds(1000));
-  controller_->ScheduleRepeatingTask(&task3,
-                                     base::TimeDelta::FromMilliseconds(1000));
-
-  // Despite only one task asking for it we should get waitForNavigation:true
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":0,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":1000.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":true}}"));
-
-  GrantVirtualTimeBudget(2000);
-}
-
-TEST_F(VirtualTimeControllerTest, DeferStartAndResume) {
-  MockDeferrer deferrer;
-  controller_->SetResumeDeferrer(&deferrer);
-
-  MockTask task1(MockTask::StartPolicy::START_IMMEDIATELY, 0);
-  controller_->ScheduleRepeatingTask(&task1,
-                                     base::TimeDelta::FromMilliseconds(1000));
-  EXPECT_FALSE(deferrer.continue_callback_);
-
-  // Shouldn't see the devtools command until the deferrer's callback has run.
-  EXPECT_CALL(*mock_channel_, SendProtocolMessage(_)).Times(0);
-  GrantVirtualTimeBudget(2000);
-  EXPECT_TRUE(deferrer.continue_callback_);
-
-  Mock::VerifyAndClearExpectations(mock_channel_);
-
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":0,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":1000.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-
-  std::move(deferrer.continue_callback_).Run();
-
-  client_.ReceiveProtocolMessage(
-      "{\"id\":0,\"result\":{\"virtualTimeBase\":1."
-      "0,\"virtualTimeTicksBase\":1.0}}");
-  EXPECT_FALSE(deferrer.continue_callback_);
-
-  task1.ExpectCallOnceWithOffsetAndReturn(
-      base::TimeDelta::FromMilliseconds(1000),
-      MockTask::ContinuePolicy::NOT_REQUIRED);
-
-  // Even after executing task1, virtual time shouldn't resume until the
-  // deferrer's callback has run.
-  EXPECT_CALL(*mock_channel_, SendProtocolMessage(_)).Times(0);
-
-  SendVirtualTimeBudgetExpiredEvent();
-  EXPECT_TRUE(deferrer.continue_callback_);
-
-  Mock::VerifyAndClearExpectations(mock_channel_);
-
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":2,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":1000.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-
-  std::move(deferrer.continue_callback_).Run();
-}
-
-class VirtualTimeTask : public VirtualTimeController::RepeatingTask,
-                        public VirtualTimeController::Observer {
- public:
-  using Task = base::RepeatingCallback<void(base::TimeDelta virtual_time)>;
-
-  VirtualTimeTask(VirtualTimeController* controller,
-                  Task virtual_time_started_task,
-                  Task interval_elapsed_task,
-                  Task virtual_time_stopped_task,
-                  int priority = 0)
-      : RepeatingTask(StartPolicy::START_IMMEDIATELY, priority),
-        controller_(controller),
-        virtual_time_started_task_(virtual_time_started_task),
-        interval_elapsed_task_(interval_elapsed_task),
-        virtual_time_stopped_task_(virtual_time_stopped_task) {
-    controller_->AddObserver(this);
-  }
-
-  ~VirtualTimeTask() override { controller_->RemoveObserver(this); }
-
-  // VirtualTimeController::RepeatingTask:
-  void IntervalElapsed(
-      base::TimeDelta virtual_time,
-      base::OnceCallback<void(ContinuePolicy)> continue_callback) override {
-    std::move(continue_callback).Run(ContinuePolicy::NOT_REQUIRED);
-    interval_elapsed_task_.Run(virtual_time);
-  }
-
-  // VirtualTimeController::Observer:
-  void VirtualTimeStarted(base::TimeDelta virtual_time) override {
-    virtual_time_started_task_.Run(virtual_time);
-  }
-
-  void VirtualTimeStopped(base::TimeDelta virtual_time) override {
-    virtual_time_stopped_task_.Run(virtual_time);
-  };
-
-  VirtualTimeController* controller_;  // NOT OWNED
-  Task virtual_time_started_task_;
-  Task interval_elapsed_task_;
-  Task virtual_time_stopped_task_;
-};
-
-TEST_F(VirtualTimeControllerTest, ReentrantTask) {
-#if defined(__clang__)
-  std::vector<std::string> log;
-  VirtualTimeTask task_b(
-      controller_.get(),
-      base::BindRepeating([](base::TimeDelta virtual_time) {}),
-      base::BindRepeating(
-          [](std::vector<std::string>* log, VirtualTimeController* controller,
-             VirtualTimeTask* task_b, base::TimeDelta virtual_time) {
-            log->push_back(base::StringPrintf(
-                "B: interval elapsed @ %d",
-                static_cast<int>(virtual_time.InMilliseconds())));
-            controller->CancelRepeatingTask(task_b);
-          },
-          &log, controller_.get(), &task_b),
-      base::BindRepeating(
-          [](std::vector<std::string>* log, base::TimeDelta virtual_time) {
-            log->push_back(base::StringPrintf(
-                "B: virtual time stopped @ %d",
-                static_cast<int>(virtual_time.InMilliseconds())));
-          },
-          &log));
-
-  VirtualTimeTask task_a(
-      controller_.get(),
-      base::BindRepeating(
-          [](std::vector<std::string>* log, base::TimeDelta virtual_time) {
-            log->push_back(base::StringPrintf(
-                "Virtual time started @ %d",
-                static_cast<int>(virtual_time.InMilliseconds())));
-          },
-          &log),
-      base::BindRepeating(
-          [](std::vector<std::string>* log, VirtualTimeController* controller,
-             VirtualTimeTask* task_a, VirtualTimeTask* task_b,
-             base::TimeDelta virtual_time) {
-            log->push_back(base::StringPrintf(
-                "A: interval elapsed @ %d",
-                static_cast<int>(virtual_time.InMilliseconds())));
-            controller->CancelRepeatingTask(task_a);
-            controller->ScheduleRepeatingTask(
-                task_b, base::TimeDelta::FromMilliseconds(1500));
-          },
-          &log, controller_.get(), &task_a, &task_b),
-      base::BindRepeating(
-          [](std::vector<std::string>* log, base::TimeDelta virtual_time) {
-            log->push_back(base::StringPrintf(
-                "A: virtual time stopped @ %d",
-                static_cast<int>(virtual_time.InMilliseconds())));
-          },
-          &log));
-
-  controller_->ScheduleRepeatingTask(&task_a,
-                                     base::TimeDelta::FromMilliseconds(1000));
-
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":0,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":1000.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-
-  GrantVirtualTimeBudget(6000);
-  client_.ReceiveProtocolMessage(
-      base::StringPrintf("{\"id\":0,\"result\":{\"virtualTimeBase\":1.0,"
-                         "\"virtualTimeTicksBase\":1.0}}"));
-
-  Mock::VerifyAndClearExpectations(mock_channel_);
-
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":2,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":1500.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-
-  SendVirtualTimeBudgetExpiredEvent();
-  client_.ReceiveProtocolMessage(
-      base::StringPrintf("{\"id\":2,\"result\":{\"virtualTimeBase\":1.0,"
-                         "\"virtualTimeTicksBase\":1.0}}"));
-  Mock::VerifyAndClearExpectations(mock_channel_);
-
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":4,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":3500.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-  SendVirtualTimeBudgetExpiredEvent();
-  client_.ReceiveProtocolMessage(
-      base::StringPrintf("{\"id\":4,\"result\":{\"virtualTimeBase\":1.0,"
-                         "\"virtualTimeTicksBase\":1.0}}"));
-
-  EXPECT_THAT(
-      log, ElementsAre("Virtual time started @ 0", "A: interval elapsed @ 1000",
-                       "B: interval elapsed @ 2500"));
-#endif
-}
-
-TEST_F(VirtualTimeControllerTest, Priority) {
-  std::vector<std::string> log;
-  VirtualTimeTask task_a(
-      controller_.get(),
-      base::BindRepeating([](base::TimeDelta virtual_time) {}),
-      base::BindRepeating(
-          [](std::vector<std::string>* log, base::TimeDelta virtual_time) {
-            log->push_back(base::StringPrintf(
-                "A: interval elapsed @ %d",
-                static_cast<int>(virtual_time.InMilliseconds())));
-          },
-          &log),
-      base::BindRepeating([](base::TimeDelta virtual_time) {}), 30);
-
-  VirtualTimeTask task_b(
-      controller_.get(),
-      base::BindRepeating([](base::TimeDelta virtual_time) {}),
-      base::BindRepeating(
-          [](std::vector<std::string>* log, base::TimeDelta virtual_time) {
-            log->push_back(base::StringPrintf(
-                "B: interval elapsed @ %d",
-                static_cast<int>(virtual_time.InMilliseconds())));
-          },
-          &log),
-      base::BindRepeating([](base::TimeDelta virtual_time) {}), 20);
-
-  VirtualTimeTask task_c(
-      controller_.get(),
-      base::BindRepeating([](base::TimeDelta virtual_time) {}),
-      base::BindRepeating(
-          [](std::vector<std::string>* log, base::TimeDelta virtual_time) {
-            log->push_back(base::StringPrintf(
-                "C: interval elapsed @ %d",
-                static_cast<int>(virtual_time.InMilliseconds())));
-          },
-          &log),
-      base::BindRepeating([](base::TimeDelta virtual_time) {}), 10);
-
-  controller_->ScheduleRepeatingTask(&task_a,
-                                     base::TimeDelta::FromMilliseconds(1000));
-
-  controller_->ScheduleRepeatingTask(&task_b,
-                                     base::TimeDelta::FromMilliseconds(1000));
-
-  controller_->ScheduleRepeatingTask(&task_c,
-                                     base::TimeDelta::FromMilliseconds(1000));
-
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":0,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":1000.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-
-  GrantVirtualTimeBudget(2000);
-  client_.ReceiveProtocolMessage(
-      base::StringPrintf("{\"id\":0,\"result\":{\"virtualTimeBase\":1.0,"
-                         "\"virtualTimeTicksBase\":1.0}}"));
-
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":2,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":1000.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-
-  SendVirtualTimeBudgetExpiredEvent();
-
-  EXPECT_THAT(log, ElementsAre("C: interval elapsed @ 1000",
-                               "B: interval elapsed @ 1000",
-                               "A: interval elapsed @ 1000"));
-}
-
-TEST_F(VirtualTimeControllerTest, ContinuePolicyContinueMoreTimeNeeded) {
-  MockTask task;
-  MockObserver observer;
-  controller_->AddObserver(&observer);
-  controller_->ScheduleRepeatingTask(&task,
-                                     base::TimeDelta::FromMilliseconds(1000));
-
-  EXPECT_CALL(observer,
-              VirtualTimeStarted(base::TimeDelta::FromMilliseconds(0)));
-
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":0,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":1000.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-
-  controller_->StartVirtualTime();
-
-  client_.ReceiveProtocolMessage(
-      "{\"id\":0,\"result\":{\"virtualTimeBase\":1."
-      "0,\"virtualTimeTicksBase\":1.0}}");
-
-  for (int i = 1; i < 4; i++) {
-    task.ExpectCallOnceWithOffsetAndReturn(
-        base::TimeDelta::FromMilliseconds(1000 * i),
-        MockTask::ContinuePolicy::CONTINUE_MORE_TIME_NEEDED);
-
-    EXPECT_CALL(*mock_channel_,
-                SendProtocolMessage(base::StringPrintf(
-                    "{\"id\":%d,\"method\":\"Emulation.setVirtualTimePolicy\","
-                    "\"params\":{\"budget\":1000.0,"
-                    "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                    "\"pauseIfNetworkFetchesPending\","
-                    "\"waitForNavigation\":false}}",
-                    i * 2)));
-
-    SendVirtualTimeBudgetExpiredEvent();
-
-    client_.ReceiveProtocolMessage(
-        base::StringPrintf("{\"id\":%d,\"result\":{\"virtualTimeBase\":1.0,"
-                           "\"virtualTimeTicksBase\":1.0}}",
-                           i * 2));
-  }
-
-  task.ExpectCallOnceWithOffsetAndReturn(
-      base::TimeDelta::FromMilliseconds(4000),
-      MockTask::ContinuePolicy::NOT_REQUIRED);
-
-  EXPECT_CALL(observer,
-              VirtualTimeStopped(base::TimeDelta::FromMilliseconds(4000)));
-
-  SendVirtualTimeBudgetExpiredEvent();
-}
-
-TEST_F(VirtualTimeControllerTest, ContinuePolicyStopAndRestart) {
-  MockTask task1;
-  MockTask task2;
-  MockTask task3;
-  MockObserver observer;
-  controller_->AddObserver(&observer);
-  controller_->ScheduleRepeatingTask(&task1,
-                                     base::TimeDelta::FromMilliseconds(1000));
-  controller_->ScheduleRepeatingTask(&task2,
-                                     base::TimeDelta::FromMilliseconds(1000));
-  controller_->ScheduleRepeatingTask(&task3,
-                                     base::TimeDelta::FromMilliseconds(4000));
-
-  EXPECT_CALL(observer,
-              VirtualTimeStarted(base::TimeDelta::FromMilliseconds(0)));
-
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":0,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":1000.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-
-  controller_->StartVirtualTime();
-
-  client_.ReceiveProtocolMessage(
-      "{\"id\":0,\"result\":{\"virtualTimeBase\":1."
-      "0,\"virtualTimeTicksBase\":1.0}}");
-
-  for (int i = 1; i < 4; i++) {
-    task1.ExpectCallOnceWithOffsetAndReturn(
-        base::TimeDelta::FromMilliseconds(1000 * i),
-        MockTask::ContinuePolicy::CONTINUE_MORE_TIME_NEEDED);
-    task2.ExpectCallOnceWithOffsetAndReturn(
-        base::TimeDelta::FromMilliseconds(1000 * i),
-        MockTask::ContinuePolicy::CONTINUE_MORE_TIME_NEEDED);
-
-    EXPECT_CALL(*mock_channel_,
-                SendProtocolMessage(base::StringPrintf(
-                    "{\"id\":%d,\"method\":\"Emulation.setVirtualTimePolicy\","
-                    "\"params\":{\"budget\":1000.0,"
-                    "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                    "\"pauseIfNetworkFetchesPending\","
-                    "\"waitForNavigation\":false}}",
-                    i * 2)));
-
-    SendVirtualTimeBudgetExpiredEvent();
-
-    client_.ReceiveProtocolMessage(
-        base::StringPrintf("{\"id\":%d,\"result\":{\"virtualTimeBase\":1.0,"
-                           "\"virtualTimeTicksBase\":1.0}}",
-                           i * 2));
-  }
-
-  task1.ExpectCallOnceWithOffsetAndReturn(
-      base::TimeDelta::FromMilliseconds(4000),
-      MockTask::ContinuePolicy::CONTINUE_MORE_TIME_NEEDED);
-  // STOP should take precedence over CONTINUE_MORE_TIME_NEEDED.
-  task2.ExpectCallOnceWithOffsetAndReturn(
-      base::TimeDelta::FromMilliseconds(4000), MockTask::ContinuePolicy::STOP);
-  task3.ExpectCallOnceWithOffsetAndReturn(
-      base::TimeDelta::FromMilliseconds(4000),
-      MockTask::ContinuePolicy::CONTINUE_MORE_TIME_NEEDED);
-
-  EXPECT_CALL(observer,
-              VirtualTimeStopped(base::TimeDelta::FromMilliseconds(4000)));
-
-  SendVirtualTimeBudgetExpiredEvent();
-
-  // If we start again, no task should block initially.
-  EXPECT_CALL(observer,
-              VirtualTimeStarted(base::TimeDelta::FromMilliseconds(4000)));
-
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":8,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":1000.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-
-  controller_->StartVirtualTime();
-
-  client_.ReceiveProtocolMessage(
-      "{\"id\":8,\"result\":{\"virtualTimeBase\":1."
-      "0,\"virtualTimeTicksBase\":1.0}}");
-
-  task1.ExpectCallOnceWithOffsetAndReturn(
-      base::TimeDelta::FromMilliseconds(5000),
-      MockTask::ContinuePolicy::CONTINUE_MORE_TIME_NEEDED);
-  task2.ExpectCallOnceWithOffsetAndReturn(
-      base::TimeDelta::FromMilliseconds(5000),
-      MockTask::ContinuePolicy::CONTINUE_MORE_TIME_NEEDED);
-
-  EXPECT_CALL(*mock_channel_,
-              SendProtocolMessage(
-                  "{\"id\":10,\"method\":\"Emulation.setVirtualTimePolicy\","
-                  "\"params\":{\"budget\":1000.0,"
-                  "\"maxVirtualTimeTaskStarvationCount\":0,\"policy\":"
-                  "\"pauseIfNetworkFetchesPending\","
-                  "\"waitForNavigation\":false}}"));
-
-  SendVirtualTimeBudgetExpiredEvent();
-}
-}  // namespace headless
diff --git a/headless/test/DEPS b/headless/test/DEPS
index cb553ed..518ed48 100644
--- a/headless/test/DEPS
+++ b/headless/test/DEPS
@@ -1,10 +1,4 @@
 specific_include_rules = {
-  "headless_render_test.cc": [
-    "+cc/base/switches.h",
-    "+components/viz/common/features.h",
-    "+components/viz/common/switches.h",
-    "+third_party/skia/include",
-  ],
   "headless_protocol_browsertest.cc": [
     "+cc/base/switches.h",
     "+components/viz/common/features.h",
diff --git a/headless/test/data/protocol/emulation/compositor-basic-raf.js b/headless/test/data/protocol/emulation/compositor-basic-raf.js
index bc7c8e53..7433842 100644
--- a/headless/test/data/protocol/emulation/compositor-basic-raf.js
+++ b/headless/test/data/protocol/emulation/compositor-basic-raf.js
@@ -3,113 +3,103 @@
 // found in the LICENSE file.
 
 (async function(testRunner) {
-  var {page, session, dp} = await testRunner.startBlank(
+  var {page, session, dp} = await testRunner.startWithFrameControl(
       'Tests compositor basic rAF operation.');
-  await dp.Target.enable();
 
-  // Open the test page in a new tab with BeginFrameControl enabled.
-  await testTargetPage(await session.createTargetInNewContext(
-      800, 600, 'about:blank', true));
+  await dp.Runtime.enable();
+  await dp.HeadlessExperimental.enable();
 
-  // This runs requestAnimationFrame five times without updating display then
-  // takes a screenshotin in a newly created tab with BeginFrame control.
-  async function testTargetPage(session) {
-    dp = session.protocol;
-    await dp.Runtime.enable();
-    await dp.HeadlessExperimental.enable();
+  dp.Runtime.onConsoleAPICalled(data => {
+    const text = data.params.args[0].value;
+    testRunner.log(text);
+  });
 
-    dp.Runtime.onConsoleAPICalled(data => {
-      const text = data.params.args[0].value;
-      testRunner.log(text);
-    });
+  dp.Emulation.onVirtualTimeAdvanced(data => {
+    // Debug chrome schedules stray tasks that break this test.
+    // Our numbers are round, so we prevent this flake 999 times of 1000.
+    const time = data.params.virtualTimeElapsed;
+    if (time !== Math.round(time))
+      return;
+    testRunner.log(`Advanced to ${time}ms`);
+  });
 
-    dp.Emulation.onVirtualTimeAdvanced(data => {
-      // Debug chrome schedules stray tasks that break this test.
-      // Our numbers are round, so we prevent this flake 999 times of 1000.
-      const time = data.params.virtualTimeElapsed;
-      if (time !== Math.round(time))
-        return;
-      testRunner.log(`Advanced to ${time}ms`);
-    });
+  let virtualTimeBase = 0;
+  let totalElapsedTime = 0;
+  let frameTimeTicks = 0;
+  let lastGrantedChunk = 0;
 
-    let virtualTimeBase = 0;
-    let totalElapsedTime = 0;
-    let frameTimeTicks = 0;
-    let lastGrantedChunk = 0;
+  dp.Emulation.onVirtualTimePaused(data => {
+    // Remember the base time for frame time calculation.
+    virtualTimeBase = data.params.virtualTimeElapsed;
+  });
 
-    dp.Emulation.onVirtualTimePaused(data => {
-      // Remember the base time for frame time calculation.
-      virtualTimeBase = data.params.virtualTimeElapsed;
-    });
+  await dp.Emulation.setVirtualTimePolicy({policy: 'pause'});
+  lastGrantedChunk = 1000;
+  await dp.Emulation.setVirtualTimePolicy({
+      policy: 'pauseIfNetworkFetchesPending',
+      budget: lastGrantedChunk, waitForNavigation: true});
 
-    await dp.Emulation.setVirtualTimePolicy({policy: 'pause'});
-    lastGrantedChunk = 1000;
-    await dp.Emulation.setVirtualTimePolicy({
-        policy: 'pauseIfNetworkFetchesPending',
-        budget: lastGrantedChunk, waitForNavigation: true});
+  dp.Page.navigate(
+      {url: testRunner.url('/resources/compositor-basic-raf.html')});
 
-    dp.Page.navigate(
-        {url: testRunner.url('/resources/compositor-basic-raf.html')});
+  // Renderer wants the very first frame to be fully updated.
+  await AdvanceTime();
+  await session.evaluate('startRAF()');
+  await dp.HeadlessExperimental.beginFrame({frameTimeTicks});
+  await GrantMoreTime(100);
 
-    // Renderer wants the very first frame to be fully updated.
+  // Send 3 updateless frames.
+  for (var n = 0; n < 3; ++n) {
     await AdvanceTime();
-    await session.evaluate('startRAF()');
-    await dp.HeadlessExperimental.beginFrame({frameTimeTicks});
+    await dp.HeadlessExperimental.beginFrame({frameTimeTicks,
+        noDisplayUpdates: true});
     await GrantMoreTime(100);
+  }
 
-    // Send 3 updateless frames.
-    for (var n = 0; n < 3; ++n) {
-      await AdvanceTime();
-      await dp.HeadlessExperimental.beginFrame({frameTimeTicks,
-          noDisplayUpdates: true});
-      await GrantMoreTime(100);
+  // Grab screenshot, expected size 800x600, rgba: 0,0,50,255.
+  await AdvanceTime();
+  testRunner.log(await session.evaluate('displayRAFCount();'));
+  const screenshotData =
+      (await dp.HeadlessExperimental.beginFrame(
+          {frameTimeTicks, screenshot: {format: 'png'}}))
+      .result.screenshotData;
+  await logScreenShotInfo(screenshotData);
+
+  testRunner.completeTest();
+
+  async function AdvanceTime() {
+    await dp.Emulation.onceVirtualTimeBudgetExpired();
+    totalElapsedTime += lastGrantedChunk;
+    testRunner.log(`Elasped time: ${totalElapsedTime}`);
+    frameTimeTicks = virtualTimeBase + totalElapsedTime;
+  }
+
+  async function GrantMoreTime(budget) {
+    lastGrantedChunk = budget;
+    await dp.Emulation.setVirtualTimePolicy({
+        policy: 'pauseIfNetworkFetchesPending', budget});
+  }
+
+  function logScreenShotInfo(pngBase64) {
+    const image = new Image();
+
+    let callback;
+    let promise = new Promise(fulfill => callback = fulfill);
+    image.onload = function() {
+      testRunner.log(`Screenshot size: `
+          + `${image.naturalWidth} x ${image.naturalHeight}`);
+      const canvas = document.createElement('canvas');
+      canvas.width = image.naturalWidth;
+      canvas.height = image.naturalHeight;
+      const ctx = canvas.getContext('2d');
+      ctx.drawImage(image, 0, 0);
+      const rgba = ctx.getImageData(0, 0, 1, 1).data;
+      testRunner.log(`Screenshot rgba: ${rgba}`);
+      callback();
     }
 
-    // Grab screenshot, expected size 800x600, rgba: 0,0,50,255.
-    await AdvanceTime();
-    testRunner.log(await session.evaluate('displayRAFCount();'));
-    const screenshotData =
-        (await dp.HeadlessExperimental.beginFrame(
-            {frameTimeTicks, screenshot: {format: 'png'}}))
-        .result.screenshotData;
-    await logScreenShotInfo(screenshotData);
+    image.src = `data:image/png;base64,${pngBase64}`;
 
-    testRunner.completeTest();
-
-    async function AdvanceTime() {
-      await dp.Emulation.onceVirtualTimeBudgetExpired();
-      totalElapsedTime += lastGrantedChunk;
-      testRunner.log(`Elasped time: ${totalElapsedTime}`);
-      frameTimeTicks = virtualTimeBase + totalElapsedTime;
-    }
-
-    async function GrantMoreTime(budget) {
-      lastGrantedChunk = budget;
-      await dp.Emulation.setVirtualTimePolicy({
-          policy: 'pauseIfNetworkFetchesPending', budget});
-    }
-
-    function logScreenShotInfo(pngBase64) {
-      const image = new Image();
-
-      let callback;
-      let promise = new Promise(fulfill => callback = fulfill);
-      image.onload = function() {
-        testRunner.log(`Screenshot size: `
-            + `${image.naturalWidth} x ${image.naturalHeight}`);
-        const canvas = document.createElement('canvas');
-        canvas.width = image.naturalWidth;
-        canvas.height = image.naturalHeight;
-        const ctx = canvas.getContext('2d');
-        ctx.drawImage(image, 0, 0);
-        const rgba = ctx.getImageData(0, 0, 1, 1).data;
-        testRunner.log(`Screenshot rgba: ${rgba}`);
-        callback();
-      }
-
-      image.src = `data:image/png;base64,${pngBase64}`;
-
-      return promise;
-    }
+    return promise;
   }
 })
diff --git a/headless/test/data/protocol/emulation/compositor-css-animation-test.js b/headless/test/data/protocol/emulation/compositor-css-animation-test.js
index d5aa302..812fdc5f 100644
--- a/headless/test/data/protocol/emulation/compositor-css-animation-test.js
+++ b/headless/test/data/protocol/emulation/compositor-css-animation-test.js
@@ -3,116 +3,106 @@
 // found in the LICENSE file.
 
 (async function(testRunner) {
-  var {page, session, dp} = await testRunner.startBlank(
+  var {page, session, dp} = await testRunner.startWithFrameControl(
       'Tests compositor animated css handling.');
-  await dp.Target.enable();
 
-  // Open the test page in a new tab with BeginFrameControl enabled.
-  await testTargetPage(await session.createTargetInNewContext(
-      800, 600, 'about:blank', true));
+  await dp.Runtime.enable();
+  await dp.HeadlessExperimental.enable();
 
-  // Loads a page with css animation into a a newly created tab with BeginFrame
-  // control and verifies that animation is advanced according to virtual time.
-  async function testTargetPage(session) {
-    dp = session.protocol;
-    await dp.Runtime.enable();
-    await dp.HeadlessExperimental.enable();
+  dp.Runtime.onConsoleAPICalled(data => {
+    const text = data.params.args[0].value;
+    testRunner.log(text);
+  });
 
-    dp.Runtime.onConsoleAPICalled(data => {
-      const text = data.params.args[0].value;
-      testRunner.log(text);
-    });
+  let virtualTimeBase = 0;
+  let totalElapsedTime = 0;
+  let lastGrantedChunk = 0;
+  let expiredCount = 0;
 
-    let virtualTimeBase = 0;
-    let totalElapsedTime = 0;
-    let lastGrantedChunk = 0;
-    let expiredCount = 0;
+  dp.Emulation.onVirtualTimeBudgetExpired(async data => {
+    ++expiredCount;
+    totalElapsedTime += lastGrantedChunk;
+    testRunner.log(`Expired count: ${expiredCount}`
+        + `, elaspedTime: ${totalElapsedTime}`);
 
-    dp.Emulation.onVirtualTimeBudgetExpired(async data => {
-      ++expiredCount;
-      totalElapsedTime += lastGrantedChunk;
-      testRunner.log(`Expired count: ${expiredCount}`
-          + `, elaspedTime: ${totalElapsedTime}`);
+    let grantVirtualTime = 500;
+    let frameTimeTicks = virtualTimeBase + totalElapsedTime;
 
-      let grantVirtualTime = 500;
-      let frameTimeTicks = virtualTimeBase + totalElapsedTime;
-
-      if (expiredCount == 1) {
-        // Renderer wants the very first frame to be fully updated.
-        await dp.HeadlessExperimental.beginFrame({frameTimeTicks});
+    if (expiredCount == 1) {
+      // Renderer wants the very first frame to be fully updated.
+      await dp.HeadlessExperimental.beginFrame({frameTimeTicks});
+    } else {
+      if (expiredCount >= 4 && expiredCount <= 6) {
+        // Issue updateless frames.
+        await dp.HeadlessExperimental.beginFrame(
+            {frameTimeTicks, noDisplayUpdates: true});
       } else {
-        if (expiredCount >= 4 && expiredCount <= 6) {
-          // Issue updateless frames.
-          await dp.HeadlessExperimental.beginFrame(
-              {frameTimeTicks, noDisplayUpdates: true});
-        } else {
-          // Update frame and grab a screenshot, logging background color.
-          const {result: {screenshotData}} =
-              await dp.HeadlessExperimental.beginFrame(
-                  {frameTimeTicks, screenshot: {format: 'png'}});
-          await logScreenShotInfo(screenshotData);
-        }
+        // Update frame and grab a screenshot, logging background color.
+        const {result: {screenshotData}} =
+            await dp.HeadlessExperimental.beginFrame(
+                {frameTimeTicks, screenshot: {format: 'png'}});
+        await logScreenShotInfo(screenshotData);
       }
-
-      // Grant more time or quit test.
-      if (expiredCount < 10) {
-        await dp.Emulation.setVirtualTimePolicy({
-          policy: 'pauseIfNetworkFetchesPending',
-          budget: grantVirtualTime});
-        lastGrantedChunk = grantVirtualTime;
-      } else {
-        testRunner.completeTest();
-      }
-    });
-
-    // Pause for the first time and remember base virtual time.
-    const {result: {virtualTimeTicksBase}} =
-        await dp.Emulation.setVirtualTimePolicy({policy: 'pause'});
-    virtualTimeBase = virtualTimeTicksBase;
-
-    lastGrantedChunk = 500;
-    await dp.Emulation.setVirtualTimePolicy({
-        policy: 'pauseIfNetworkFetchesPending',
-        budget: lastGrantedChunk, waitForNavigation: true});
-
-    // Animates opacity of a blue 100px square on red blackground over 4
-    // seconds (1.0 -> 0 -> 1.0 four times). Logs events to console.
-    //
-    // Timeline:
-    //      0 ms:  --- animation starts at 500ms ---
-    //    500 ms:  1.0 opacity  -> blue background.
-    //   1000 ms:    0 opacity  ->  red background.
-    //   1500 ms:  1.0 opacity  -> blue background.
-    //   2000 ms:    0 opacity  ->  red background.
-    //   2500 ms:  1.0 opacity  -> blue background.
-    //   3000 ms:    0 opacity  ->  red background.
-    //   3500 ms:  1.0 opacity  -> blue background.
-    //   4000 ms:    0 opacity  ->  red background.
-    //   4500 ms:  1.0 opacity  -> blue background.
-    //
-    // The animation will start with the first BeginFrame after load.
-    dp.Page.navigate(
-        {url: testRunner.url('/resources/compositor-css-animation.html')});
-
-    function logScreenShotInfo(pngBase64) {
-      const image = new Image();
-
-      let callback;
-      let promise = new Promise(fulfill => callback = fulfill);
-      image.onload = function() {
-        const canvas = document.createElement('canvas');
-        canvas.width = image.naturalWidth;
-        canvas.height = image.naturalHeight;
-        const ctx = canvas.getContext('2d');
-        ctx.drawImage(image, 0, 0);
-        const rgba = ctx.getImageData(0, 0, 1, 1).data;
-        testRunner.log(`Screenshot rgba: ${rgba}`);
-        callback();
-      }
-
-      image.src = `data:image/png;base64,${pngBase64}`;
-
-      return promise;
     }
+
+    // Grant more time or quit test.
+    if (expiredCount < 10) {
+      await dp.Emulation.setVirtualTimePolicy({
+        policy: 'pauseIfNetworkFetchesPending',
+        budget: grantVirtualTime});
+      lastGrantedChunk = grantVirtualTime;
+    } else {
+      testRunner.completeTest();
+    }
+  });
+
+  // Pause for the first time and remember base virtual time.
+  const {result: {virtualTimeTicksBase}} =
+      await dp.Emulation.setVirtualTimePolicy({policy: 'pause'});
+  virtualTimeBase = virtualTimeTicksBase;
+
+  lastGrantedChunk = 500;
+  await dp.Emulation.setVirtualTimePolicy({
+      policy: 'pauseIfNetworkFetchesPending',
+      budget: lastGrantedChunk, waitForNavigation: true});
+
+  // Animates opacity of a blue 100px square on red blackground over 4
+  // seconds (1.0 -> 0 -> 1.0 four times). Logs events to console.
+  //
+  // Timeline:
+  //      0 ms:  --- animation starts at 500ms ---
+  //    500 ms:  1.0 opacity  -> blue background.
+  //   1000 ms:    0 opacity  ->  red background.
+  //   1500 ms:  1.0 opacity  -> blue background.
+  //   2000 ms:    0 opacity  ->  red background.
+  //   2500 ms:  1.0 opacity  -> blue background.
+  //   3000 ms:    0 opacity  ->  red background.
+  //   3500 ms:  1.0 opacity  -> blue background.
+  //   4000 ms:    0 opacity  ->  red background.
+  //   4500 ms:  1.0 opacity  -> blue background.
+  //
+  // The animation will start with the first BeginFrame after load.
+  dp.Page.navigate(
+      {url: testRunner.url('/resources/compositor-css-animation.html')});
+
+  function logScreenShotInfo(pngBase64) {
+    const image = new Image();
+
+    let callback;
+    let promise = new Promise(fulfill => callback = fulfill);
+    image.onload = function() {
+      const canvas = document.createElement('canvas');
+      canvas.width = image.naturalWidth;
+      canvas.height = image.naturalHeight;
+      const ctx = canvas.getContext('2d');
+      ctx.drawImage(image, 0, 0);
+      const rgba = ctx.getImageData(0, 0, 1, 1).data;
+      testRunner.log(`Screenshot rgba: ${rgba}`);
+      callback();
+    }
+
+    image.src = `data:image/png;base64,${pngBase64}`;
+
+    return promise;
   }
 })
diff --git a/headless/test/data/protocol/emulation/compositor-image-animation-test.js b/headless/test/data/protocol/emulation/compositor-image-animation-test.js
index 1793457..712e219 100644
--- a/headless/test/data/protocol/emulation/compositor-image-animation-test.js
+++ b/headless/test/data/protocol/emulation/compositor-image-animation-test.js
@@ -3,13 +3,8 @@
 // found in the LICENSE file.
 
 (async function(testRunner) {
-  var {page, session, dp} = await testRunner.startBlank(
+  var {page, session, dp} = await testRunner.startWithFrameControl(
       'Tests compositor animated image handling.');
-  await dp.Target.enable();
-
-  // Open the test page in a new tab with BeginFrameControl enabled.
-  await testTargetPage(await session.createTargetInNewContext(
-      800, 600, 'about:blank', true));
 
   // Loads an animated GIF into a a newly created tab with BeginFrame control
   // and verifies that:
@@ -17,114 +12,106 @@
   // - first screenshot starts the GIF animation,
   // - animation is advanced according to virtual time.
   // - the animation is not resynced after the first iteration.
-  async function testTargetPage(session) {
-    dp = session.protocol;
-    await dp.Runtime.enable();
-    await dp.HeadlessExperimental.enable();
+  await dp.Runtime.enable();
+  await dp.HeadlessExperimental.enable();
 
-    dp.Runtime.onConsoleAPICalled(data => {
-      const text = data.params.args[0].value;
-      testRunner.log(text);
-    });
+  dp.Runtime.onConsoleAPICalled(data => {
+    const text = data.params.args[0].value;
+    testRunner.log(text);
+  });
 
-    let virtualTimeBase = 0;
-    let totalElapsedTime = 0;
-    let lastGrantedChunk = 0;
-    let expiredCount = 0;
+  let virtualTimeBase = 0;
+  let totalElapsedTime = 0;
+  let lastGrantedChunk = 0;
+  let expiredCount = 0;
 
-    dp.Emulation.onVirtualTimeBudgetExpired(async data => {
-      ++expiredCount;
-      totalElapsedTime += lastGrantedChunk;
-      testRunner.log(`Expired count: ${expiredCount}, `
-          + `elaspedTime: ${totalElapsedTime}`);
+  dp.Emulation.onVirtualTimeBudgetExpired(async data => {
+    ++expiredCount;
+    totalElapsedTime += lastGrantedChunk;
+    testRunner.log(`Expired count: ${expiredCount}, `
+        + `elaspedTime: ${totalElapsedTime}`);
 
-      let grantVirtualTime = 500;
-      let frameTimeTicks = virtualTimeBase + totalElapsedTime;
+    let grantVirtualTime = 500;
+    let frameTimeTicks = virtualTimeBase + totalElapsedTime;
 
-      if (expiredCount === 1 + 7
-        || expiredCount === 1 + 7 + 5
-        || expiredCount === 1 + 7 + 5 + 6) {
-        // Animation starts when first screenshot is taken, so the first
-        // screenshot should be blue. Screenshot #2 is taken on the third second
-        // of the animation, so it should be yellow. Screenshot #3 is taken two
-        // animation cycles later, so it should be yelloe again.
-        const {result: {screenshotData}} =
-            await dp.HeadlessExperimental.beginFrame(
-                {frameTimeTicks, screenshot: {format: 'png'}});
-        await logScreenShotInfo(screenshotData);
-      } else {
-        await dp.HeadlessExperimental.beginFrame(
-            {frameTimeTicks, noDisplayUpdates: true});
-      }
-
-      // Grant more time or quit test.
-      if (expiredCount < 20) {
-        await dp.Emulation.setVirtualTimePolicy({
-          policy: 'pauseIfNetworkFetchesPending',
-          budget: grantVirtualTime});
-        lastGrantedChunk = grantVirtualTime;
-      } else {
-        testRunner.completeTest();
-      }
-    });
-
-    // Pause for the first time and remember base virtual time.
-    const {result: {virtualTimeTicksBase}} =
-        await dp.Emulation.setVirtualTimePolicy(
-              {initialVirtualTime: 100, policy: 'pause'});
-    virtualTimeBase = virtualTimeTicksBase;
-
-    // Renderer wants the very first frame to be fully updated.
-    await dp.HeadlessExperimental.beginFrame({noDisplayUpdates: false});
-
-    // Grant initial time.
-    lastGrantedChunk = 500;
-    await dp.Emulation.setVirtualTimePolicy({
-        policy: 'pauseIfNetworkFetchesPending',
-        budget: lastGrantedChunk, waitForNavigation: true});
-
-    // The loaded GIF is 100x100px and has 1 second of blue, 1 second of red and
-    // 1 second of yellow.
-    dp.Page.navigate(
-          {url: testRunner.url('/resources/compositor-image-animation.html')});
-
-    async function AdvanceTime() {
-      await dp.Emulation.onceVirtualTimeBudgetExpired();
-      totalElapsedTime += lastGrantedChunk;
-      testRunner.log(`Elasped time: ${totalElapsedTime}`);
-      frameTimeTicks = virtualTimeBase + totalElapsedTime;
+    if (expiredCount === 1 + 7
+      || expiredCount === 1 + 7 + 5
+      || expiredCount === 1 + 7 + 5 + 6) {
+      // Animation starts when first screenshot is taken, so the first
+      // screenshot should be blue. Screenshot #2 is taken on the third second
+      // of the animation, so it should be yellow. Screenshot #3 is taken two
+      // animation cycles later, so it should be yelloe again.
+      const {result: {screenshotData}} =
+          await dp.HeadlessExperimental.beginFrame(
+              {frameTimeTicks, screenshot: {format: 'png'}});
+      await logScreenShotInfo(screenshotData);
+    } else {
+      await dp.HeadlessExperimental.beginFrame(
+          {frameTimeTicks, noDisplayUpdates: true});
     }
 
-    async function GrantMoreTime(budget) {
-      lastGrantedChunk = budget;
+    // Grant more time or quit test.
+    if (expiredCount < 20) {
       await dp.Emulation.setVirtualTimePolicy({
-          policy: 'pauseIfNetworkFetchesPending', budget});
-    }
-
-    function logScreenShotInfo(pngBase64) {
-      const image = new Image();
-
-      let callback;
-      let promise = new Promise(fulfill => callback = fulfill);
-      image.onload = function() {
-        const canvas = document.createElement('canvas');
-        canvas.width = image.naturalWidth;
-        canvas.height = image.naturalHeight;
-        const ctx = canvas.getContext('2d');
-        ctx.drawImage(image, 0, 0);
-        const rgba = ctx.getImageData(0, 0, 1, 1).data;
-        testRunner.log(`Screenshot rgba: ${rgba}`);
-        callback();
-      }
-
-      image.src = `data:image/png;base64,${pngBase64}`;
-
-      return promise;
-    }
-
-    setTimeout(() => {
-      testRunner.log('Forced test termination');
+        policy: 'pauseIfNetworkFetchesPending',
+        budget: grantVirtualTime});
+      lastGrantedChunk = grantVirtualTime;
+    } else {
       testRunner.completeTest();
-    }, 10 * 1000);
+    }
+  });
+
+  // Pause for the first time and remember base virtual time.
+  const {result: {virtualTimeTicksBase}} =
+      await dp.Emulation.setVirtualTimePolicy(
+            {initialVirtualTime: 100, policy: 'pause'});
+  virtualTimeBase = virtualTimeTicksBase;
+
+  // Renderer wants the very first frame to be fully updated.
+  await dp.HeadlessExperimental.beginFrame({noDisplayUpdates: false});
+
+  // Grant initial time.
+  lastGrantedChunk = 500;
+  await dp.Emulation.setVirtualTimePolicy({
+      policy: 'pauseIfNetworkFetchesPending',
+      budget: lastGrantedChunk, waitForNavigation: true});
+
+  // The loaded GIF is 100x100px and has 1 second of blue, 1 second of red and
+  // 1 second of yellow.
+  dp.Page.navigate(
+        {url: testRunner.url('/resources/compositor-image-animation.html')});
+
+  async function AdvanceTime() {
+    await dp.Emulation.onceVirtualTimeBudgetExpired();
+    totalElapsedTime += lastGrantedChunk;
+    testRunner.log(`Elasped time: ${totalElapsedTime}`);
+    frameTimeTicks = virtualTimeBase + totalElapsedTime;
+  }
+
+  async function GrantMoreTime(budget) {
+    lastGrantedChunk = budget;
+    await dp.Emulation.setVirtualTimePolicy({
+        policy: 'pauseIfNetworkFetchesPending', budget});
+  }
+
+  function logScreenShotInfo(pngBase64) {
+    const image = new Image();
+
+    let callback;
+    let promise = new Promise(fulfill => callback = fulfill);
+    image.onload = function() {
+      const canvas = document.createElement('canvas');
+      canvas.width = image.naturalWidth;
+      canvas.height = image.naturalHeight;
+      const ctx = canvas.getContext('2d');
+      ctx.drawImage(image, 0, 0);
+      const rgba = ctx.getImageData(0, 0, 1, 1).data;
+      testRunner.log(`Screenshot rgba: ${rgba}`);
+      callback();
+    }
+
+    image.src = `data:image/png;base64,${pngBase64}`;
+
+    return promise;
   }
 })
diff --git a/headless/test/data/protocol/helpers/virtual-time-controller-test.js b/headless/test/data/protocol/helpers/virtual-time-controller-test.js
index a15b82e01..4ed49a71 100644
--- a/headless/test/data/protocol/helpers/virtual-time-controller-test.js
+++ b/headless/test/data/protocol/helpers/virtual-time-controller-test.js
@@ -3,48 +3,40 @@
 // found in the LICENSE file.
 
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank(
-    `Tests virtual time controller operation.`);
-  await dp.Target.enable();
-
   let VirtualTimeController =
       await testRunner.loadScript('virtual-time-controller.js');
 
-  // Open the test page in a new tab with BeginFrameControl enabled.
-  await testTargetPage(
-      await session.createTargetInNewContext(800, 600, 'about:blank', true));
+  let {page, session, dp} = await testRunner.startWithFrameControl(
+    `Tests virtual time controller operation.`);
 
-  async function testTargetPage(session) {
-    const dp = session.protocol;
-    await dp.Runtime.enable();
-    await dp.HeadlessExperimental.enable();
+  await dp.Runtime.enable();
+  await dp.HeadlessExperimental.enable();
 
-    dp.Runtime.onConsoleAPICalled(data => {
-      const text = data.params.args[0].value;
-      testRunner.log(text);
-    });
+  dp.Runtime.onConsoleAPICalled(data => {
+    const text = data.params.args[0].value;
+    testRunner.log(text);
+  });
 
-    let expirationCount = 0;
-    const vtc = new VirtualTimeController(testRunner, dp, 25);
-    await vtc.grantInitialTime(100, 1000, onInstalled, onExpired);
+  let expirationCount = 0;
+  const vtc = new VirtualTimeController(testRunner, dp, 25);
+  await vtc.grantInitialTime(100, 1000, onInstalled, onExpired);
 
-    async function onInstalled(virtualTimeBase){
-      testRunner.log(`onInstalled:`);
-    }
-
-    async function onExpired(totalElapsedTime) {
-      testRunner.log(`onExpired: ${totalElapsedTime}`);
-      if (expirationCount === 0)
-        await session.evaluate('startRAF()');
-
-      if (++expirationCount < 3) {
-        await vtc.grantTime(50, onExpired);
-      } else {
-        testRunner.completeTest();
-      }
-    }
-
-    dp.Page.navigate({url: testRunner.url(
-        'resources/virtual-time-controller-test.html')});
+  async function onInstalled(virtualTimeBase){
+    testRunner.log(`onInstalled:`);
   }
+
+  async function onExpired(totalElapsedTime) {
+    testRunner.log(`onExpired: ${totalElapsedTime}`);
+    if (expirationCount === 0)
+      await session.evaluate('startRAF()');
+
+    if (++expirationCount < 3) {
+      await vtc.grantTime(50, onExpired);
+    } else {
+      testRunner.completeTest();
+    }
+  }
+
+  dp.Page.navigate({url: testRunner.url(
+      'resources/virtual-time-controller-test.html')});
 })
diff --git a/headless/test/data/protocol/inspector-protocol-test.html b/headless/test/data/protocol/inspector-protocol-test.html
index e0c46263..0a11866 100644
--- a/headless/test/data/protocol/inspector-protocol-test.html
+++ b/headless/test/data/protocol/inspector-protocol-test.html
@@ -12,12 +12,12 @@
 testRunner.waitUntilDone = () => {};
 testRunner.setCanOpenWindows = () => {};
 testRunner.notifyDone = () => {
-  console.debug(JSON.stringify({id: 0, method: 'DONE', params: {}, result: output.join('\n')}));
+  sendProtocolMessage(JSON.stringify({id: 0, method: 'DONE', params: {}, result: output.join('\n')}));
 };
 DevToolsHost = {};
 DevToolsHost.sendMessageToEmbedder = (message) => {
   const object = JSON.parse(message);
-  console.debug(object.params[0]);
+  sendProtocolMessage(object.params[0]);
 }
 
 DevToolsHost.dummyPageURL = `http://127.0.0.1:${window.location.port}/protocol/inspector-protocol-page.html`;
diff --git a/headless/test/data/protocol/sanity/renderer-canvas.js b/headless/test/data/protocol/sanity/renderer-canvas.js
index 3f6d5145..dfcea27 100644
--- a/headless/test/data/protocol/sanity/renderer-canvas.js
+++ b/headless/test/data/protocol/sanity/renderer-canvas.js
@@ -3,80 +3,72 @@
 // found in the LICENSE file.
 
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank(
+  let {page, session, dp} = await testRunner.startWithFrameControl(
       'Tests renderer: canvas.');
 
-  // Open the test page in a new tab with BeginFrameControl enabled.
-  await testTargetPage(await session.createTargetInNewContext(
-      800, 600, 'about:blank', true));
+  await dp.Runtime.enable();
+  await dp.HeadlessExperimental.enable();
 
-  async function testTargetPage(session) {
-    dp = session.protocol;
-    await dp.Runtime.enable();
-    await dp.HeadlessExperimental.enable();
+  let RendererTestHelper =
+      await testRunner.loadScript('../helpers/renderer-test-helper.js');
+  let {httpInterceptor, frameNavigationHelper, virtualTimeController} =
+      await (new RendererTestHelper(testRunner, dp, page)).init();
 
-    let RendererTestHelper =
-        await testRunner.loadScript('../helpers/renderer-test-helper.js');
-    let {httpInterceptor, frameNavigationHelper, virtualTimeController} =
-        await (new RendererTestHelper(testRunner, dp, page)).init();
+  httpInterceptor.addResponse(
+      `http://example.com/`,
+      `<html>
+        <body>
+          <canvas id="test_canvas" width="100" height="100"
+                  style="position:absolute;left:0px;top:0px">
+            Oops!  Canvas not supported!
+          </canvas>
+          <script>
+            var context = document.getElementById("test_canvas").
+                          getContext("2d");
+            context.fillStyle = "rgb(255,0,0)";
+            context.fillRect(25, 25, 50, 50);
+          </script>
+        </body>
+      </html>`);
 
-    httpInterceptor.addResponse(
-        `http://example.com/`,
-        `<html>
-          <body>
-            <canvas id="test_canvas" width="100" height="100"
-                    style="position:absolute;left:0px;top:0px">
-              Oops!  Canvas not supported!
-            </canvas>
-            <script>
-              var context = document.getElementById("test_canvas").
-                            getContext("2d");
-              context.fillStyle = "rgb(255,0,0)";
-              context.fillRect(25, 25, 50, 50);
-            </script>
-          </body>
-        </html>`);
+  await virtualTimeController.grantInitialTime(500, 1000,
+    null,
+    async () => {
+      const frameTimeTicks = virtualTimeController.currentFrameTime();
+      const screenshotData =
+          (await dp.HeadlessExperimental.beginFrame(
+              {frameTimeTicks, screenshot: {format: 'png'}}))
+          .result.screenshotData;
+      await logScreenShotData(screenshotData);
+      testRunner.completeTest();
+    }
+  );
 
-    await virtualTimeController.grantInitialTime(500, 1000,
-      null,
-      async () => {
-        const frameTimeTicks = virtualTimeController.currentFrameTime();
-        const screenshotData =
-            (await dp.HeadlessExperimental.beginFrame(
-                {frameTimeTicks, screenshot: {format: 'png'}}))
-            .result.screenshotData;
-        await logScreenShotData(screenshotData);
-        testRunner.completeTest();
-      }
-    );
+  function logScreenShotData(pngBase64) {
+    const image = new Image();
 
-    function logScreenShotData(pngBase64) {
-      const image = new Image();
-
-      let callback;
-      let promise = new Promise(fulfill => callback = fulfill);
-      image.onload = function() {
-        testRunner.log(`Screenshot size: `
-            + `${image.naturalWidth} x ${image.naturalHeight}`);
-        const canvas = document.createElement('canvas');
-        canvas.width = image.naturalWidth;
-        canvas.height = image.naturalHeight;
-        const ctx = canvas.getContext('2d');
-        ctx.drawImage(image, 0, 0);
-        // Expected rgba @(0,0): 255,255,255,255
-        const rgba = ctx.getImageData(0, 0, 1, 1).data;
-        testRunner.log(`rgba @(0,0): ${rgba}`);
-        // Expected rgba @(25,25): 255,0,0,255
-        const rgba2 = ctx.getImageData(25, 25, 1, 1).data;
-        testRunner.log(`rgba @(25,25): ${rgba2}`);
-        callback();
-      }
-
-      image.src = `data:image/png;base64,${pngBase64}`;
-
-      return promise;
+    let callback;
+    let promise = new Promise(fulfill => callback = fulfill);
+    image.onload = function() {
+      testRunner.log(`Screenshot size: `
+          + `${image.naturalWidth} x ${image.naturalHeight}`);
+      const canvas = document.createElement('canvas');
+      canvas.width = image.naturalWidth;
+      canvas.height = image.naturalHeight;
+      const ctx = canvas.getContext('2d');
+      ctx.drawImage(image, 0, 0);
+      // Expected rgba @(0,0): 255,255,255,255
+      const rgba = ctx.getImageData(0, 0, 1, 1).data;
+      testRunner.log(`rgba @(0,0): ${rgba}`);
+      // Expected rgba @(25,25): 255,0,0,255
+      const rgba2 = ctx.getImageData(25, 25, 1, 1).data;
+      testRunner.log(`rgba @(25,25): ${rgba2}`);
+      callback();
     }
 
-    await frameNavigationHelper.navigate('http://example.com/');
+    image.src = `data:image/png;base64,${pngBase64}`;
+
+    return promise;
   }
+  await frameNavigationHelper.navigate('http://example.com/');
 })
diff --git a/headless/test/data/protocol/sanity/renderer-css-url-filter.js b/headless/test/data/protocol/sanity/renderer-css-url-filter.js
index 4f690c2e..d338d47 100644
--- a/headless/test/data/protocol/sanity/renderer-css-url-filter.js
+++ b/headless/test/data/protocol/sanity/renderer-css-url-filter.js
@@ -3,97 +3,90 @@
 // found in the LICENSE file.
 
 (async function(testRunner) {
-  let {page, session, dp} = await testRunner.startBlank(
-      'Tests renderer: canvas.');
-
-  // Open the test page in a new tab with BeginFrameControl enabled.
-  await testTargetPage(await session.createTargetInNewContext(
-      100, 100, 'about:blank', true));
+  let {page, session, dp} = await testRunner.startWithFrameControl(
+      'Tests renderer: canvas.', {width: 100, height: 100});
 
   // Ensures that "filter: url(...)" does not get into an infinite style update
   // loop.
-  async function testTargetPage(session) {
-    dp = session.protocol;
-    await dp.Runtime.enable();
-    await dp.HeadlessExperimental.enable();
+  await dp.Runtime.enable();
+  await dp.HeadlessExperimental.enable();
 
-    let RendererTestHelper =
-        await testRunner.loadScript('../helpers/renderer-test-helper.js');
-    let {httpInterceptor, frameNavigationHelper, virtualTimeController} =
-        await (new RendererTestHelper(testRunner, dp, page)).init();
+  let RendererTestHelper =
+      await testRunner.loadScript('../helpers/renderer-test-helper.js');
+  let {httpInterceptor, frameNavigationHelper, virtualTimeController} =
+      await (new RendererTestHelper(testRunner, dp, page)).init();
 
-    // The image from circle.svg will be drawn with the blur from blur.svg.
-    httpInterceptor.addResponse(
-        `http://www.example.com/`,
-        `<!DOCTYPE html>
-        <style>
-          body { margin: 0; }
-          img {
-            -webkit-filter: url(blur.svg#blur);
-            filter: url(blur.svg#blur);
-          }
-        </style>
-        <img src="circle.svg">`);
-
-    // Just a normal image.
-    httpInterceptor.addResponse(
-        `http://www.example.com/circle.svg`,
-        `<svg width="100" height="100" version="1.1"
-            xmlns="http://www.w3.org/2000/svg"
-          xmlns:xlink="http://www.w3.org/1999/xlink">
-          <circle cx="50" cy="50" r="50" fill="green" />
-        </svg>`);
-
-    // A blur filter stored inside an svg file.
-    httpInterceptor.addResponse(
-        `http://www.example.com/blur.svg#blur`,
-        `<svg width="100" height="100" version="1.1"
-            xmlns="http://www.w3.org/2000/svg"
-            xmlns:xlink="http://www.w3.org/1999/xlink">
-          <filter id="blur">
-            <feGaussianBlur in="SourceGraphic" stdDeviation="5"/>
-          </filter>
-        </svg>`);
-
-    await virtualTimeController.grantInitialTime(500, 1000,
-      null,
-      async () => {
-        const frameTimeTicks = virtualTimeController.currentFrameTime();
-        const screenshotData =
-            (await dp.HeadlessExperimental.beginFrame(
-                {frameTimeTicks, screenshot: {format: 'png'}}))
-            .result.screenshotData;
-        await logScreenShotData(screenshotData);
-        testRunner.completeTest();
-      }
-    );
-
-    function logScreenShotData(pngBase64) {
-      const image = new Image();
-
-      let callback;
-      let promise = new Promise(fulfill => callback = fulfill);
-      image.onload = function() {
-        testRunner.log(`Screenshot size: `
-            + `${image.naturalWidth} x ${image.naturalHeight}`);
-        const canvas = document.createElement('canvas');
-        canvas.width = image.naturalWidth;
-        canvas.height = image.naturalHeight;
-        const ctx = canvas.getContext('2d');
-        ctx.drawImage(image, 0, 0);
-        for (let n = 0; n < 25; ++n) {
-          const rgba = ctx.getImageData(n, n, 1, 1).data;
-          testRunner.log(`rgba @(${n},${n}): ${rgba}`);
+  // The image from circle.svg will be drawn with the blur from blur.svg.
+  httpInterceptor.addResponse(
+      `http://www.example.com/`,
+      `<!DOCTYPE html>
+      <style>
+        body { margin: 0; }
+        img {
+          -webkit-filter: url(blur.svg#blur);
+          filter: url(blur.svg#blur);
         }
+      </style>
+      <img src="circle.svg">`);
 
-        callback();
+  // Just a normal image.
+  httpInterceptor.addResponse(
+      `http://www.example.com/circle.svg`,
+      `<svg width="100" height="100" version="1.1"
+          xmlns="http://www.w3.org/2000/svg"
+        xmlns:xlink="http://www.w3.org/1999/xlink">
+        <circle cx="50" cy="50" r="50" fill="green" />
+      </svg>`);
+
+  // A blur filter stored inside an svg file.
+  httpInterceptor.addResponse(
+      `http://www.example.com/blur.svg#blur`,
+      `<svg width="100" height="100" version="1.1"
+          xmlns="http://www.w3.org/2000/svg"
+          xmlns:xlink="http://www.w3.org/1999/xlink">
+        <filter id="blur">
+          <feGaussianBlur in="SourceGraphic" stdDeviation="5"/>
+        </filter>
+      </svg>`);
+
+  await virtualTimeController.grantInitialTime(500, 1000,
+    null,
+    async () => {
+      const frameTimeTicks = virtualTimeController.currentFrameTime();
+      const screenshotData =
+          (await dp.HeadlessExperimental.beginFrame(
+              {frameTimeTicks, screenshot: {format: 'png'}}))
+          .result.screenshotData;
+      await logScreenShotData(screenshotData);
+      testRunner.completeTest();
+    }
+  );
+
+  function logScreenShotData(pngBase64) {
+    const image = new Image();
+
+    let callback;
+    let promise = new Promise(fulfill => callback = fulfill);
+    image.onload = function() {
+      testRunner.log(`Screenshot size: `
+          + `${image.naturalWidth} x ${image.naturalHeight}`);
+      const canvas = document.createElement('canvas');
+      canvas.width = image.naturalWidth;
+      canvas.height = image.naturalHeight;
+      const ctx = canvas.getContext('2d');
+      ctx.drawImage(image, 0, 0);
+      for (let n = 0; n < 25; ++n) {
+        const rgba = ctx.getImageData(n, n, 1, 1).data;
+        testRunner.log(`rgba @(${n},${n}): ${rgba}`);
       }
 
-      image.src = `data:image/png;base64,${pngBase64}`;
-
-      return promise;
+      callback();
     }
 
-    await frameNavigationHelper.navigate('http://www.example.com/');
+    image.src = `data:image/png;base64,${pngBase64}`;
+
+    return promise;
   }
+
+  await frameNavigationHelper.navigate('http://www.example.com/');
 })
diff --git a/headless/test/headless_protocol_browsertest.cc b/headless/test/headless_protocol_browsertest.cc
index bd0227c..2439bd4 100644
--- a/headless/test/headless_protocol_browsertest.cc
+++ b/headless/test/headless_protocol_browsertest.cc
@@ -39,7 +39,7 @@
 class HeadlessProtocolBrowserTest
     : public HeadlessAsyncDevTooledBrowserTest,
       public HeadlessDevToolsClient::RawProtocolListener,
-      public runtime::Observer {
+      public runtime::ExperimentalObserver {
  public:
   HeadlessProtocolBrowserTest() {
     embedded_test_server()->ServeFilesFromSourceDirectory(
@@ -51,8 +51,12 @@
   // HeadlessWebContentsObserver implementation.
   void DevToolsTargetReady() override {
     HeadlessAsyncDevTooledBrowserTest::DevToolsTargetReady();
-    devtools_client_->GetRuntime()->AddObserver(this);
+    devtools_client_->GetRuntime()->GetExperimental()->AddObserver(this);
     devtools_client_->GetRuntime()->Enable();
+    devtools_client_->GetRuntime()->GetExperimental()->AddBinding(
+        headless::runtime::AddBindingParams::Builder()
+            .SetName("sendProtocolMessage")
+            .Build());
     browser_devtools_client_->SetRawProtocolListener(this);
   }
 
@@ -81,23 +85,8 @@
   }
 
   // runtime::Observer implementation.
-  void OnConsoleAPICalled(
-      const runtime::ConsoleAPICalledParams& params) override {
-    const std::vector<std::unique_ptr<runtime::RemoteObject>>& args =
-        *params.GetArgs();
-    if (args.empty())
-      return;
-    if (params.GetType() != runtime::ConsoleAPICalledType::DEBUG)
-      return;
-
-    runtime::RemoteObject* object = args[0].get();
-    if (object->GetType() != runtime::RemoteObjectType::STRING)
-      return;
-
-    DispatchMessageFromJS(object->GetValue()->GetString());
-  }
-
-  void DispatchMessageFromJS(const std::string& json_message) {
+  void OnBindingCalled(const runtime::BindingCalledParams& params) override {
+    std::string json_message = params.GetPayload();
     std::unique_ptr<base::Value> message = base::JSONReader::Read(json_message);
     const base::DictionaryValue* message_dict;
     const base::DictionaryValue* params_dict;
diff --git a/headless/test/headless_render_browsertest.cc b/headless/test/headless_render_browsertest.cc
deleted file mode 100644
index fb26cd0..0000000
--- a/headless/test/headless_render_browsertest.cc
+++ /dev/null
@@ -1,1488 +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 <functional>
-
-#include "base/path_service.h"
-#include "base/run_loop.h"
-#include "base/threading/thread_restrictions.h"
-#include "build/build_config.h"
-#include "content/public/test/browser_test.h"
-#include "headless/public/devtools/domains/dom_snapshot.h"
-#include "headless/public/devtools/domains/page.h"
-#include "headless/public/devtools/domains/runtime.h"
-#include "headless/public/headless_devtools_client.h"
-#include "headless/test/headless_render_test.h"
-#include "net/test/embedded_test_server/http_response.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#define HEADLESS_RENDER_BROWSERTEST(clazz)                  \
-  class HeadlessRenderBrowserTest##clazz : public clazz {}; \
-  HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessRenderBrowserTest##clazz)
-
-#define DISABLED_HEADLESS_RENDER_BROWSERTEST(clazz)         \
-  class HeadlessRenderBrowserTest##clazz : public clazz {}; \
-  DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessRenderBrowserTest##clazz)
-
-// TODO(dats): For some reason we are missing all HTTP redirects.
-// crbug.com/789298
-#define DISABLE_HTTP_REDIRECTS_CHECKS
-
-namespace headless {
-
-namespace {
-
-constexpr char kSomeUrl[] = "http://example.com/foobar";
-constexpr char kTextHtml[] = "text/html";
-constexpr char kApplicationOctetStream[] = "application/octet-stream";
-constexpr char kImagePng[] = "image/png";
-constexpr char kImageSvgXml[] = "image/svg+xml";
-
-using dom_snapshot::GetSnapshotResult;
-using dom_snapshot::DOMNode;
-using dom_snapshot::LayoutTreeNode;
-using net::test_server::HttpRequest;
-using net::test_server::HttpResponse;
-using net::test_server::BasicHttpResponse;
-using net::test_server::RawHttpResponse;
-using page::FrameScheduledNavigationReason;
-using testing::ElementsAre;
-using testing::UnorderedElementsAre;
-using testing::Eq;
-using testing::Ne;
-using testing::StartsWith;
-
-template <typename T, typename V>
-std::vector<T> ElementsView(const std::vector<std::unique_ptr<V>>& elements,
-                            std::function<bool(const V&)> filter,
-                            std::function<T(const V&)> transform) {
-  std::vector<T> result;
-  for (const auto& element : elements) {
-    if (filter(*element))
-      result.push_back(transform(*element));
-  }
-  return result;
-}
-
-bool HasType(int type, const DOMNode& node) {
-  return node.GetNodeType() == type;
-}
-bool HasName(const char* name, const DOMNode& node) {
-  return node.GetNodeName() == name;
-}
-bool IsTag(const DOMNode& node) {
-  return HasType(1, node);
-}
-bool IsText(const DOMNode& node) {
-  return HasType(3, node);
-}
-
-std::vector<std::string> TextLayout(const GetSnapshotResult* snapshot) {
-  return ElementsView<std::string, LayoutTreeNode>(
-      *snapshot->GetLayoutTreeNodes(),
-      [](const auto& node) { return node.HasLayoutText(); },
-      [](const auto& node) { return node.GetLayoutText(); });
-}
-
-std::vector<const DOMNode*> FilterDOM(
-    const GetSnapshotResult* snapshot,
-    std::function<bool(const DOMNode&)> filter) {
-  return ElementsView<const DOMNode*, DOMNode>(
-      *snapshot->GetDomNodes(), filter, [](const auto& n) { return &n; });
-}
-
-std::vector<const DOMNode*> FindTags(const GetSnapshotResult* snapshot,
-                                     const char* name = nullptr) {
-  return FilterDOM(snapshot, [name](const auto& n) {
-    return IsTag(n) && (!name || HasName(name, n));
-  });
-}
-
-size_t IndexInDOM(const GetSnapshotResult* snapshot, const DOMNode* node) {
-  for (size_t i = 0; i < snapshot->GetDomNodes()->size(); ++i) {
-    if (snapshot->GetDomNodes()->at(i).get() == node)
-      return i;
-  }
-  CHECK(false);
-  return static_cast<size_t>(-1);
-}
-
-const DOMNode* GetAt(const GetSnapshotResult* snapshot, size_t index) {
-  CHECK_LE(index, snapshot->GetDomNodes()->size());
-  return snapshot->GetDomNodes()->at(index).get();
-}
-
-const DOMNode* NextNode(const GetSnapshotResult* snapshot,
-                        const DOMNode* node) {
-  return GetAt(snapshot, IndexInDOM(snapshot, node) + 1);
-}
-
-MATCHER_P(NodeName, expected, "") {
-  return arg->GetNodeName() == expected;
-}
-MATCHER_P(NodeValue, expected, "") {
-  return arg->GetNodeValue() == expected;
-}
-MATCHER_P(NodeType, expected, 0) {
-  return arg->GetNodeType() == expected;
-}
-
-MATCHER_P(RemoteString, expected, "") {
-  return arg->GetType() == runtime::RemoteObjectType::STRING &&
-         arg->GetValue()->GetString() == expected;
-}
-
-MATCHER_P(RequestPath, expected, "") {
-  return arg.relative_url == expected;
-}
-
-MATCHER_P(Reason, expected, "") {
-  return arg.reason == expected;
-}
-
-MATCHER_P(CookieValue, expected, "") {
-  return arg->GetValue() == expected;
-}
-
-const DOMNode* FindTag(const GetSnapshotResult* snapshot, const char* name) {
-  auto tags = FindTags(snapshot, name);
-  if (tags.empty())
-    return nullptr;
-  EXPECT_THAT(tags, ElementsAre(NodeName(name)));
-  return tags[0];
-}
-
-TestNetworkInterceptor::Response HttpRedirect(
-    int code,
-    const std::string& url,
-    const std::string& status = "Moved") {
-  CHECK(code >= 300 && code < 400);
-  std::stringstream str;
-  str << "HTTP/1.1 " << code << " " << status << "\r\nLocation: " << url
-      << "\r\n\r\n";
-  return TestNetworkInterceptor::Response(str.str());
-}
-
-TestNetworkInterceptor::Response HttpOk(
-    const std::string& html,
-    const std::string& mime_type = kTextHtml) {
-  return TestNetworkInterceptor::Response(html, mime_type);
-}
-
-TestNetworkInterceptor::Response ResponseFromFile(
-    const std::string& file_name,
-    const std::string& mime_type) {
-  static const base::FilePath kTestDataDirectory(
-      FILE_PATH_LITERAL("headless/test/data"));
-
-  base::ScopedAllowBlockingForTesting allow_blocking;
-
-  base::FilePath src_dir;
-  CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &src_dir));
-  base::FilePath file_path =
-      src_dir.Append(kTestDataDirectory).Append(file_name);
-  std::string contents;
-  CHECK(base::ReadFileToString(file_path, &contents));
-
-  return TestNetworkInterceptor::Response(contents, mime_type);
-}
-
-}  // namespace
-
-class HelloWorldTest : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse(kSomeUrl, HttpOk(R"|(<!doctype html>
-<h1>Hello headless world!</h1>
-)|"));
-    return GURL(kSomeUrl);
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(FindTags(dom_snapshot),
-                ElementsAre(NodeName("HTML"), NodeName("HEAD"),
-                            NodeName("BODY"), NodeName("H1")));
-    EXPECT_THAT(
-        FilterDOM(dom_snapshot, IsText),
-        ElementsAre(NodeValue("Hello headless world!"), NodeValue("\n")));
-    EXPECT_THAT(TextLayout(dom_snapshot), ElementsAre("Hello headless world!"));
-    EXPECT_THAT(interceptor_->urls_requested(), ElementsAre(kSomeUrl));
-    EXPECT_FALSE(main_frame_.empty());
-    EXPECT_TRUE(scheduled_navigations_.empty());
-    EXPECT_THAT(frames_[main_frame_].size(), Eq(1u));
-    const auto& frame = frames_[main_frame_][0];
-    EXPECT_THAT(frame->GetUrl(), Eq(kSomeUrl));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(HelloWorldTest);
-
-class TimeoutTest : public HelloWorldTest {
- private:
-  void OnPageRenderCompleted() override {
-    // Never complete.
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    FAIL() << "Should not reach here";
-  }
-
-  void OnTimeout() override { SetTestCompleted(); }
-};
-HEADLESS_RENDER_BROWSERTEST(TimeoutTest);
-
-class JavaScriptOverrideTitle_JsEnabled : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse(kSomeUrl, HttpOk(R"|(
-<html>
-  <head>
-    <title>JavaScript is off</title>
-    <script language="JavaScript">
-      <!-- Begin
-        document.title = 'JavaScript is on';
-      //  End -->
-    </script>
-  </head>
-  <body onload="settitle()">
-    Hello, World!
-  </body>
-</html>
-)|"));
-    return GURL(kSomeUrl);
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    const DOMNode* value =
-        NextNode(dom_snapshot, FindTag(dom_snapshot, "TITLE"));
-    EXPECT_THAT(value, NodeValue("JavaScript is on"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(JavaScriptOverrideTitle_JsEnabled);
-
-class JavaScriptOverrideTitle_JsDisabled
-    : public JavaScriptOverrideTitle_JsEnabled {
- private:
-  void OverrideWebPreferences(WebPreferences* preferences) override {
-    JavaScriptOverrideTitle_JsEnabled::OverrideWebPreferences(preferences);
-    preferences->javascript_enabled = false;
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    const DOMNode* value =
-        NextNode(dom_snapshot, FindTag(dom_snapshot, "TITLE"));
-    EXPECT_THAT(value, NodeValue("JavaScript is off"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(JavaScriptOverrideTitle_JsDisabled);
-
-class JavaScriptConsoleErrors : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse(kSomeUrl, HttpOk(R"|(
-<html>
-  <head>
-    <script language="JavaScript">
-      <![CDATA[
-        function image() {
-          window.open('<xsl:value-of select="/IMAGE/@href" />');
-        }
-      ]]>
-    </script>
-  </head>
-  <body onload="func3()">
-    <script type="text/javascript">
-      func1()
-    </script>
-    <script type="text/javascript">
-      func2();
-    </script>
-    <script type="text/javascript">
-      console.log("Hello, Script!");
-    </script>
-  </body>
-</html>
-)|"));
-    return GURL(kSomeUrl);
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(console_log_, ElementsAre("L Hello, Script!"));
-    EXPECT_THAT(js_exceptions_,
-                ElementsAre(StartsWith("Uncaught SyntaxError:"),
-                            StartsWith("Uncaught ReferenceError: func1"),
-                            StartsWith("Uncaught ReferenceError: func2"),
-                            StartsWith("Uncaught ReferenceError: func3")));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(JavaScriptConsoleErrors);
-
-class DelayedCompletion : public HeadlessRenderTest {
- private:
-  base::TimeTicks start_;
-
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse(kSomeUrl, HttpOk(R"|(
-<html>
-  <body>
-   <script type="text/javascript">
-     setTimeout(() => {
-       var div = document.getElementById('content');
-       var p = document.createElement('p');
-       p.textContent = 'delayed text';
-       div.appendChild(p);
-     }, 3000);
-   </script>
-    <div id="content"/>
-  </body>
-</html>
-)|"));
-    start_ = base::TimeTicks::Now();
-    return GURL(kSomeUrl);
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    base::TimeTicks end = base::TimeTicks::Now();
-    EXPECT_THAT(
-        FindTags(dom_snapshot),
-        ElementsAre(NodeName("HTML"), NodeName("HEAD"), NodeName("BODY"),
-                    NodeName("SCRIPT"), NodeName("DIV"), NodeName("P")));
-    const DOMNode* value = NextNode(dom_snapshot, FindTag(dom_snapshot, "P"));
-    EXPECT_THAT(value, NodeValue("delayed text"));
-    // The page delays output for 3 seconds. Due to virtual time this should
-    // take significantly less actual time.
-    base::TimeDelta passed = end - start_;
-    EXPECT_THAT(passed.InSecondsF(), testing::Le(2.9f));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(DelayedCompletion);
-
-class ClientRedirectChain : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/", HttpOk(R"|(
-<html>
-  <head>
-    <meta http-equiv="refresh" content="0; url=http://www.example.com/1"/>
-    <title>Hello, World 0</title>
-  </head>
-  <body>http://www.example.com/</body>
-</html>
-)|"));
-    interceptor_->InsertResponse("http://www.example.com/1", HttpOk(R"|(
-<html>
-  <head>
-    <title>Hello, World 1</title>
-    <script>
-      document.location='http://www.example.com/2';
-    </script>
-  </head>
-  <body>http://www.example.com/1</body>
-</html>
-)|"));
-    interceptor_->InsertResponse("http://www.example.com/2", HttpOk(R"|(
-<html>
-  <head>
-    <title>Hello, World 2</title>
-    <script>
-      setTimeout("document.location='http://www.example.com/3'", 1000);
-    </script>
-  </head>
-  <body>http://www.example.com/2</body>
-</html>
-)|"));
-    interceptor_->InsertResponse("http://www.example.com/3", HttpOk(R"|(
-<html>
-  <head>
-    <title>Pass</title>
-  </head>
-  <body>
-    http://www.example.com/3
-    <img src="pass">
-  </body>
-</html>
-)|"));
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(
-        interceptor_->urls_requested(),
-        ElementsAre("http://www.example.com/", "http://www.example.com/1",
-                    "http://www.example.com/2", "http://www.example.com/3",
-                    "http://www.example.com/pass"));
-    const DOMNode* value =
-        NextNode(dom_snapshot, FindTag(dom_snapshot, "TITLE"));
-    EXPECT_THAT(value, NodeValue("Pass"));
-    EXPECT_THAT(
-        scheduled_navigations_[main_frame_],
-        ElementsAre(Reason(FrameScheduledNavigationReason::META_TAG_REFRESH),
-                    Reason(FrameScheduledNavigationReason::SCRIPT_INITIATED),
-                    Reason(FrameScheduledNavigationReason::SCRIPT_INITIATED)));
-    EXPECT_THAT(frames_[main_frame_].size(), Eq(4u));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(ClientRedirectChain);
-
-class ClientRedirectChain_NoJs : public ClientRedirectChain {
- private:
-  void OverrideWebPreferences(WebPreferences* preferences) override {
-    ClientRedirectChain::OverrideWebPreferences(preferences);
-    preferences->javascript_enabled = false;
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(
-        interceptor_->urls_requested(),
-        ElementsAre("http://www.example.com/", "http://www.example.com/1"));
-    const DOMNode* value =
-        NextNode(dom_snapshot, FindTag(dom_snapshot, "TITLE"));
-    EXPECT_THAT(value, NodeValue("Hello, World 1"));
-    EXPECT_THAT(
-        scheduled_navigations_[main_frame_],
-        ElementsAre(Reason(FrameScheduledNavigationReason::META_TAG_REFRESH)));
-    EXPECT_THAT(frames_[main_frame_].size(), Eq(2u));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(ClientRedirectChain_NoJs);
-
-class ServerRedirectChain : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/",
-                                 HttpRedirect(302, "http://www.example.com/1"));
-    interceptor_->InsertResponse("http://www.example.com/1",
-                                 HttpRedirect(301, "http://www.example.com/2"));
-    interceptor_->InsertResponse("http://www.example.com/2",
-                                 HttpRedirect(302, "http://www.example.com/3"));
-    interceptor_->InsertResponse("http://www.example.com/3",
-                                 HttpOk("<p>Pass</p>"));
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(
-        interceptor_->urls_requested(),
-        ElementsAre("http://www.example.com/", "http://www.example.com/1",
-                    "http://www.example.com/2", "http://www.example.com/3"));
-    const DOMNode* value = NextNode(dom_snapshot, FindTag(dom_snapshot, "P"));
-    EXPECT_THAT(value, NodeValue("Pass"));
-#ifndef DISABLE_HTTP_REDIRECTS_CHECKS
-    EXPECT_THAT(
-        scheduled_navigations_[main_frame_],
-        ElementsAre(
-            Reason(FrameScheduledNavigationReason::HTTP_HEADER_REFRESH),
-            Reason(FrameScheduledNavigationReason::HTTP_HEADER_REFRESH),
-            Reason(FrameScheduledNavigationReason::HTTP_HEADER_REFRESH)));
-    EXPECT_THAT(frames_[main_frame_].size(), Eq(4u));
-#endif  // #ifndef DISABLE_HTTP_REDIRECTS_CHECKS
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(ServerRedirectChain);
-
-class ServerRedirectToFailure : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/",
-                                 HttpRedirect(302, "http://www.example.com/1"));
-    interceptor_->InsertResponse(
-        "http://www.example.com/1",
-        HttpRedirect(301, "http://www.example.com/FAIL"));
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(
-        interceptor_->urls_requested(),
-        ElementsAre("http://www.example.com/", "http://www.example.com/1",
-                    "http://www.example.com/FAIL"));
-  }
-};
-// TODO(crbug.com/861548): re-implement as DevTools protocol test.
-DISABLED_HEADLESS_RENDER_BROWSERTEST(ServerRedirectToFailure);
-
-class ServerRedirectRelativeChain : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/",
-                                 HttpRedirect(302, "http://www.mysite.com/1"));
-    interceptor_->InsertResponse("http://www.mysite.com/1",
-                                 HttpRedirect(301, "/2"));
-    interceptor_->InsertResponse("http://www.mysite.com/2",
-                                 HttpOk("<p>Pass</p>"));
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(
-        interceptor_->urls_requested(),
-        ElementsAre("http://www.example.com/", "http://www.mysite.com/1",
-                    "http://www.mysite.com/2"));
-    const DOMNode* value = NextNode(dom_snapshot, FindTag(dom_snapshot, "P"));
-    EXPECT_THAT(value, NodeValue("Pass"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(ServerRedirectRelativeChain);
-
-class MixedRedirectChain : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/", HttpOk(R"|(
- <html>
-   <head>
-     <meta http-equiv="refresh" content="0; url=http://www.example.com/1"/>
-     <title>Hello, World 0</title>
-   </head>
-   <body>http://www.example.com/</body>
- </html>
- )|"));
-    interceptor_->InsertResponse("http://www.example.com/1", HttpOk(R"|(
- <html>
-   <head>
-     <title>Hello, World 1</title>
-     <script>
-       document.location='http://www.example.com/2';
-     </script>
-   </head>
-   <body>http://www.example.com/1</body>
- </html>
- )|"));
-    interceptor_->InsertResponse("http://www.example.com/2",
-                                 HttpRedirect(302, "3"));
-    interceptor_->InsertResponse("http://www.example.com/3",
-                                 HttpRedirect(301, "http://www.example.com/4"));
-    interceptor_->InsertResponse("http://www.example.com/4",
-                                 HttpOk("<p>Pass</p>"));
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(
-        interceptor_->urls_requested(),
-        ElementsAre("http://www.example.com/", "http://www.example.com/1",
-                    "http://www.example.com/2", "http://www.example.com/3",
-                    "http://www.example.com/4"));
-    const DOMNode* value = NextNode(dom_snapshot, FindTag(dom_snapshot, "P"));
-    EXPECT_THAT(value, NodeValue("Pass"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(MixedRedirectChain);
-
-class FramesRedirectChain : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/",
-                                 HttpRedirect(302, "http://www.example.com/1"));
-    interceptor_->InsertResponse("http://www.example.com/1", HttpOk(R"|(
-<html>
- <frameset>
-  <frame src="http://www.example.com/frameA/">
-  <frame src="http://www.example.com/frameB/">
- </frameset>
-</html>
-)|"));
-
-    // Frame A
-    interceptor_->InsertResponse("http://www.example.com/frameA/", HttpOk(R"|(
-<html>
- <head>
-  <script>document.location='http://www.example.com/frameA/1'</script>
- </head>
- <body>HELLO WORLD 1</body>
-</html>
-)|"));
-    interceptor_->InsertResponse("http://www.example.com/frameA/1",
-                                 HttpRedirect(301, "/frameA/2"));
-    interceptor_->InsertResponse("http://www.example.com/frameA/2",
-                                 HttpOk("<p>FRAME A</p>"));
-
-    // Frame B
-    interceptor_->InsertResponse("http://www.example.com/frameB/", HttpOk(R"|(
-<html>
- <head><title>HELLO WORLD 2</title></head>
- <body>
-  <iframe src="http://www.example.com/iframe/"></iframe>
- </body>
-</html>
-)|"));
-    interceptor_->InsertResponse("http://www.example.com/iframe/", HttpOk(R"|(
-<html>
- <head>
-  <script>document.location='http://www.example.com/iframe/1'</script>
- </head>
- <body>HELLO WORLD 1</body>
-</html>
-)|"));
-    interceptor_->InsertResponse("http://www.example.com/iframe/1",
-                                 HttpRedirect(302, "/iframe/2"));
-    interceptor_->InsertResponse("http://www.example.com/iframe/2",
-                                 HttpRedirect(301, "3"));
-    interceptor_->InsertResponse("http://www.example.com/iframe/3",
-                                 HttpOk("<p>IFRAME B</p>"));
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(
-        interceptor_->urls_requested(),
-        UnorderedElementsAre(
-            "http://www.example.com/", "http://www.example.com/1",
-            "http://www.example.com/frameA/", "http://www.example.com/frameA/1",
-            "http://www.example.com/frameA/2", "http://www.example.com/frameB/",
-            "http://www.example.com/iframe/", "http://www.example.com/iframe/1",
-            "http://www.example.com/iframe/2",
-            "http://www.example.com/iframe/3"));
-    auto dom = FindTags(dom_snapshot, "P");
-    EXPECT_THAT(dom, ElementsAre(NodeName("P"), NodeName("P")));
-    EXPECT_THAT(NextNode(dom_snapshot, dom[0]), NodeValue("FRAME A"));
-    EXPECT_THAT(NextNode(dom_snapshot, dom[1]), NodeValue("IFRAME B"));
-
-    const page::Frame* main_frame = nullptr;
-    const page::Frame* a_frame = nullptr;
-    const page::Frame* b_frame = nullptr;
-    const page::Frame* i_frame = nullptr;
-    EXPECT_THAT(frames_.size(), Eq(4u));
-    for (const auto& it : frames_) {
-      if (it.second.back()->GetUrl() == "http://www.example.com/1")
-        main_frame = it.second.back().get();
-      else if (it.second.back()->GetUrl() == "http://www.example.com/frameA/2")
-        a_frame = it.second.back().get();
-      else if (it.second.back()->GetUrl() == "http://www.example.com/frameB/")
-        b_frame = it.second.back().get();
-      else if (it.second.back()->GetUrl() == "http://www.example.com/iframe/3")
-        i_frame = it.second.back().get();
-      else
-        ADD_FAILURE() << "Unexpected frame URL: " << it.second.back()->GetUrl();
-    }
-
-#ifndef DISABLE_HTTP_REDIRECTS_CHECKS
-    EXPECT_THAT(frames_[main_frame->GetId()].size(), Eq(2u));
-    EXPECT_THAT(frames_[a_frame->GetId()].size(), Eq(3u));
-    EXPECT_THAT(frames_[b_frame->GetId()].size(), Eq(1u));
-    EXPECT_THAT(frames_[i_frame->GetId()].size(), Eq(4u));
-    EXPECT_THAT(scheduled_navigations_[main_frame->GetId()],
-                ElementsAre(Reason(
-                    FrameScheduledNavigationReason::HTTP_HEADER_REFRESH)));
-    EXPECT_THAT(
-        scheduled_navigations_[a_frame->GetId()],
-        ElementsAre(
-            Reason(FrameScheduledNavigationReason::SCRIPT_INITIATED),
-            Reason(FrameScheduledNavigationReason::HTTP_HEADER_REFRESH)));
-    EXPECT_THAT(
-        scheduled_navigations_[i_frame->GetId()],
-        ElementsAre(
-            Reason(FrameScheduledNavigationReason::SCRIPT_INITIATED),
-            Reason(FrameScheduledNavigationReason::HTTP_HEADER_REFRESH),
-            Reason(FrameScheduledNavigationReason::HTTP_HEADER_REFRESH)));
-#endif  // #ifndef DISABLE_HTTP_REDIRECTS_CHECKS
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(FramesRedirectChain);
-
-class DoubleRedirect : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/", HttpOk(R"|(
-<html>
-  <head>
-    <title>Hello, World 1</title>
-    <script>
-      document.location='http://www.example.com/1';
-      document.location='http://www.example.com/2';
-    </script>
-  </head>
-  <body>http://www.example.com/1</body>
-</html>
-)|"));
-    interceptor_->InsertResponse("http://www.example.com/2",
-                                 HttpOk("<p>Pass</p>"));
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    // Two navigations have been scheduled while the document was loading...
-    EXPECT_THAT(
-        scheduled_navigations_[main_frame_],
-        ElementsAre(Reason(FrameScheduledNavigationReason::SCRIPT_INITIATED),
-                    Reason(FrameScheduledNavigationReason::SCRIPT_INITIATED)));
-    // ..., but only the second one was started. It canceled the first one.
-    EXPECT_THAT(
-        interceptor_->urls_requested(),
-        ElementsAre("http://www.example.com/", "http://www.example.com/2"));
-    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")),
-                NodeValue("Pass"));
-    EXPECT_THAT(frames_[main_frame_].size(), Eq(2u));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(DoubleRedirect);
-
-class RedirectAfterCompletion : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/", HttpOk(R"|(
-<html>
- <head>
-  <meta http-equiv='refresh' content='120; url=http://www.example.com/1'>
- </head>
- <body><p>Pass</p></body>
-</html>
-)|"));
-    interceptor_->InsertResponse("http://www.example.com/1",
-                                 HttpOk("<p>Fail</p>"));
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    // While the document was loading, one navigation has been scheduled...
-    EXPECT_THAT(
-        scheduled_navigations_[main_frame_],
-        ElementsAre(Reason(FrameScheduledNavigationReason::META_TAG_REFRESH)));
-    // ..., but because of the timeout, it has not been started yet.
-    EXPECT_THAT(interceptor_->urls_requested(),
-                ElementsAre("http://www.example.com/"));
-    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")),
-                NodeValue("Pass"));
-    EXPECT_THAT(frames_[main_frame_].size(), Eq(1u));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(RedirectAfterCompletion);
-
-class Redirect307PostMethod : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/", HttpOk(R"|(
-<html>
- <body onload='document.forms[0].submit();'>
-  <form action='1' method='post'>
-   <input name='foo' value='bar'>
-  </form>
- </body>
-</html>
-)|"));
-    interceptor_->InsertResponse("http://www.example.com/1",
-                                 HttpRedirect(307, "/2"));
-    interceptor_->InsertResponse("http://www.example.com/2",
-                                 HttpOk("<p>Pass</p>"));
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(
-        interceptor_->urls_requested(),
-        ElementsAre("http://www.example.com/", "http://www.example.com/1",
-                    "http://www.example.com/2"));
-    EXPECT_THAT(interceptor_->methods_requested(),
-                ElementsAre("GET", "POST", "POST"));
-    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")),
-                NodeValue("Pass"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(Redirect307PostMethod);
-
-class RedirectPostChain : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/", HttpOk(R"|(
-<html>
- <body onload='document.forms[0].submit();'>
-  <form action='1' method='post'>
-   <input name='foo' value='bar'>
-  </form>
- </body>
-</html>
-)|"));
-    interceptor_->InsertResponse("http://www.example.com/1",
-                                 HttpRedirect(307, "/2"));
-    interceptor_->InsertResponse("http://www.example.com/2", HttpOk(R"|(
-<html>
- <body onload='document.forms[0].submit();'>
-  <form action='3' method='post'>
-  </form>
- </body>
-</html>
-)|"));
-    interceptor_->InsertResponse("http://www.example.com/3",
-                                 HttpRedirect(307, "/4"));
-    interceptor_->InsertResponse("http://www.example.com/4",
-                                 HttpOk("<p>Pass</p>"));
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(
-        interceptor_->urls_requested(),
-        ElementsAre("http://www.example.com/", "http://www.example.com/1",
-                    "http://www.example.com/2", "http://www.example.com/3",
-                    "http://www.example.com/4"));
-    EXPECT_THAT(interceptor_->methods_requested(),
-                ElementsAre("GET", "POST", "POST", "POST", "POST"));
-    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")),
-                NodeValue("Pass"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(RedirectPostChain);
-
-class Redirect307PutMethod : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/", HttpOk(R"|(
- <html>
-  <head>
-   <script>
-    function doPut() {
-      var xhr = new XMLHttpRequest();
-      xhr.open('PUT', 'http://www.example.com/1');
-      xhr.setRequestHeader('Content-Type', 'text/plain');
-      xhr.addEventListener('load', function() {
-        document.getElementById('content').textContent = this.responseText;
-      });
-      xhr.send('some data');
-    }
-   </script>
-  </head>
-  <body onload='doPut();'>
-   <p id="content"></p>
-  </body>
- </html>
- )|"));
-    interceptor_->InsertResponse("http://www.example.com/1",
-                                 HttpRedirect(307, "/2"));
-    interceptor_->InsertResponse("http://www.example.com/2",
-                                 {"Pass", "text/plain"});
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(
-        interceptor_->urls_requested(),
-        ElementsAre("http://www.example.com/", "http://www.example.com/1",
-                    "http://www.example.com/2"));
-    EXPECT_THAT(interceptor_->methods_requested(),
-                ElementsAre("GET", "PUT", "PUT"));
-    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")),
-                NodeValue("Pass"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(Redirect307PutMethod);
-
-class Redirect303PutGet : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/", HttpOk(R"|(
-<html>
- <head>
-  <script>
-   function doPut() {
-     var xhr = new XMLHttpRequest();
-     xhr.open('PUT', 'http://www.example.com/1');
-     xhr.setRequestHeader('Content-Type', 'text/plain');
-     xhr.addEventListener('load', function() {
-       document.getElementById('content').textContent = this.responseText;
-     });
-     xhr.send('some data');
-   }
-  </script>
- </head>
- <body onload='doPut();'>
-  <p id="content"></p>
- </body>
-</html>
-)|"));
-    interceptor_->InsertResponse("http://www.example.com/1",
-                                 HttpRedirect(303, "/2"));
-    interceptor_->InsertResponse("http://www.example.com/2",
-                                 {"Pass", "text/plain"});
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(
-        interceptor_->urls_requested(),
-        ElementsAre("http://www.example.com/", "http://www.example.com/1",
-                    "http://www.example.com/2"));
-    EXPECT_THAT(interceptor_->methods_requested(),
-                ElementsAre("GET", "PUT", "GET"));
-    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")),
-                NodeValue("Pass"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(Redirect303PutGet);
-
-class RedirectBaseUrl : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://foo.com/",
-                                 HttpRedirect(302, "http://bar.com/"));
-    interceptor_->InsertResponse("http://bar.com/",
-                                 HttpOk("<img src=\"pass\">"));
-    return GURL("http://foo.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(interceptor_->urls_requested(),
-                ElementsAre("http://foo.com/", "http://bar.com/",
-                            "http://bar.com/pass"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(RedirectBaseUrl);
-
-class RedirectNonAsciiUrl : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    // "中文" is 0xE4 0xB8 0xAD, 0xE6 0x96 0x87
-    interceptor_->InsertResponse(
-        "http://www.example.com/",
-        HttpRedirect(302, "http://www.example.com/中文"));
-    interceptor_->InsertResponse(
-        "http://www.example.com/%E4%B8%AD%E6%96%87",
-        HttpRedirect(303, "http://www.example.com/pass#中文"));
-    interceptor_->InsertResponse(
-        "http://www.example.com/pass#%E4%B8%AD%E6%96%87",
-        HttpOk("<p>Pass</p>"));
-    interceptor_->InsertResponse(
-        "http://www.example.com/%C3%A4%C2%B8%C2%AD%C3%A6%C2%96%C2%87",
-        {"HTTP/1.1 500 Bad Response\r\nContent-Type: text/html\r\n\r\nFail"});
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(interceptor_->urls_requested(),
-                ElementsAre("http://www.example.com/",
-                            "http://www.example.com/%E4%B8%AD%E6%96%87",
-                            "http://www.example.com/pass#%E4%B8%AD%E6%96%87"));
-    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")),
-                NodeValue("Pass"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(RedirectNonAsciiUrl);
-
-class RedirectEmptyUrl : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse(
-        "http://www.example.com/",
-        {"HTTP/1.1 302 Found\r\nLocation: \r\nContent-Type: "
-         "text/html\r\n\r\n<!DOCTYPE html><p>Pass</p>"});
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(interceptor_->urls_requested(),
-                ElementsAre("http://www.example.com/"));
-    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")),
-                NodeValue("Pass"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(RedirectEmptyUrl);
-
-class RedirectInvalidUrl : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse(
-        "http://www.example.com/",
-        {"HTTP/1.1 302 Found\r\nLocation: http://\r\n\r\n"
-         "<!DOCTYPE html><p>Pass</p>"});
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(interceptor_->urls_requested(),
-                ElementsAre("http://www.example.com/"));
-  }
-};
-// TODO(crbug.com/861548): re-implement as DevTools protocol test.
-DISABLED_HEADLESS_RENDER_BROWSERTEST(RedirectInvalidUrl);
-
-class RedirectKeepsFragment : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/#foo",
-                                 HttpRedirect(302, "/1"));
-    interceptor_->InsertResponse("http://www.example.com/1#foo",
-                                 HttpRedirect(302, "/2"));
-    interceptor_->InsertResponse("http://www.example.com/2#foo", HttpOk(R"|(
-<body>
- <p id="content"></p>
- <script>
-  document.getElementById('content').textContent = window.location.href;
- </script>
-</body>
-)|"));
-    return GURL("http://www.example.com/#foo");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(interceptor_->urls_requested(),
-                ElementsAre("http://www.example.com/#foo",
-                            "http://www.example.com/1#foo",
-                            "http://www.example.com/2#foo"));
-    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")),
-                NodeValue("http://www.example.com/2#foo"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(RedirectKeepsFragment);
-
-class RedirectReplacesFragment : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/#foo",
-                                 HttpRedirect(302, "/1#bar"));
-    interceptor_->InsertResponse("http://www.example.com/1#bar",
-                                 HttpRedirect(302, "/2"));
-    interceptor_->InsertResponse("http://www.example.com/2#bar", HttpOk(R"|(
-<body>
- <p id="content"></p>
- <script>
-  document.getElementById('content').textContent = window.location.href;
- </script>
-</body>
-)|"));
-    return GURL("http://www.example.com/#foo");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(interceptor_->urls_requested(),
-                ElementsAre("http://www.example.com/#foo",
-                            "http://www.example.com/1#bar",
-                            "http://www.example.com/2#bar"));
-    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")),
-                NodeValue("http://www.example.com/2#bar"));
-  }
-};
-// TODO(crbug.com/861548): re-implement as DevTools protocol test.
-DISABLED_HEADLESS_RENDER_BROWSERTEST(RedirectReplacesFragment);
-
-class RedirectNewFragment : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/",
-                                 HttpRedirect(302, "/1#foo"));
-    interceptor_->InsertResponse("http://www.example.com/1#foo",
-                                 HttpRedirect(302, "/2"));
-    interceptor_->InsertResponse("http://www.example.com/2#foo", HttpOk(R"|(
-<body>
- <p id="content"></p>
- <script>
-  document.getElementById('content').textContent = window.location.href;
- </script>
-</body>
-)|"));
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(
-        interceptor_->urls_requested(),
-        ElementsAre("http://www.example.com/", "http://www.example.com/1#foo",
-                    "http://www.example.com/2#foo"));
-    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")),
-                NodeValue("http://www.example.com/2#foo"));
-  }
-};
-// TODO(https://crbug.com/839747): Re-implement as DevTools protocol test.
-DISABLED_HEADLESS_RENDER_BROWSERTEST(RedirectNewFragment);
-
-class WindowLocationFragments : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/#fragment1",
-                                 HttpOk(R"|(
- <script>
-   if (window.location.hash == '#fragment1') {
-     document.write('<iframe src="iframe#fragment2"></iframe>');
-   }
- </script>)|"));
-    interceptor_->InsertResponse("http://www.example.com/iframe#fragment2",
-                                 HttpOk(R"|(
- <script>
-   if (window.location.hash == '#fragment2') {
-     document.location = 'http://www.example.com/pass';
-   }
- </script>)|"));
-    interceptor_->InsertResponse("http://www.example.com/pass",
-                                 HttpOk("<p>Pass</p>"));
-    return GURL("http://www.example.com/#fragment1");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(interceptor_->urls_requested(),
-                ElementsAre("http://www.example.com/#fragment1",
-                            "http://www.example.com/iframe#fragment2",
-                            "http://www.example.com/pass"));
-    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")),
-                NodeValue("Pass"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(WindowLocationFragments);
-
-class CookieSetFromJs : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/", HttpOk(R"|(
-<html><head><script>
-document.cookie = 'SessionID=123';
-n = document.cookie.indexOf('SessionID');
-if (n < 0) {
-  top.location = '/epicfail';
-}
-</script></head><body>Pass</body></html>)|"));
-    return GURL("http://www.example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(interceptor_->urls_requested(),
-                ElementsAre("http://www.example.com/"));
-    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "BODY")),
-                NodeValue("Pass"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(CookieSetFromJs);
-
-class CookieSetFromJs_NoCookies : public CookieSetFromJs {
- private:
-  void OverrideWebPreferences(WebPreferences* preferences) override {
-    HeadlessRenderTest::OverrideWebPreferences(preferences);
-    preferences->cookie_enabled = false;
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(interceptor_->urls_requested(),
-                ElementsAre("http://www.example.com/",
-                            "http://www.example.com/epicfail"));
-  }
-};
-
-// Flaky on Linux. https://crbug.com/839747
-#if defined(OS_LINUX)
-DISABLED_HEADLESS_RENDER_BROWSERTEST(CookieSetFromJs_NoCookies);
-#else
-HEADLESS_RENDER_BROWSERTEST(CookieSetFromJs_NoCookies);
-#endif
-
-class CookieUpdatedFromJs : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    client->GetNetwork()->SetCookie(network::SetCookieParams::Builder()
-                                        .SetUrl("http://www.example.com/")
-                                        .SetName("foo")
-                                        .SetValue("bar")
-                                        .Build());
-    interceptor_->InsertResponse("http://www.example.com/", HttpOk(R"|(
-<html><head><script>
-var x = document.cookie;
-document.cookie = x + 'baz';
-</script></head><body>Pass</body></html>)|"));
-    return GURL("http://www.example.com/");
-  }
-
-  void OnPageRenderCompleted() override {
-    devtools_client_->GetNetwork()->GetCookies(
-        network::GetCookiesParams::Builder()
-            .SetUrls({"http://www.example.com/"})
-            .Build(),
-        base::BindOnce(&CookieUpdatedFromJs::OnGetCookies,
-                       base::Unretained(this)));
-  }
-
-  void OnGetCookies(std::unique_ptr<network::GetCookiesResult> result) {
-    const auto& cookies = *result->GetCookies();
-    EXPECT_THAT(cookies, ElementsAre(CookieValue("barbaz")));
-    HeadlessRenderTest::OnPageRenderCompleted();
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "BODY")),
-                NodeValue("Pass"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(CookieUpdatedFromJs);
-
-class InCrossOriginObject : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://foo.com/", HttpOk(R"|(
- <html><body>
-  <iframe id='myframe' src='http://bar.com/'></iframe>
-   <script>
-    window.onload = function() {
-      try {
-        var a = 0 in document.getElementById('myframe').contentWindow;
-      } catch (e) {
-        console.log(e.message);
-      }
-    };
- </script><p>Pass</p></body></html>)|"));
-    interceptor_->InsertResponse("http://bar.com/",
-                                 HttpOk(R"|(<html></html>)|"));
-    return GURL("http://foo.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(NextNode(dom_snapshot, FindTag(dom_snapshot, "P")),
-                NodeValue("Pass"));
-    EXPECT_THAT(console_log_,
-                ElementsAre(StartsWith("L Blocked a frame with origin "
-                                       "\"http://foo.com\" from accessing")));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(InCrossOriginObject);
-
-class ContentSecurityPolicy : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    // Only first 3 scripts of 4 on the page are whitelisted for execution.
-    // Therefore only 3 lines in the log are expected.
-    interceptor_->InsertResponse(
-        "http://example.com/",
-        {"HTTP/1.1 200 OK\r\n"
-         "Content-Type: text/html\r\n"
-         "Content-Security-Policy: script-src"
-         " 'sha256-INSsCHXoo4K3+jDRF8FSvl13GP22I9vcqcJjkq35Y20='"
-         " 'sha384-77lSn5Q6V979pJ8W2TXc6Lrj98LughR0ofkFwa+"
-         "qOEtlcofEdLPkOPtpJF8QQMev'"
-         " 'sha512-"
-         "2cS3KZwfnxFo6lvBvAl113f5N3QCRgtRJBbtFaQHKOhk36sdYYKFvhCqGTvbN7pBKUfsj"
-         "fCQgFF4MSbCQuvT8A=='\r\n\r\n"
-         "<!DOCTYPE html>\n"
-         "<script>console.log('pass256');</script>\n"
-         "<script>console.log('pass384');</script>\n"
-         "<script>console.log('pass512');</script>\n"
-         "<script>console.log('fail');</script>"});
-    // For example, regenerate sha256 hash with:
-    // echo -n "console.log('pass256');" \
-    //   | openssl sha256 -binary \
-    //   | openssl base64
-    return GURL("http://example.com/");
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    EXPECT_THAT(console_log_,
-                ElementsAre("L pass256", "L pass384", "L pass512"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(ContentSecurityPolicy);
-
-class FrameLoadEvents : public HeadlessRenderTest {
- private:
-  std::map<std::string, std::string> frame_navigated_;
-  std::map<std::string, std::string> frame_scheduled_;
-
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://example.com/",
-                                 HttpRedirect(302, "http://example.com/1"));
-
-    interceptor_->InsertResponse("http://example.com/1", HttpOk(R"|(
-<html><frameset>
- <frame src="http://example.com/frameA/" id="frameA">
- <frame src="http://example.com/frameB/" id="frameB">
-</frameset></html>
-)|"));
-
-    interceptor_->InsertResponse("http://example.com/frameA/", HttpOk(R"|(
-<html><head><script>
- document.location="http://example.com/frameA/1"
-</script></head></html>
-)|"));
-
-    interceptor_->InsertResponse("http://example.com/frameB/", HttpOk(R"|(
-<html><head><script>
- document.location="http://example.com/frameB/1"
-</script></head></html>
-)|"));
-
-    interceptor_->InsertResponse("http://example.com/frameA/1",
-                                 HttpOk("<html><body>FRAME A 1</body></html>"));
-
-    interceptor_->InsertResponse("http://example.com/frameB/1", HttpOk(R"|(
-<html><body>FRAME B 1
- <iframe src="http://example.com/frameB/1/iframe/" id="iframe"></iframe>
-</body></html>
-)|"));
-
-    interceptor_->InsertResponse("http://example.com/frameB/1/iframe/",
-                                 HttpOk(R"|(
-<html><head><script>
- document.location="http://example.com/frameB/1/iframe/1"
-</script></head></html>
-)|"));
-
-    interceptor_->InsertResponse("http://example.com/frameB/1/iframe/1",
-                                 HttpOk("<html><body>IFRAME 1</body><html>"));
-
-    return GURL("http://example.com/");
-  }
-
-  void OnFrameNavigated(const page::FrameNavigatedParams& params) override {
-    frame_navigated_.insert(std::make_pair(params.GetFrame()->GetId(),
-                                           params.GetFrame()->GetUrl()));
-    HeadlessRenderTest::OnFrameNavigated(params);
-  }
-
-  void OnFrameScheduledNavigation(
-      const page::FrameScheduledNavigationParams& params) override {
-    frame_scheduled_.insert(
-        std::make_pair(params.GetFrameId(), params.GetUrl()));
-    HeadlessRenderTest::OnFrameScheduledNavigation(params);
-  }
-
-  void VerifyDom(GetSnapshotResult* dom_snapshot) override {
-    std::vector<std::string> urls;
-    for (const auto& kv : frame_navigated_) {
-      urls.push_back(kv.second);
-    }
-    EXPECT_THAT(urls, UnorderedElementsAre(
-                          "http://example.com/1", "http://example.com/frameA/",
-                          "http://example.com/frameB/",
-                          "http://example.com/frameB/1/iframe/"));
-    urls.clear();
-    for (const auto& kv : frame_scheduled_) {
-      urls.push_back(kv.second);
-    }
-    EXPECT_THAT(urls,
-                UnorderedElementsAre("http://example.com/frameA/1",
-                                     "http://example.com/frameB/1",
-                                     "http://example.com/frameB/1/iframe/1"));
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(FrameLoadEvents);
-
-class CustomFont : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/", HttpOk(R"|(
-<html>
-  <head>
-    <style>
-      @font-face {
-        font-family: testfont;
-        src: url("font.ttf");
-      }
-      span.test {
-        font-family: testfont;
-        font-size: 200px;
-      }
-    </style>
-  </head>
-  <body>
-    <span class="test">Hello</span>
-  </body>
-</html>
-)|"));
-    interceptor_->InsertResponse(
-        "http://www.example.com/font.ttf",
-        ResponseFromFile("font.ttf", kApplicationOctetStream));
-    return GURL("http://www.example.com/");
-  }
-
-  base::Optional<ScreenshotOptions> GetScreenshotOptions() override {
-    return ScreenshotOptions("custom_font.png", 0, 0, 500, 250, 1);
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(CustomFont);
-
-// Ensures that "filter: url(...)" does not get into an infinite style update
-// loop.
-class CssUrlFilter : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    // The image from circle.svg will be drawn with the blur from blur.svg.
-    interceptor_->InsertResponse("http://www.example.com/", HttpOk(R"|(
-<!DOCTYPE html>
-<style>
-body { margin: 0; }
-img {
-  -webkit-filter: url(blur.svg#blur);
-  filter: url(blur.svg#blur);
-}
-</style>
-<img src="circle.svg">
-)|"));
-
-    // Just a normal image.
-    interceptor_->InsertResponse("http://www.example.com/circle.svg",
-                                 HttpOk(R"|(
-<svg width="100" height="100" version="1.1" xmlns="http://www.w3.org/2000/svg"
-     xmlns:xlink="http://www.w3.org/1999/xlink">
-<circle cx="50" cy="50" r="50" fill="green" />
-</svg>
-)|",
-                                        kImageSvgXml));
-
-    // A blur filter stored inside an svg file.
-    interceptor_->InsertResponse("http://www.example.com/blur.svg#blur",
-                                 HttpOk(R"|(
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
-     xmlns:xlink="http://www.w3.org/1999/xlink">
-  <filter id="blur">
-    <feGaussianBlur in="SourceGraphic" stdDeviation="5"/>
-  </filter>
-</svg>
-)|",
-                                        kImageSvgXml));
-
-    return GURL("http://www.example.com/");
-  }
-
-  base::Optional<ScreenshotOptions> GetScreenshotOptions() override {
-    return ScreenshotOptions("css_url_filter.png", 0, 0, 100, 100, 1);
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(CssUrlFilter);
-
-// Ensures that a number of SVGs features render correctly.
-class SvgExamples : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse(
-        "http://www.example.com/",
-        ResponseFromFile("svg_examples.svg", kImageSvgXml));
-    interceptor_->InsertResponse(
-        "http://www.example.com/svg_example_image.png",
-        ResponseFromFile("svg_example_image.png", kImagePng));
-
-    return GURL("http://www.example.com/");
-  }
-
-  base::Optional<ScreenshotOptions> GetScreenshotOptions() override {
-    return ScreenshotOptions("svg_examples.png", 0, 0, 400, 600, 1);
-  }
-};
-#if defined(OS_LINUX) && defined(ARCH_CPU_X86) && !defined(NDEBUG)
-// https://crbug.com/859325
-DISABLED_HEADLESS_RENDER_BROWSERTEST(SvgExamples);
-#else
-HEADLESS_RENDER_BROWSERTEST(SvgExamples);
-#endif
-
-// Ensures that basic <canvas> painting is supported.
-class Canvas : public HeadlessRenderTest {
- private:
-  GURL GetPageUrl(HeadlessDevToolsClient* client) override {
-    interceptor_->InsertResponse("http://www.example.com/", HttpOk(R"|(
-<html>
-  <body>
-    <canvas id="test_canvas" width="200" height="200"
-            style="position:absolute;left:0px;top:0px">
-      Oops!  Canvas not supported!
-    </canvas>
-    <script>
-      var context = document.getElementById("test_canvas").
-                    getContext("2d");
-      context.fillStyle = "rgb(255,0,0)";
-      context.fillRect(30, 30, 50, 50);
-    </script>
-  </body>
-</html>
-)|"));
-
-    return GURL("http://www.example.com/");
-  }
-
-  base::Optional<ScreenshotOptions> GetScreenshotOptions() override {
-    return ScreenshotOptions("canvas.png", 0, 0, 200, 200, 1);
-  }
-};
-HEADLESS_RENDER_BROWSERTEST(Canvas);
-
-}  // namespace headless
diff --git a/headless/test/headless_render_test.cc b/headless/test/headless_render_test.cc
deleted file mode 100644
index 171f6f1b..0000000
--- a/headless/test/headless_render_test.cc
+++ /dev/null
@@ -1,514 +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 "headless/test/headless_render_test.h"
-
-#include "base/base_paths.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/path_service.h"
-#include "base/threading/thread_restrictions.h"
-#include "cc/base/switches.h"
-#include "components/viz/common/features.h"
-#include "components/viz/common/switches.h"
-#include "content/public/common/content_switches.h"
-#include "headless/public/devtools/domains/dom_snapshot.h"
-#include "headless/public/headless_devtools_client.h"
-#include "headless/public/util/compositor_controller.h"
-#include "headless/public/util/virtual_time_controller.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/codec/png_codec.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/skia_util.h"
-
-namespace headless {
-
-namespace {
-
-static constexpr int kAnimationIntervalMs = 100;
-static constexpr bool kUpdateDisplayForAnimations = false;
-static const char kUpdateGoldens[] = "update-goldens";
-
-void SetVirtualTimePolicyDoneCallback(
-    base::RunLoop* run_loop,
-    std::unique_ptr<emulation::SetVirtualTimePolicyResult>) {
-  run_loop->Quit();
-}
-
-bool DecodePNG(const std::string& data, SkBitmap* bitmap) {
-  return gfx::PNGCodec::Decode(
-      reinterpret_cast<unsigned const char*>(data.data()), data.size(), bitmap);
-}
-
-bool ColorsMatchWithinLimit(SkColor color1, SkColor color2, int error_limit) {
-  auto a_diff = static_cast<int>(SkColorGetA(color1)) -
-                static_cast<int>(SkColorGetA(color2));
-  auto r_diff = static_cast<int>(SkColorGetR(color1)) -
-                static_cast<int>(SkColorGetR(color2));
-  auto g_diff = static_cast<int>(SkColorGetG(color1)) -
-                static_cast<int>(SkColorGetG(color2));
-  auto b_diff = static_cast<int>(SkColorGetB(color1)) -
-                static_cast<int>(SkColorGetB(color2));
-  return a_diff * a_diff + r_diff * r_diff + g_diff * g_diff +
-             b_diff * b_diff <=
-         error_limit * error_limit;
-}
-
-bool MatchesBitmap(const SkBitmap& expected_bmp,
-                   const SkBitmap& actual_bmp,
-                   int error_limit) {
-  // Number of pixels with an error
-  int error_pixels_count = 0;
-  gfx::Rect error_bounding_rect = gfx::Rect();
-
-  // Check that bitmaps have identical dimensions.
-  EXPECT_EQ(expected_bmp.width(), actual_bmp.width());
-  EXPECT_EQ(expected_bmp.height(), actual_bmp.height());
-  if (expected_bmp.width() != actual_bmp.width() ||
-      expected_bmp.height() != actual_bmp.height()) {
-    LOG(ERROR) << "To update goldens, use --update-goldens.";
-    return false;
-  }
-
-  for (int y = 0; y < actual_bmp.height(); ++y) {
-    for (int x = 0; x < actual_bmp.width(); ++x) {
-      SkColor actual_color = actual_bmp.getColor(x, y);
-      SkColor expected_color = expected_bmp.getColor(x, y);
-      if (!ColorsMatchWithinLimit(actual_color, expected_color, error_limit)) {
-        if (error_pixels_count < 10) {
-          LOG(ERROR) << "Pixel (" << x << "," << y << "): expected " << std::hex
-                     << expected_color << " actual " << actual_color;
-        }
-        error_pixels_count++;
-        error_bounding_rect.Union(gfx::Rect(x, y, 1, 1));
-      }
-    }
-  }
-
-  if (error_pixels_count != 0) {
-    LOG(ERROR) << "Number of pixel with an error: " << error_pixels_count;
-    LOG(ERROR) << "Error Bounding Box : " << error_bounding_rect.ToString();
-    LOG(ERROR) << "To update goldens, use --update-goldens.";
-    return false;
-  }
-
-  return true;
-}
-
-bool WriteStringToFile(const base::FilePath& file_path,
-                       const std::string& content) {
-  int result = base::WriteFile(file_path, content.data(),
-                               static_cast<int>(content.size()));
-  return content.size() == static_cast<size_t>(result);
-}
-
-bool ScreenshotMatchesGolden(const std::string& screenshot_data,
-                             const std::string& golden_file_name) {
-  static const base::FilePath kGoldenDirectory(
-      FILE_PATH_LITERAL("headless/test/data/golden"));
-
-  SkBitmap actual_bitmap;
-  EXPECT_TRUE(DecodePNG(screenshot_data, &actual_bitmap));
-  if (actual_bitmap.empty())
-    return false;
-
-  base::ScopedAllowBlockingForTesting allow_blocking;
-
-  base::FilePath src_dir;
-  CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &src_dir));
-  base::FilePath golden_path =
-      src_dir.Append(kGoldenDirectory).Append(golden_file_name);
-
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(kUpdateGoldens)) {
-    LOG(INFO) << "Updating golden file at " << golden_path;
-    CHECK(WriteStringToFile(golden_path, screenshot_data));
-  }
-
-  std::string golden_data;
-  CHECK(base::ReadFileToString(golden_path, &golden_data));
-
-  SkBitmap expected_bitmap;
-  EXPECT_TRUE(DecodePNG(golden_data, &expected_bitmap));
-  if (expected_bitmap.empty())
-    return false;
-
-  return MatchesBitmap(expected_bitmap, actual_bitmap, 5);
-}
-
-}  // namespace
-
-HeadlessRenderTest::HeadlessRenderTest() : weak_ptr_factory_(this) {}
-
-HeadlessRenderTest::~HeadlessRenderTest() = default;
-
-void HeadlessRenderTest::PostRunAsynchronousTest() {
-  // Make sure the test did complete.
-  EXPECT_EQ(FINISHED, state_) << "The test did not finish.";
-}
-
-class HeadlessRenderTest::AdditionalVirtualTimeBudget
-    : public VirtualTimeController::RepeatingTask,
-      public VirtualTimeController::Observer {
- public:
-  AdditionalVirtualTimeBudget(VirtualTimeController* virtual_time_controller,
-                              HeadlessRenderTest* test,
-                              base::RunLoop* run_loop,
-                              int budget_ms)
-      : RepeatingTask(StartPolicy::WAIT_FOR_NAVIGATION, 0),
-        virtual_time_controller_(virtual_time_controller),
-        test_(test),
-        run_loop_(run_loop) {
-    virtual_time_controller_->ScheduleRepeatingTask(
-        this, base::TimeDelta::FromMilliseconds(budget_ms));
-    virtual_time_controller_->AddObserver(this);
-    virtual_time_controller_->StartVirtualTime();
-  }
-
-  ~AdditionalVirtualTimeBudget() override {
-    virtual_time_controller_->RemoveObserver(this);
-    virtual_time_controller_->CancelRepeatingTask(this);
-  }
-
-  // headless::VirtualTimeController::RepeatingTask implementation:
-  void IntervalElapsed(
-      base::TimeDelta virtual_time,
-      base::OnceCallback<void(ContinuePolicy)> continue_callback) override {
-    std::move(continue_callback).Run(ContinuePolicy::NOT_REQUIRED);
-  }
-
-  // headless::VirtualTimeController::Observer:
-  void VirtualTimeStarted(base::TimeDelta virtual_time_offset) override {
-    run_loop_->Quit();
-  }
-
-  void VirtualTimeStopped(base::TimeDelta virtual_time_offset) override {
-    test_->HandleVirtualTimeExhausted();
-    delete this;
-  }
-
- private:
-  headless::VirtualTimeController* const virtual_time_controller_;
-  HeadlessRenderTest* test_;
-  base::RunLoop* run_loop_;
-};
-
-void HeadlessRenderTest::RunDevTooledTest() {
-  virtual_time_controller_ =
-      std::make_unique<VirtualTimeController>(devtools_client_.get());
-
-  SetDeviceMetricsOverride(headless::page::Viewport::Builder()
-                               .SetX(0)
-                               .SetY(0)
-                               .SetWidth(1)
-                               .SetHeight(1)
-                               .SetScale(1)
-                               .Build());
-
-  compositor_controller_ = std::make_unique<CompositorController>(
-      browser()->BrowserMainThread(), devtools_client_.get(),
-      virtual_time_controller_.get(),
-      base::TimeDelta::FromMilliseconds(kAnimationIntervalMs),
-      kUpdateDisplayForAnimations);
-
-  devtools_client_->GetPage()->GetExperimental()->AddObserver(this);
-  devtools_client_->GetPage()->Enable(Sync());
-  devtools_client_->GetRuntime()->GetExperimental()->AddObserver(this);
-  devtools_client_->GetRuntime()->Enable(Sync());
-
-  GURL url = GetPageUrl(devtools_client_.get());
-
-  // Pause virtual time until we actually start loading content.
-  {
-    base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
-    devtools_client_->GetEmulation()->GetExperimental()->SetVirtualTimePolicy(
-        emulation::SetVirtualTimePolicyParams::Builder()
-            .SetPolicy(emulation::VirtualTimePolicy::PAUSE)
-            .Build());
-    devtools_client_->GetEmulation()->GetExperimental()->SetVirtualTimePolicy(
-        emulation::SetVirtualTimePolicyParams::Builder()
-            .SetPolicy(
-                emulation::VirtualTimePolicy::PAUSE_IF_NETWORK_FETCHES_PENDING)
-            .SetBudget(4001)
-            .SetWaitForNavigation(true)
-            .Build(),
-        base::BindOnce(&SetVirtualTimePolicyDoneCallback, &run_loop));
-
-    run_loop.Run();
-  }
-
-  {
-    base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
-    // Note AdditionalVirtualTimeBudget will self delete.
-    new AdditionalVirtualTimeBudget(virtual_time_controller_.get(), this,
-                                    &run_loop, 5000);
-    run_loop.Run();
-  }
-
-  state_ = STARTING;
-  devtools_client_->GetPage()->Navigate(url.spec());
-  browser()->BrowserMainThread()->PostDelayedTask(
-      FROM_HERE,
-      base::BindOnce(&HeadlessRenderTest::HandleTimeout,
-                     weak_ptr_factory_.GetWeakPtr()),
-      base::TimeDelta::FromSeconds(10));
-
-  // The caller will loop until FinishAsynchronousTest() is called either
-  // from OnGetDomSnapshotDone() or from HandleTimeout().
-}
-
-void HeadlessRenderTest::SetDeviceMetricsOverride(
-    std::unique_ptr<headless::page::Viewport> viewport) {
-  gfx::Size size = GetEmulatedWindowSize();
-  devtools_client_->GetEmulation()->GetExperimental()->SetDeviceMetricsOverride(
-      headless::emulation::SetDeviceMetricsOverrideParams::Builder()
-          .SetDeviceScaleFactor(0)
-          .SetMobile(false)
-          .SetWidth(size.width())
-          .SetHeight(size.height())
-          .SetScreenWidth(size.width())
-          .SetScreenHeight(size.height())
-          .SetViewport(std::move(viewport))
-          .Build(),
-      Sync());
-}
-
-void HeadlessRenderTest::OnTimeout() {
-  ADD_FAILURE() << "Rendering timed out!";
-}
-
-void HeadlessRenderTest::SetUpCommandLine(base::CommandLine* command_line) {
-  HeadlessAsyncDevTooledBrowserTest::SetUpCommandLine(command_line);
-  // See bit.ly/headless-rendering for why we use these flags.
-  command_line->AppendSwitch(switches::kRunAllCompositorStagesBeforeDraw);
-  command_line->AppendSwitch(switches::kDisableNewContentRenderingTimeout);
-  command_line->AppendSwitch(cc::switches::kDisableCheckerImaging);
-  command_line->AppendSwitch(cc::switches::kDisableThreadedAnimation);
-  command_line->AppendSwitch(switches::kDisableImageAnimationResync);
-  command_line->AppendSwitch(switches::kDisableThreadedScrolling);
-
-  scoped_feature_list_.InitAndEnableFeature(
-      features::kEnableSurfaceSynchronization);
-}
-
-void HeadlessRenderTest::SetUp() {
-  EnablePixelOutput();
-  HeadlessAsyncDevTooledBrowserTest::SetUp();
-}
-
-void HeadlessRenderTest::CustomizeHeadlessBrowserContext(
-    HeadlessBrowserContext::Builder& builder) {
-  builder.SetOverrideWebPreferencesCallback(
-      base::Bind(&HeadlessRenderTest::OverrideWebPreferences,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
-bool HeadlessRenderTest::GetEnableBeginFrameControl() {
-  return true;
-}
-
-void HeadlessRenderTest::OverrideWebPreferences(WebPreferences* preferences) {
-  preferences->hide_scrollbars = true;
-  preferences->javascript_enabled = true;
-  preferences->autoplay_policy = content::AutoplayPolicy::kUserGestureRequired;
-}
-
-base::Optional<HeadlessRenderTest::ScreenshotOptions>
-HeadlessRenderTest::GetScreenshotOptions() {
-  return base::nullopt;
-}
-
-gfx::Size HeadlessRenderTest::GetEmulatedWindowSize() {
-  return gfx::Size(800, 600);
-}
-
-void HeadlessRenderTest::OnLoadEventFired(const page::LoadEventFiredParams&) {
-  CHECK_NE(INIT, state_);
-  if (state_ == LOADING || state_ == STARTING) {
-    state_ = RENDERING;
-  }
-}
-
-void HeadlessRenderTest::OnFrameStartedLoading(
-    const page::FrameStartedLoadingParams& params) {
-  CHECK_NE(INIT, state_);
-  if (state_ == STARTING) {
-    state_ = LOADING;
-    main_frame_ = params.GetFrameId();
-  }
-}
-
-void HeadlessRenderTest::OnFrameScheduledNavigation(
-    const page::FrameScheduledNavigationParams& params) {
-  scheduled_navigations_[params.GetFrameId()].emplace_back(
-      Navigation{params.GetUrl(), params.GetReason()});
-}
-
-void HeadlessRenderTest::OnFrameNavigated(
-    const page::FrameNavigatedParams& params) {
-  frames_[params.GetFrame()->GetId()].push_back(params.GetFrame()->Clone());
-}
-
-void HeadlessRenderTest::OnConsoleAPICalled(
-    const runtime::ConsoleAPICalledParams& params) {
-  std::stringstream str;
-  switch (params.GetType()) {
-    case runtime::ConsoleAPICalledType::WARNING:
-      str << "W";
-      break;
-    case runtime::ConsoleAPICalledType::ASSERT:
-    case runtime::ConsoleAPICalledType::ERR:
-      str << "E";
-      break;
-    case runtime::ConsoleAPICalledType::DEBUG:
-      str << "D";
-      break;
-    case runtime::ConsoleAPICalledType::INFO:
-      str << "I";
-      break;
-    default:
-      str << "L";
-      break;
-  }
-  const auto& args = *params.GetArgs();
-  for (const auto& arg : args) {
-    str << " ";
-    if (arg->HasDescription()) {
-      str << arg->GetDescription();
-    } else if (arg->GetType() == runtime::RemoteObjectType::UNDEFINED) {
-      str << "undefined";
-    } else if (arg->HasValue()) {
-      const base::Value* v = arg->GetValue();
-      switch (v->type()) {
-        case base::Value::Type::NONE:
-          str << "null";
-          break;
-        case base::Value::Type::BOOLEAN:
-          str << v->GetBool();
-          break;
-        case base::Value::Type::INTEGER:
-          str << v->GetInt();
-          break;
-        case base::Value::Type::DOUBLE:
-          str << v->GetDouble();
-          break;
-        case base::Value::Type::STRING:
-          str << v->GetString();
-          break;
-        default:
-          DCHECK(false);
-          break;
-      }
-    } else {
-      DCHECK(false);
-    }
-  }
-  console_log_.push_back(str.str());
-}
-
-void HeadlessRenderTest::OnExceptionThrown(
-    const runtime::ExceptionThrownParams& params) {
-  const runtime::ExceptionDetails* details = params.GetExceptionDetails();
-  js_exceptions_.push_back(details->GetText() + " " +
-                           details->GetException()->GetDescription());
-}
-
-void HeadlessRenderTest::VerifyDom(
-    dom_snapshot::GetSnapshotResult* dom_snapshot) {}
-
-void HeadlessRenderTest::OnPageRenderCompleted() {
-  CHECK_GE(state_, LOADING);
-  if (state_ >= DONE)
-    return;
-  state_ = DONE;
-
-  devtools_client_->GetDOMSnapshot()->GetExperimental()->GetSnapshot(
-      dom_snapshot::GetSnapshotParams::Builder()
-          .SetComputedStyleWhitelist(std::vector<std::string>())
-          .Build(),
-      base::BindOnce(&HeadlessRenderTest::OnGetDomSnapshotDone,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void HeadlessRenderTest::HandleVirtualTimeExhausted() {
-  if (state_ < DONE) {
-    OnPageRenderCompleted();
-  }
-}
-
-void HeadlessRenderTest::OnGetDomSnapshotDone(
-    std::unique_ptr<dom_snapshot::GetSnapshotResult> result) {
-  CHECK_EQ(DONE, state_);
-  VerifyDom(result.get());
-
-  base::Optional<ScreenshotOptions> screenshot_options = GetScreenshotOptions();
-  if (screenshot_options) {
-    state_ = SCREENSHOT;
-    CaptureScreenshot(*screenshot_options);
-    return;
-  }
-  RenderComplete();
-}
-
-void HeadlessRenderTest::CaptureScreenshot(const ScreenshotOptions& options) {
-  // Set up emulation according to options.
-  auto clip = headless::page::Viewport::Builder()
-                  .SetX(options.x)
-                  .SetY(options.y)
-                  .SetWidth(options.width)
-                  .SetHeight(options.height)
-                  .SetScale(options.scale)
-                  .Build();
-
-  SetDeviceMetricsOverride(std::move(clip));
-
-  compositor_controller_->CaptureScreenshot(
-      CompositorController::ScreenshotParamsFormat::PNG, 100,
-      base::BindRepeating(&HeadlessRenderTest::ScreenshotCaptured,
-                          base::Unretained(this), options));
-}
-
-void HeadlessRenderTest::ScreenshotCaptured(const ScreenshotOptions& options,
-                                            const std::string& data) {
-  EXPECT_TRUE(ScreenshotMatchesGolden(data, options.golden_file_name));
-  RenderComplete();
-}
-
-void HeadlessRenderTest::RenderComplete() {
-  state_ = FINISHED;
-  CleanUp();
-  FinishAsynchronousTest();
-}
-
-void HeadlessRenderTest::HandleTimeout() {
-  if (state_ != FINISHED) {
-    CleanUp();
-    FinishAsynchronousTest();
-    OnTimeout();
-  }
-}
-
-void HeadlessRenderTest::CleanUp() {
-  devtools_client_->GetRuntime()->Disable(Sync());
-  devtools_client_->GetRuntime()->GetExperimental()->RemoveObserver(this);
-  devtools_client_->GetPage()->Disable(Sync());
-  devtools_client_->GetPage()->GetExperimental()->RemoveObserver(this);
-}
-
-HeadlessRenderTest::ScreenshotOptions::ScreenshotOptions(
-    const std::string& golden_file_name,
-    int x,
-    int y,
-    int width,
-    int height,
-    double scale)
-    : golden_file_name(golden_file_name),
-      x(x),
-      y(y),
-      width(width),
-      height(height),
-      scale(scale) {}
-
-}  // namespace headless
diff --git a/headless/test/headless_render_test.h b/headless/test/headless_render_test.h
deleted file mode 100644
index c9bd2827..0000000
--- a/headless/test/headless_render_test.h
+++ /dev/null
@@ -1,176 +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 HEADLESS_TEST_HEADLESS_RENDER_TEST_H_
-#define HEADLESS_TEST_HEADLESS_RENDER_TEST_H_
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop_current.h"
-#include "base/optional.h"
-#include "base/run_loop.h"
-#include "base/test/scoped_feature_list.h"
-#include "headless/public/devtools/domains/emulation.h"
-#include "headless/public/devtools/domains/page.h"
-#include "headless/public/devtools/domains/runtime.h"
-#include "headless/public/headless_browser.h"
-#include "headless/public/headless_browser_context.h"
-#include "headless/test/headless_browser_test.h"
-#include "ui/gfx/geometry/size.h"
-#include "url/gurl.h"
-
-namespace headless {
-class CompositorController;
-class HeadlessDevToolsClient;
-class VirtualTimeController;
-namespace dom_snapshot {
-class GetSnapshotResult;
-}  // namespace dom_snapshot
-
-// Base class for tests that render a particular page and verify the output.
-class HeadlessRenderTest : public HeadlessAsyncDevTooledBrowserTest,
-                           public page::ExperimentalObserver,
-                           public runtime::ExperimentalObserver {
- public:
-  struct Navigation {
-    std::string url;
-    page::FrameScheduledNavigationReason reason;
-  };
-
-  void RunDevTooledTest() override;
-
- protected:
-  // Automatically waits in destructor until callback is called.
-  class Sync {
-   public:
-    Sync() {}
-    ~Sync() {
-      base::MessageLoopCurrent::ScopedNestableTaskAllower nest_loop;
-      run_loop.Run();
-    }
-    operator base::OnceClosure() { return run_loop.QuitClosure(); }
-
-   private:
-    base::RunLoop run_loop;
-    DISALLOW_COPY_AND_ASSIGN(Sync);
-  };
-
-  struct ScreenshotOptions {
-    ScreenshotOptions(const std::string& golden_file_name,
-                      int x,
-                      int y,
-                      int width,
-                      int height,
-                      double scale);
-
-    std::string golden_file_name;
-    int x;
-    int y;
-    int width;
-    int height;
-    double scale;
-  };
-
-  HeadlessRenderTest();
-  ~HeadlessRenderTest() override;
-
-  // Marks that the test case reached the final conclusion.
-  void SetTestCompleted() { state_ = FINISHED; }
-
-  // Do necessary preparations and return a URL to render.
-  virtual GURL GetPageUrl(HeadlessDevToolsClient* client) = 0;
-
-  // Check if the DOM snapshot is as expected.
-  virtual void VerifyDom(dom_snapshot::GetSnapshotResult* dom_snapshot);
-
-  // Called when all steps needed to load and present page are done.
-  virtual void OnPageRenderCompleted();
-
-  // Called if page rendering wasn't completed within reasonable time.
-  virtual void OnTimeout();
-
-  // Override to set specific options for requests.
-  virtual void OverrideWebPreferences(WebPreferences* preferences);
-
-  // Determines whether a screenshot will be taken or not. If one is taken,
-  // ScreenshotOptions specifies the area to capture as well as a golden data
-  // file to compare the result to. By default, no screenshot is taken.
-  virtual base::Optional<ScreenshotOptions> GetScreenshotOptions();
-
-  // Returns the emulated width/height of the window. Defaults to 800x600.
-  virtual gfx::Size GetEmulatedWindowSize();
-
-  // Setting up the browsertest.
-  void SetUpCommandLine(base::CommandLine* command_line) override;
-  void SetUp() override;
-  void CustomizeHeadlessBrowserContext(
-      HeadlessBrowserContext::Builder& builder) override;
-  bool GetEnableBeginFrameControl() override;
-  void PostRunAsynchronousTest() override;
-
-  // page::ExperimentalObserver implementation:
-  void OnLoadEventFired(const page::LoadEventFiredParams& params) override;
-  void OnFrameStartedLoading(
-      const page::FrameStartedLoadingParams& params) override;
-  void OnFrameScheduledNavigation(
-      const page::FrameScheduledNavigationParams& params) override;
-  void OnFrameNavigated(const page::FrameNavigatedParams& params) override;
-
-  // runtime::ExperimentalObserver implementation:
-  void OnConsoleAPICalled(
-      const runtime::ConsoleAPICalledParams& params) override;
-  void OnExceptionThrown(const runtime::ExceptionThrownParams& params) override;
-
-  // For each frame, keep track of scheduled navigations.
-  // FYI: It doesn't track every navigations. For instance, it doesn't include
-  // the first navigation. It doesn't include HTTP redirect, but it includes
-  // client-side redirect.
-  std::map<std::string, std::vector<Navigation>> scheduled_navigations_;
-
-  std::map<std::string, std::vector<std::unique_ptr<page::Frame>>> frames_;
-  std::string main_frame_;
-  std::vector<std::string> console_log_;
-  std::vector<std::string> js_exceptions_;
-
- private:
-  class AdditionalVirtualTimeBudget;
-
-  void SetDeviceMetricsOverride(
-      std::unique_ptr<headless::page::Viewport> viewport);
-  void HandleVirtualTimeExhausted();
-  void OnGetDomSnapshotDone(
-      std::unique_ptr<dom_snapshot::GetSnapshotResult> result);
-  void CaptureScreenshot(const ScreenshotOptions& options);
-  void ScreenshotCaptured(const ScreenshotOptions& options,
-                          const std::string& data);
-  void RenderComplete();
-  void HandleTimeout();
-  void CleanUp();
-
-  enum State {
-    INIT,        // Setting up the client, no navigation performed yet.
-    STARTING,    // Navigation request issued but URL not being loaded yet.
-    LOADING,     // URL was requested but resources are not fully loaded yet.
-    RENDERING,   // Main resources were loaded but page is still being rendered.
-    DONE,        // Page considered to be rendered, DOM snapshot is being taken.
-    SCREENSHOT,  // DOM snapshot has completed, screenshot is being taken.
-    FINISHED,    // Test has finished.
-  };
-  State state_ = INIT;
-
-  std::unique_ptr<VirtualTimeController> virtual_time_controller_;
-  std::unique_ptr<CompositorController> compositor_controller_;
-
-  base::test::ScopedFeatureList scoped_feature_list_;
-
-  base::WeakPtrFactory<HeadlessRenderTest> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(HeadlessRenderTest);
-};
-
-}  // namespace headless
-
-#endif  // HEADLESS_TEST_HEADLESS_RENDER_TEST_H_
diff --git a/infra/config/branch/cq.cfg b/infra/config/branch/cq.cfg
index 11d8983..e93a992 100644
--- a/infra/config/branch/cq.cfg
+++ b/infra/config/branch/cq.cfg
@@ -2,7 +2,6 @@
 # documentation of this file format.
 
 version: 1
-cq_name: "chromium"
 cq_status_url: "https://chromium-cq-status.appspot.com"
 git_repo_url: "https://chromium.googlesource.com/chromium/src"
 commit_burst_delay: 60
diff --git a/ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.mm b/ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.mm
index 5ab31b59..37eb84e 100644
--- a/ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.mm
+++ b/ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.mm
@@ -43,10 +43,7 @@
   [super configureCell:cell];
   cell.textLabel.text = self.text;
   cell.switchView.enabled = self.isEnabled;
-
-  // Force disabled cells to be drawn in the "off" state, but do not change the
-  // value of the |on| property.
-  cell.switchView.on = self.isOn && self.isEnabled;
+  cell.switchView.on = self.isOn;
   cell.textLabel.textColor =
       [CollectionViewSwitchCell defaultTextColorForState:cell.switchView.state];
 }
diff --git a/ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item_unittest.mm b/ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item_unittest.mm
index fbdcb4a..67a46e92 100644
--- a/ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item_unittest.mm
+++ b/ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item_unittest.mm
@@ -74,12 +74,11 @@
   EXPECT_FALSE(cell.switchView.isOn);
   EXPECT_NSEQ(disabledColor, cell.textLabel.textColor);
 
-  // Disabled and on.  In this case, the switch should draw in the "off" state,
-  // because it is disabled.
+  // Disabled and on.
   item.on = YES;
   item.enabled = NO;
   [item configureCell:cell];
-  EXPECT_FALSE(cell.switchView.isOn);
+  EXPECT_TRUE(cell.switchView.isOn);
   EXPECT_NSEQ(disabledColor, cell.textLabel.textColor);
 }
 
diff --git a/ios/chrome/browser/ui/settings/autofill_settings_egtest.mm b/ios/chrome/browser/ui/settings/autofill_settings_egtest.mm
index 4b38c61..04d6610 100644
--- a/ios/chrome/browser/ui/settings/autofill_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/autofill_settings_egtest.mm
@@ -269,15 +269,14 @@
       performAction:grey_tap()];
 
   // Check the Autofill, address, and credit card switches are disabled.
-  // Disabled switches are toggled off.
   [[EarlGrey selectElementWithMatcher:chrome_test_util::SettingsSwitchCell(
-                                          @"autofillItem_switch", NO, NO)]
+                                          @"autofillItem_switch", YES, NO)]
       assertWithMatcher:grey_notNil()];
   [[EarlGrey selectElementWithMatcher:chrome_test_util::SettingsSwitchCell(
-                                          @"addressItem_switch", NO, NO)]
+                                          @"addressItem_switch", YES, NO)]
       assertWithMatcher:grey_notNil()];
   [[EarlGrey selectElementWithMatcher:chrome_test_util::SettingsSwitchCell(
-                                          @"cardItem_switch", NO, NO)]
+                                          @"cardItem_switch", YES, NO)]
       assertWithMatcher:grey_notNil()];
 }
 
@@ -372,16 +371,15 @@
         performAction:chrome_test_util::TurnSettingsSwitchOn(!expectedState)];
 
     // Expect Autofill address and credit card switches to be disabled when
-    // Autofill toggle is off and enabled when it is on. Disabled switches are
-    // toggled off.
+    // Autofill toggle is off and enabled when it is on.
     [[EarlGrey selectElementWithMatcher:chrome_test_util::SettingsSwitchCell(
-                                            @"addressItem_switch",
-                                            !expectedState, !expectedState)]
-        assertWithMatcher:grey_notNil()];
-    [[EarlGrey selectElementWithMatcher:chrome_test_util::SettingsSwitchCell(
-                                            @"cardItem_switch", !expectedState,
+                                            @"addressItem_switch", YES,
                                             !expectedState)]
         assertWithMatcher:grey_notNil()];
+    [[EarlGrey
+        selectElementWithMatcher:chrome_test_util::SettingsSwitchCell(
+                                     @"cardItem_switch", YES, !expectedState)]
+        assertWithMatcher:grey_notNil()];
 
     // Expect Autofill addresses and credit cards to remain visible.
     [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(
diff --git a/ios/chrome/browser/ui/settings/cells/settings_switch_item.mm b/ios/chrome/browser/ui/settings/cells/settings_switch_item.mm
index f133fe8..6854e48 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_switch_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/settings_switch_item.mm
@@ -54,10 +54,7 @@
   [super configureCell:cell];
   cell.textLabel.text = self.text;
   cell.switchView.enabled = self.isEnabled;
-
-  // Force disabled cells to be drawn in the "off" state, but do not change the
-  // value of the |on| property.
-  cell.switchView.on = self.isOn && self.isEnabled;
+  cell.switchView.on = self.isOn;
   cell.textLabel.textColor =
       [SettingsSwitchCell defaultTextColorForState:cell.switchView.state];
 
diff --git a/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm b/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
index 21a2232..6ee06da4 100644
--- a/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
@@ -914,10 +914,9 @@
 
   TapEdit();
 
-  // Check that the "Save Passwords" switch is disabled. Disabled switches are
-  // toggled off.
+  // Check that the "Save Passwords" switch is disabled.
   [[EarlGrey selectElementWithMatcher:chrome_test_util::SettingsSwitchCell(
-                                          @"savePasswordsItem_switch", NO, NO)]
+                                          @"savePasswordsItem_switch", YES, NO)]
       assertWithMatcher:grey_notNil()];
 
   [GetInteractionForPasswordEntry(@"example.com, concrete username")
diff --git a/ios/chrome/browser/ui/settings/voicesearch_collection_view_controller.mm b/ios/chrome/browser/ui/settings/voicesearch_collection_view_controller.mm
index 60717e82..1b5acbf 100644
--- a/ios/chrome/browser/ui/settings/voicesearch_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/voicesearch_collection_view_controller.mm
@@ -78,8 +78,9 @@
   SettingsSwitchItem* tts =
       [[SettingsSwitchItem alloc] initWithType:ItemTypeTTSEnabled];
   tts.text = l10n_util::GetNSString(IDS_IOS_VOICE_SEARCH_SETTING_TTS);
-  tts.on = _ttsEnabled.GetValue();
-  tts.enabled = [self currentLanguageSupportsTTS];
+  BOOL enabled = [self currentLanguageSupportsTTS];
+  tts.on = enabled && _ttsEnabled.GetValue();
+  tts.enabled = enabled;
   [model addItem:tts toSectionWithIdentifier:SectionIdentifierTTS];
 
   // Variables used to populate the languages section.
diff --git a/ios/chrome/browser/ui/settings/voicesearch_collection_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/voicesearch_collection_view_controller_unittest.mm
index be545a8..37b870666 100644
--- a/ios/chrome/browser/ui/settings/voicesearch_collection_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/voicesearch_collection_view_controller_unittest.mm
@@ -146,7 +146,7 @@
 
   CreateController();
   SettingsSwitchItem* switchItem = GetCollectionViewItem(0, 0);
-  EXPECT_TRUE(switchItem.isOn);
+  EXPECT_FALSE(switchItem.isOn);
   EXPECT_FALSE(switchItem.isEnabled);
 }
 
diff --git a/ios/net/cookies/cookie_store_ios_persistent.mm b/ios/net/cookies/cookie_store_ios_persistent.mm
index 4fa4a68..9817467 100644
--- a/ios/net/cookies/cookie_store_ios_persistent.mm
+++ b/ios/net/cookies/cookie_store_ios_persistent.mm
@@ -8,6 +8,7 @@
 
 #include <memory>
 
+#include "base/bind.h"
 #include "base/threading/thread_checker.h"
 #import "ios/net/cookies/ns_http_system_cookie_store.h"
 #import "ios/net/cookies/system_cookie_util.h"
@@ -19,6 +20,20 @@
 
 namespace net {
 
+namespace {
+// Add metrics reporting to GetCookieListWithOptionsAsync cookie monster
+// callback.
+void CookieListCallbackWithMetricsLogging(
+    CookieMonster::GetCookieListCallback callback,
+    const CookieList& cookies) {
+  net::ReportGetCookiesForURLResult(SystemCookieStoreType::kCookieMonster,
+                                    !cookies.empty());
+  if (!callback.is_null()) {
+    std::move(callback).Run(cookies);
+  }
+}
+}  // namespace
+
 #pragma mark -
 #pragma mark CookieStoreIOSPersistent
 
@@ -65,9 +80,11 @@
     const net::CookieOptions& options,
     GetCookieListCallback callback) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  cookie_monster()->GetCookieListWithOptionsAsync(url, options,
-                                                  std::move(callback));
+  ReportGetCookiesForURLCall(SystemCookieStoreType::kCookieMonster);
+  cookie_monster()->GetCookieListWithOptionsAsync(
+      url, options,
+      base::BindOnce(&CookieListCallbackWithMetricsLogging,
+                     base::Passed(&callback)));
 }
 
 void CookieStoreIOSPersistent::GetAllCookiesAsync(
diff --git a/ios/net/cookies/ns_http_system_cookie_store.mm b/ios/net/cookies/ns_http_system_cookie_store.mm
index b5c1973..8e5cbc3f09 100644
--- a/ios/net/cookies/ns_http_system_cookie_store.mm
+++ b/ios/net/cookies/ns_http_system_cookie_store.mm
@@ -8,6 +8,7 @@
 #include "base/time/time.h"
 #import "ios/net/cookies/cookie_creation_time_manager.h"
 #import "ios/net/cookies/cookie_store_ios_client.h"
+#import "ios/net/cookies/system_cookie_util.h"
 #import "net/base/mac/url_conversions.h"
 #include "url/gurl.h"
 
@@ -41,14 +42,19 @@
 void NSHTTPSystemCookieStore::GetCookiesForURLAsync(
     const GURL& url,
     SystemCookieCallbackForCookies callback) {
+  ReportGetCookiesForURLCall(SystemCookieStoreType::kNSHTTPSystemCookieStore);
   NSArray* cookies = GetCookiesForURL(url);
+  net::ReportGetCookiesForURLResult(
+      SystemCookieStoreType::kNSHTTPSystemCookieStore, cookies.count != 0);
   RunCookieCallback(base::BindOnce(std::move(callback), cookies));
 }
+
 void NSHTTPSystemCookieStore::GetAllCookiesAsync(
     SystemCookieCallbackForCookies callback) {
   NSArray* cookies = GetAllCookies();
   RunCookieCallback(base::BindOnce(std::move(callback), cookies));
 }
+
 void NSHTTPSystemCookieStore::DeleteCookieAsync(NSHTTPCookie* cookie,
                                                 SystemCookieCallback callback) {
   DeleteCookie(cookie);
diff --git a/ios/net/cookies/system_cookie_util.h b/ios/net/cookies/system_cookie_util.h
index 3907885..5759956 100644
--- a/ios/net/cookies/system_cookie_util.h
+++ b/ios/net/cookies/system_cookie_util.h
@@ -31,6 +31,42 @@
   COOKIES_APPLICATION_FOREGROUNDED  // The application has been foregrounded.
 };
 
+// Enum for the IOS.Cookies.GetCookiesForURLCallStoreType UMA histogram to
+// report the type of the backing system cookie store, when GetCookiesForURL
+// method is called.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class SystemCookieStoreType {
+  kWKHTTPSystemCookieStore = 0,
+  kNSHTTPSystemCookieStore = 1,
+  kCookieMonster = 2,
+  kMaxValue = kCookieMonster,
+};
+
+// Enum for the IOS.Cookies.GetCookiesForURLCallResult UMA histogram to report
+// if the call found cookies or no cookies were found on a specific system
+// cookie store type.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class GetCookiesForURLCallResult {
+  kCookiesFoundOnWKHTTPSystemCookieStore = 0,
+  kNoCookiesOnWKHTTPSystemCookieStore = 1,
+  kCookiesFoundOnNSHTTPSystemCookieStore = 2,
+  kNoCookiesOnNSHTTPSystemCookieStore = 3,
+  kCookiesFoundOnCookieMonster = 4,
+  kNoCookiesOnCookieMonster = 5,
+  kMaxValue = kNoCookiesOnCookieMonster,
+};
+
+// Reports metrics to indicate if call to GetCookiesForURL found cookies or no
+// cookies were found on a specific system cookie store type.
+void ReportGetCookiesForURLResult(SystemCookieStoreType store_type,
+                                  bool has_cookies);
+
+// Reports metrics to indicate that GetCookiesForURL was called from cookie
+// store with type |store_type|.
+void ReportGetCookiesForURLCall(SystemCookieStoreType store_type);
+
 // Report metrics if the number of cookies drops unexpectedly.
 void CheckForCookieLoss(size_t cookie_count, CookieEvent event);
 
diff --git a/ios/net/cookies/system_cookie_util.mm b/ios/net/cookies/system_cookie_util.mm
index 945bbdb5..c899b23 100644
--- a/ios/net/cookies/system_cookie_util.mm
+++ b/ios/net/cookies/system_cookie_util.mm
@@ -82,6 +82,41 @@
       net::CookieSameSite::DEFAULT_MODE, net::COOKIE_PRIORITY_DEFAULT);
 }
 
+void ReportGetCookiesForURLResult(SystemCookieStoreType store_type,
+                                  bool has_cookies) {
+  GetCookiesForURLCallResult call_result =
+      GetCookiesForURLCallResult::kCookiesFoundOnWKHTTPSystemCookieStore;
+  switch (store_type) {
+    case SystemCookieStoreType::kWKHTTPSystemCookieStore:
+      call_result =
+          has_cookies
+              ? GetCookiesForURLCallResult::
+                    kCookiesFoundOnWKHTTPSystemCookieStore
+              : GetCookiesForURLCallResult::kNoCookiesOnWKHTTPSystemCookieStore;
+      break;
+    case SystemCookieStoreType::kNSHTTPSystemCookieStore:
+      call_result =
+          has_cookies
+              ? GetCookiesForURLCallResult::
+                    kCookiesFoundOnNSHTTPSystemCookieStore
+              : GetCookiesForURLCallResult::kNoCookiesOnNSHTTPSystemCookieStore;
+
+      break;
+    case SystemCookieStoreType::kCookieMonster:
+      call_result =
+          has_cookies ? GetCookiesForURLCallResult::kCookiesFoundOnCookieMonster
+                      : GetCookiesForURLCallResult::kNoCookiesOnCookieMonster;
+      break;
+  }
+  UMA_HISTOGRAM_ENUMERATION("IOS.Cookies.GetCookiesForURLCallResult",
+                            call_result);
+}
+
+void ReportGetCookiesForURLCall(SystemCookieStoreType store_type) {
+  UMA_HISTOGRAM_ENUMERATION("IOS.Cookies.GetCookiesForURLCallStoreType",
+                            store_type);
+}
+
 // Converts net::CanonicalCookie to NSHTTPCookie.
 NSHTTPCookie* SystemCookieFromCanonicalCookie(
     const net::CanonicalCookie& cookie) {
diff --git a/ios/net/cookies/system_cookie_util_unittest.mm b/ios/net/cookies/system_cookie_util_unittest.mm
index 8e4f2cf..4b29e9bc 100644
--- a/ios/net/cookies/system_cookie_util_unittest.mm
+++ b/ios/net/cookies/system_cookie_util_unittest.mm
@@ -7,6 +7,7 @@
 #import <Foundation/Foundation.h>
 
 #include "base/strings/sys_string_conversions.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/time/time.h"
 #include "net/cookies/cookie_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -27,6 +28,8 @@
 const char kCookiePath[] = "path/";
 const char kCookieValue[] = "value";
 const char kCookieValueInvalidUtf8[] = "\x81r\xe4\xbd\xa0\xe5\xa5\xbd";
+const char kGetCookiesResultHistogram[] =
+    "IOS.Cookies.GetCookiesForURLCallResult";
 
 void CheckSystemCookie(const base::Time& expires, bool secure, bool httponly) {
   // Generate a canonical cookie.
@@ -59,6 +62,14 @@
             system_cookie_expire_date);
 }
 
+void VerifyGetCookiesResultHistogram(
+    const base::HistogramTester& histogram_tester,
+    GetCookiesForURLCallResult expected_value) {
+  histogram_tester.ExpectBucketCount(
+      kGetCookiesResultHistogram,
+      static_cast<base::HistogramBase::Sample>(expected_value), 1);
+}
+
 }  // namespace
 
 using CookieUtil = PlatformTest;
@@ -109,6 +120,38 @@
   EXPECT_TRUE(chrome_cookie.IsSecure());
 }
 
+// Tests that histogram is reported correctly based on the input.
+TEST_F(CookieUtil, ReportGetCookiesForURLResult) {
+  base::HistogramTester histogram_tester;
+  histogram_tester.ExpectTotalCount(kGetCookiesResultHistogram, 0);
+  ReportGetCookiesForURLResult(SystemCookieStoreType::kNSHTTPSystemCookieStore,
+                               /*has_cookies=*/true);
+  VerifyGetCookiesResultHistogram(
+      histogram_tester,
+      GetCookiesForURLCallResult::kCookiesFoundOnNSHTTPSystemCookieStore);
+  histogram_tester.ExpectTotalCount(kGetCookiesResultHistogram, 1);
+
+  ReportGetCookiesForURLResult(SystemCookieStoreType::kNSHTTPSystemCookieStore,
+                               /*has_cookies=*/false);
+  VerifyGetCookiesResultHistogram(
+      histogram_tester,
+      GetCookiesForURLCallResult::kNoCookiesOnNSHTTPSystemCookieStore);
+  histogram_tester.ExpectTotalCount(kGetCookiesResultHistogram, 2);
+
+  ReportGetCookiesForURLResult(SystemCookieStoreType::kCookieMonster,
+                               /*has_cookies=*/false);
+  VerifyGetCookiesResultHistogram(
+      histogram_tester, GetCookiesForURLCallResult::kNoCookiesOnCookieMonster);
+  histogram_tester.ExpectTotalCount(kGetCookiesResultHistogram, 3);
+
+  ReportGetCookiesForURLResult(SystemCookieStoreType::kWKHTTPSystemCookieStore,
+                               /*has_cookies=*/true);
+  VerifyGetCookiesResultHistogram(
+      histogram_tester,
+      GetCookiesForURLCallResult::kCookiesFoundOnWKHTTPSystemCookieStore);
+  histogram_tester.ExpectTotalCount(kGetCookiesResultHistogram, 4);
+}
+
 TEST_F(CookieUtil, SystemCookieFromCanonicalCookie) {
   base::Time expire_date = base::Time::Now() + base::TimeDelta::FromHours(2);
 
diff --git a/ios/web/net/cookies/wk_http_system_cookie_store.mm b/ios/web/net/cookies/wk_http_system_cookie_store.mm
index 618fa953..ac1d734 100644
--- a/ios/web/net/cookies/wk_http_system_cookie_store.mm
+++ b/ios/web/net/cookies/wk_http_system_cookie_store.mm
@@ -64,6 +64,8 @@
     SystemCookieCallbackForCookies callback) {
   // This function shouldn't be called if cookie_store_ is deleted.
   DCHECK(cookie_store_);
+  net::ReportGetCookiesForURLCall(
+      net::SystemCookieStoreType::kWKHTTPSystemCookieStore);
   __block SystemCookieCallbackForCookies shared_callback = std::move(callback);
   base::WeakPtr<net::CookieCreationTimeManager> weak_time_manager =
       creation_time_manager_->GetWeakPtr();
@@ -77,6 +79,9 @@
               [result addObject:cookie];
             }
           }
+          net::ReportGetCookiesForURLResult(
+              net::SystemCookieStoreType::kWKHTTPSystemCookieStore,
+              cookies.count != 0);
           RunSystemCookieCallbackForCookies(std::move(shared_callback),
                                             weak_time_manager, result);
         }];
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc
index 709578f..3ca7160 100644
--- a/media/base/video_frame.cc
+++ b/media/base/video_frame.cc
@@ -215,13 +215,13 @@
   if (format != PIXEL_FORMAT_ARGB && format != PIXEL_FORMAT_XRGB &&
       format != PIXEL_FORMAT_RGB32 && format != PIXEL_FORMAT_UYVY &&
       format != PIXEL_FORMAT_NV12 && format != PIXEL_FORMAT_I420) {
-    LOG(DFATAL) << "Unsupported pixel format: "
+    DLOG(ERROR) << "Unsupported pixel format: "
                 << VideoPixelFormatToString(format);
     return nullptr;
   }
   const StorageType storage = STORAGE_OPAQUE;
   if (!IsValidConfig(format, storage, coded_size, visible_rect, natural_size)) {
-    LOG(DFATAL) << __func__ << " Invalid config."
+    DLOG(ERROR) << __func__ << " Invalid config."
                 << ConfigToString(format, storage, coded_size, visible_rect,
                                   natural_size);
     return nullptr;
@@ -317,7 +317,7 @@
     base::TimeDelta timestamp) {
   const StorageType storage = STORAGE_UNOWNED_MEMORY;
   if (!IsValidConfig(format, storage, coded_size, visible_rect, natural_size)) {
-    LOG(DFATAL) << __func__ << " Invalid config."
+    DLOG(ERROR) << __func__ << " Invalid config."
                 << ConfigToString(format, storage, coded_size, visible_rect,
                                   natural_size);
     return nullptr;
@@ -353,14 +353,14 @@
     base::TimeDelta timestamp) {
   const StorageType storage = STORAGE_UNOWNED_MEMORY;
   if (!IsValidConfig(format, storage, coded_size, visible_rect, natural_size)) {
-    LOG(DFATAL) << __func__ << " Invalid config."
+    DLOG(ERROR) << __func__ << " Invalid config."
                 << ConfigToString(format, storage, coded_size, visible_rect,
                                   natural_size);
     return nullptr;
   }
 
   if (NumPlanes(format) != 4) {
-    LOG(DFATAL) << "Expecting Y, U, V and A planes to be present for the video"
+    DLOG(ERROR) << "Expecting Y, U, V and A planes to be present for the video"
                 << " format.";
     return nullptr;
   }
@@ -390,14 +390,14 @@
     base::TimeDelta timestamp) {
   const StorageType storage = STORAGE_DMABUFS;
   if (!IsValidConfig(format, storage, coded_size, visible_rect, natural_size)) {
-    LOG(DFATAL) << __func__ << " Invalid config."
+    DLOG(ERROR) << __func__ << " Invalid config."
                 << ConfigToString(format, storage, coded_size, visible_rect,
                                   natural_size);
     return nullptr;
   }
 
   if (dmabuf_fds.empty() || dmabuf_fds.size() > NumPlanes(format)) {
-    LOG(DFATAL) << __func__ << " Incorrect number of dmabuf fds provided, got: "
+    DLOG(ERROR) << __func__ << " Incorrect number of dmabuf fds provided, got: "
                 << dmabuf_fds.size() << ", expected 1 to " << NumPlanes(format);
     return nullptr;
   }
@@ -406,7 +406,7 @@
   scoped_refptr<VideoFrame> frame = new VideoFrame(
       format, storage, coded_size, visible_rect, natural_size, timestamp);
   if (!frame) {
-    LOG(DFATAL) << __func__ << " Couldn't create VideoFrame instance.";
+    DLOG(ERROR) << __func__ << " Couldn't create VideoFrame instance.";
     return nullptr;
   }
   memcpy(&frame->mailbox_holders_, mailbox_holders,
@@ -438,7 +438,7 @@
     // minimum OS X and iOS SDKs permits it.
     format = PIXEL_FORMAT_NV12;
   } else {
-    LOG(DFATAL) << "CVPixelBuffer format not supported: " << cv_format;
+    DLOG(ERROR) << "CVPixelBuffer format not supported: " << cv_format;
     return nullptr;
   }
 
@@ -448,7 +448,7 @@
   const StorageType storage = STORAGE_UNOWNED_MEMORY;
 
   if (!IsValidConfig(format, storage, coded_size, visible_rect, natural_size)) {
-    LOG(DFATAL) << __func__ << " Invalid config."
+    DLOG(ERROR) << __func__ << " Invalid config."
                 << ConfigToString(format, storage, coded_size, visible_rect,
                                   natural_size);
     return nullptr;
@@ -474,7 +474,7 @@
   DCHECK(frame->visible_rect().Contains(visible_rect));
 
   if (!AreValidPixelFormatsForWrap(frame->format(), format)) {
-    LOG(DFATAL) << __func__ << " Invalid format conversion."
+    DLOG(ERROR) << __func__ << " Invalid format conversion."
                 << VideoPixelFormatToString(frame->format()) << " to "
                 << VideoPixelFormatToString(format);
     return nullptr;
@@ -482,7 +482,7 @@
 
   if (!IsValidConfig(format, frame->storage_type(), frame->coded_size(),
                      visible_rect, natural_size)) {
-    LOG(DFATAL) << __func__ << " Invalid config."
+    DLOG(ERROR) << __func__ << " Invalid config."
                 << ConfigToString(format, frame->storage_type(),
                                   frame->coded_size(), visible_rect,
                                   natural_size);
@@ -505,7 +505,7 @@
   if (frame->storage_type() == STORAGE_DMABUFS) {
     wrapping_frame->dmabuf_fds_ = DuplicateFDs(frame->dmabuf_fds_);
     if (wrapping_frame->dmabuf_fds_.empty()) {
-      LOG(DFATAL) << __func__ << " Couldn't duplicate fds.";
+      DLOG(ERROR) << __func__ << " Couldn't duplicate fds.";
       return nullptr;
     }
   }
@@ -991,7 +991,7 @@
   // http://crbug.com/555909
   if (format != PIXEL_FORMAT_I420 && format != PIXEL_FORMAT_Y16 &&
       format != PIXEL_FORMAT_ARGB) {
-    LOG(DFATAL) << "Only PIXEL_FORMAT_I420, PIXEL_FORMAT_Y16, and "
+    DLOG(ERROR) << "Only PIXEL_FORMAT_I420, PIXEL_FORMAT_Y16, and "
                    "PIXEL_FORMAT_ARGB formats are supported: "
                 << VideoPixelFormatToString(format);
     return nullptr;
@@ -999,7 +999,7 @@
 
   if (!IsValidConfig(format, storage_type, coded_size, visible_rect,
                      natural_size)) {
-    LOG(DFATAL) << __func__ << " Invalid config."
+    DLOG(ERROR) << __func__ << " Invalid config."
                 << ConfigToString(format, storage_type, coded_size,
                                   visible_rect, natural_size);
     return nullptr;
@@ -1049,7 +1049,7 @@
                                   coded_size.width() / 2});
       return frame;
     default:
-      LOG(DFATAL) << "Invalid number of planes: " << NumPlanes(format)
+      DLOG(ERROR) << "Invalid number of planes: " << NumPlanes(format)
                   << " in format: " << VideoPixelFormatToString(format);
       return nullptr;
   }
@@ -1161,7 +1161,7 @@
   const StorageType storage = STORAGE_OWNED_MEMORY;
   if (!IsValidConfig(layout.format(), storage, layout.coded_size(),
                      visible_rect, natural_size)) {
-    LOG(DFATAL) << __func__ << " Invalid config."
+    DLOG(ERROR) << __func__ << " Invalid config."
                 << ConfigToString(layout.format(), storage, layout.coded_size(),
                                   visible_rect, natural_size);
     return nullptr;
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 58f84ef..29a6274 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -2889,6 +2889,12 @@
   }
 
   UpdateSecondaryProperties();
+
+  // If the WatchTimeReporter was recreated in the middle of playback, we want
+  // to resume playback here too since we won't get another play() call. When
+  // seeking, the seek completion will restart it if necessary.
+  if (!paused_ && !seeking_)
+    watch_time_reporter_->OnPlaying();
 }
 
 void WebMediaPlayerImpl::UpdateSecondaryProperties() {
@@ -3132,7 +3138,8 @@
 void WebMediaPlayerImpl::SwitchToLocalRenderer(
     MediaObserverClient::ReasonToSwitchToLocal reason) {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
-  DCHECK(disable_pipeline_auto_suspend_);
+  if (!disable_pipeline_auto_suspend_)
+    return;  // Is currently with local renderer.
   disable_pipeline_auto_suspend_ = false;
 
   // Capabilities reporting may resume now that playback is local.
diff --git a/media/gpu/android/codec_wrapper.cc b/media/gpu/android/codec_wrapper.cc
index 7d851d1..acbe29e 100644
--- a/media/gpu/android/codec_wrapper.cc
+++ b/media/gpu/android/codec_wrapper.cc
@@ -24,7 +24,7 @@
 class CodecWrapperImpl : public base::RefCountedThreadSafe<CodecWrapperImpl> {
  public:
   CodecWrapperImpl(CodecSurfacePair codec_surface_pair,
-                   base::Closure output_buffer_release_cb);
+                   CodecWrapper::OutputReleasedCB output_buffer_release_cb);
 
   using DequeueStatus = CodecWrapper::DequeueStatus;
   using QueueStatus = CodecWrapper::QueueStatus;
@@ -89,7 +89,7 @@
 
   // A callback that's called whenever an output buffer is released back to the
   // codec.
-  base::Closure output_buffer_release_cb_;
+  CodecWrapper::OutputReleasedCB output_buffer_release_cb_;
 
   // Do we owe the client an EOS in DequeueOutput, due to an eos that we elided
   // while we're already flushed?
@@ -111,8 +111,9 @@
   return codec_->ReleaseCodecOutputBuffer(id_, true);
 }
 
-CodecWrapperImpl::CodecWrapperImpl(CodecSurfacePair codec_surface_pair,
-                                   base::Closure output_buffer_release_cb)
+CodecWrapperImpl::CodecWrapperImpl(
+    CodecSurfacePair codec_surface_pair,
+    CodecWrapper::OutputReleasedCB output_buffer_release_cb)
     : state_(State::kFlushed),
       codec_(std::move(codec_surface_pair.first)),
       surface_bundle_(std::move(codec_surface_pair.second)),
@@ -386,13 +387,15 @@
   int index = buffer_it->second;
   codec_->ReleaseOutputBuffer(index, render);
   buffer_ids_.erase(buffer_ids_.begin(), buffer_it + 1);
-  if (output_buffer_release_cb_)
-    output_buffer_release_cb_.Run();
+  if (output_buffer_release_cb_) {
+    output_buffer_release_cb_.Run(state_ == State::kDrained ||
+                                  state_ == State::kDraining);
+  }
   return true;
 }
 
 CodecWrapper::CodecWrapper(CodecSurfacePair codec_surface_pair,
-                           base::Closure output_buffer_release_cb)
+                           OutputReleasedCB output_buffer_release_cb)
     : impl_(new CodecWrapperImpl(std::move(codec_surface_pair),
                                  std::move(output_buffer_release_cb))) {}
 
diff --git a/media/gpu/android/codec_wrapper.h b/media/gpu/android/codec_wrapper.h
index b316f11..2c81fe9 100644
--- a/media/gpu/android/codec_wrapper.h
+++ b/media/gpu/android/codec_wrapper.h
@@ -68,8 +68,12 @@
   // released back to the codec (whether it's rendered or not). This is a signal
   // that the codec might be ready to accept more input. It may be run on any
   // thread.
+  //
+  // OutputReleasedCB will be called with a bool indicating if CodecWrapper is
+  // currently draining or in the drained state.
+  using OutputReleasedCB = base::RepeatingCallback<void(bool)>;
   CodecWrapper(CodecSurfacePair codec_surface_pair,
-               base::Closure output_buffer_release_cb);
+               OutputReleasedCB output_buffer_release_cb);
   ~CodecWrapper();
 
   // Takes the backing codec and surface, implicitly discarding all outstanding
diff --git a/media/gpu/android/codec_wrapper_unittest.cc b/media/gpu/android/codec_wrapper_unittest.cc
index b01bb38..e08a4a3 100644
--- a/media/gpu/android/codec_wrapper_unittest.cc
+++ b/media/gpu/android/codec_wrapper_unittest.cc
@@ -63,7 +63,8 @@
   NiceMock<MockMediaCodecBridge>* codec_;
   std::unique_ptr<CodecWrapper> wrapper_;
   scoped_refptr<AVDASurfaceBundle> surface_bundle_;
-  NiceMock<base::MockCallback<base::Closure>> output_buffer_release_cb_;
+  NiceMock<base::MockCallback<CodecWrapper::OutputReleasedCB>>
+      output_buffer_release_cb_;
   scoped_refptr<DecoderBuffer> fake_decoder_buffer_;
 };
 
@@ -211,13 +212,22 @@
 
 TEST_F(CodecWrapperTest, OutputBufferReleaseCbIsCalledWhenRendering) {
   auto codec_buffer = DequeueCodecOutputBuffer();
-  EXPECT_CALL(output_buffer_release_cb_, Run()).Times(1);
+  EXPECT_CALL(output_buffer_release_cb_, Run(false)).Times(1);
   codec_buffer->ReleaseToSurface();
 }
 
 TEST_F(CodecWrapperTest, OutputBufferReleaseCbIsCalledWhenDestructing) {
   auto codec_buffer = DequeueCodecOutputBuffer();
-  EXPECT_CALL(output_buffer_release_cb_, Run()).Times(1);
+  EXPECT_CALL(output_buffer_release_cb_, Run(false)).Times(1);
+}
+
+TEST_F(CodecWrapperTest, OutputBufferReflectsDrainingOrDrainedStatus) {
+  wrapper_->QueueInputBuffer(*fake_decoder_buffer_, EncryptionScheme());
+  auto eos = DecoderBuffer::CreateEOSBuffer();
+  wrapper_->QueueInputBuffer(*eos, EncryptionScheme());
+  ASSERT_TRUE(wrapper_->IsDraining());
+  auto codec_buffer = DequeueCodecOutputBuffer();
+  EXPECT_CALL(output_buffer_release_cb_, Run(true)).Times(1);
 }
 
 TEST_F(CodecWrapperTest, CodecStartsInFlushedState) {
diff --git a/media/gpu/android/media_codec_video_decoder.cc b/media/gpu/android/media_codec_video_decoder.cc
index bdaceaa..ace97d8 100644
--- a/media/gpu/android/media_codec_video_decoder.cc
+++ b/media/gpu/android/media_codec_video_decoder.cc
@@ -89,6 +89,16 @@
   }
 }
 
+void OutputBufferReleased(bool using_async_api,
+                          base::RepeatingClosure pump_cb,
+                          bool is_drained_or_draining) {
+  // The asynchronous API doesn't need pumping upon calls to ReleaseOutputBuffer
+  // unless we're draining or drained.
+  if (using_async_api && !is_drained_or_draining)
+    return;
+  pump_cb.Run();
+}
+
 }  // namespace
 
 // static
@@ -455,12 +465,10 @@
 
   codec_ = std::make_unique<CodecWrapper>(
       CodecSurfacePair(std::move(codec), std::move(surface_bundle)),
-      // The async API will always get an OnBuffersAvailable callback once an
-      // output buffer is available, so we don't need to manually pump here.
-      using_async_api_ ? base::RepeatingClosure()
-                       : BindToCurrentLoop(base::BindRepeating(
-                             &MediaCodecVideoDecoder::StartTimerOrPumpCodec,
-                             weak_factory_.GetWeakPtr())));
+      base::BindRepeating(&OutputBufferReleased, using_async_api_,
+                          BindToCurrentLoop(base::BindRepeating(
+                              &MediaCodecVideoDecoder::StartTimerOrPumpCodec,
+                              weak_factory_.GetWeakPtr()))));
 
   // If the target surface changed while codec creation was in progress,
   // transition to it immediately.
diff --git a/media/gpu/ipc/service/vda_video_decoder.cc b/media/gpu/ipc/service/vda_video_decoder.cc
index beff80c..97e51cb 100644
--- a/media/gpu/ipc/service/vda_video_decoder.cc
+++ b/media/gpu/ipc/service/vda_video_decoder.cc
@@ -503,6 +503,8 @@
   DCHECK(vda_initialized_);
 
   if (parent_task_runner_->BelongsToCurrentThread()) {
+    if (!parent_weak_this_)
+      return;
     // Note: This optimization is only correct if the output callback does not
     // reentrantly call Decode(). MojoVideoDecoderService is safe, but there is
     // no guarantee in the media::VideoDecoder interface definition.
@@ -553,6 +555,8 @@
   DCHECK(vda_initialized_);
 
   if (parent_task_runner_->BelongsToCurrentThread()) {
+    if (!parent_weak_this_)
+      return;
     // Note: This optimization is only correct if the decode callback does not
     // reentrantly call Decode(). MojoVideoDecoderService is safe, but there is
     // no guarantee in the media::VideoDecoder interface definition.
@@ -688,6 +692,8 @@
   DVLOG(1) << __func__;
 
   if (parent_task_runner_->BelongsToCurrentThread()) {
+    if (!parent_weak_this_)
+      return;
     AddEventOnParentThread(std::move(event));
     return;
   }
diff --git a/net/BUILD.gn b/net/BUILD.gn
index aa90b645..1d4e113 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1561,20 +1561,14 @@
       "third_party/quic/platform/impl/quic_url_impl.h",
       "third_party/quic/platform/impl/quic_url_utils_impl.cc",
       "third_party/quic/platform/impl/quic_url_utils_impl.h",
-      "third_party/quic/quartc/quartc_clock_interface.h",
       "third_party/quic/quartc/quartc_factory.cc",
       "third_party/quic/quartc/quartc_factory.h",
-      "third_party/quic/quartc/quartc_factory_interface.cc",
-      "third_party/quic/quartc/quartc_factory_interface.h",
       "third_party/quic/quartc/quartc_packet_writer.cc",
       "third_party/quic/quartc/quartc_packet_writer.h",
       "third_party/quic/quartc/quartc_session.cc",
       "third_party/quic/quartc/quartc_session.h",
-      "third_party/quic/quartc/quartc_session_interface.h",
       "third_party/quic/quartc/quartc_stream.cc",
       "third_party/quic/quartc/quartc_stream.h",
-      "third_party/quic/quartc/quartc_stream_interface.h",
-      "third_party/quic/quartc/quartc_task_runner_interface.h",
       "third_party/spdy/core/fuzzing/hpack_fuzz_util.cc",
       "third_party/spdy/core/fuzzing/hpack_fuzz_util.h",
       "third_party/spdy/core/hpack/hpack_constants.cc",
diff --git a/net/http/http_stream_factory_job_controller.cc b/net/http/http_stream_factory_job_controller.cc
index d632aabb..3f33223 100644
--- a/net/http/http_stream_factory_job_controller.cc
+++ b/net/http/http_stream_factory_job_controller.cc
@@ -107,7 +107,7 @@
   bound_job_ = nullptr;
   if (proxy_resolve_request_) {
     DCHECK_EQ(STATE_RESOLVE_PROXY_COMPLETE, next_state_);
-    session_->proxy_resolution_service()->CancelRequest(proxy_resolve_request_);
+    proxy_resolve_request_.reset();
   }
   net_log_.EndEvent(NetLogEventType::HTTP_STREAM_JOB_CONTROLLER);
 }
@@ -155,8 +155,7 @@
 LoadState HttpStreamFactory::JobController::GetLoadState() const {
   DCHECK(request_);
   if (next_state_ == STATE_RESOLVE_PROXY_COMPLETE)
-    return session_->proxy_resolution_service()->GetLoadState(
-        proxy_resolve_request_);
+    return proxy_resolve_request_->GetLoadState();
   if (bound_job_)
     return bound_job_->GetLoadState();
   if (main_job_)
diff --git a/net/http/http_stream_factory_job_controller.h b/net/http/http_stream_factory_job_controller.h
index ac3f842..e43c00f 100644
--- a/net/http/http_stream_factory_job_controller.h
+++ b/net/http/http_stream_factory_job_controller.h
@@ -370,7 +370,7 @@
   bool can_start_alternative_proxy_job_;
 
   State next_state_;
-  ProxyResolutionService::Request* proxy_resolve_request_;
+  std::unique_ptr<ProxyResolutionService::Request> proxy_resolve_request_;
   const HttpRequestInfo request_info_;
   ProxyInfo proxy_info_;
   const SSLConfig server_ssl_config_;
diff --git a/net/proxy_resolution/proxy_resolution_service.cc b/net/proxy_resolution/proxy_resolution_service.cc
index ea417271..3703bcb 100644
--- a/net/proxy_resolution/proxy_resolution_service.cc
+++ b/net/proxy_resolution/proxy_resolution_service.cc
@@ -829,148 +829,54 @@
 const ProxyResolutionService::PacPollPolicy*
     ProxyResolutionService::PacFileDeciderPoller::poll_policy_ = NULL;
 
-// ProxyResolutionService::Request --------------------------------------------
-
-class ProxyResolutionService::Request
-    : public base::RefCounted<ProxyResolutionService::Request> {
+class ProxyResolutionService::RequestImpl
+    : public ProxyResolutionService::Request {
  public:
-  Request(ProxyResolutionService* service,
-          const GURL& url,
-          const std::string& method,
-          ProxyDelegate* proxy_delegate,
-          ProxyInfo* results,
-          CompletionOnceCallback user_callback,
-          const NetLogWithSource& net_log)
-      : service_(service),
-        user_callback_(std::move(user_callback)),
-        results_(results),
-        url_(url),
-        method_(method),
-        proxy_delegate_(proxy_delegate),
-        resolve_job_(nullptr),
-        net_log_(net_log),
-        creation_time_(TimeTicks::Now()) {
-    DCHECK(!user_callback_.is_null());
-  }
+  RequestImpl(ProxyResolutionService* service,
+              const GURL& url,
+              const std::string& method,
+              ProxyDelegate* proxy_delegate,
+              ProxyInfo* results,
+              const CompletionOnceCallback user_callback,
+              const NetLogWithSource& net_log);
+  ~RequestImpl() override;
 
   // Starts the resolve proxy request.
-  int Start() {
-    DCHECK(!was_cancelled());
-    DCHECK(!is_started());
-
-    DCHECK(service_->config_);
-    traffic_annotation_ = MutableNetworkTrafficAnnotationTag(
-        service_->config_->traffic_annotation());
-
-    return resolver()->GetProxyForURL(
-        url_, results_,
-        base::Bind(&Request::QueryComplete, base::Unretained(this)),
-        &resolve_job_, net_log_);
-  }
+  int Start();
 
   bool is_started() const {
     // Note that !! casts to bool. (VS gives a warning otherwise).
     return !!resolve_job_.get();
   }
 
-  void StartAndCompleteCheckingForSynchronous() {
-    int rv =
-        service_->TryToCompleteSynchronously(url_, proxy_delegate_, results_);
-    if (rv == ERR_IO_PENDING)
-      rv = Start();
-    if (rv != ERR_IO_PENDING)
-      QueryComplete(rv);
-  }
+  void StartAndCompleteCheckingForSynchronous();
 
-  void CancelResolveJob() {
-    DCHECK(is_started());
-    // The request may already be running in the resolver.
-    resolve_job_.reset();
-    DCHECK(!is_started());
-  }
+  void CancelResolveJob();
 
-  void Cancel() {
-    net_log_.AddEvent(NetLogEventType::CANCELLED);
+  // Returns true if the request has been completed.
+  bool was_completed() const { return user_callback_.is_null(); }
 
-    if (is_started())
-      CancelResolveJob();
-
-    // Mark as cancelled, to prevent accessing this again later.
-    service_ = NULL;
-    user_callback_.Reset();
-    results_ = NULL;
-
-    net_log_.EndEvent(NetLogEventType::PROXY_RESOLUTION_SERVICE);
-  }
-
-  // Returns true if Cancel() has been called.
-  bool was_cancelled() const {
-    return user_callback_.is_null();
-  }
+  // Callback for when the ProxyResolver request has completed.
+  void QueryComplete(int result_code);
 
   // Helper to call after ProxyResolver completion (both synchronous and
   // asynchronous). Fixes up the result that is to be returned to user.
-  int QueryDidComplete(int result_code) {
-    DCHECK(!was_cancelled());
+  int QueryDidComplete(int result_code);
 
-    // Clear |resolve_job_| so is_started() returns false while
-    // DidFinishResolvingProxy() runs.
-    resolve_job_.reset();
-
-    // Note that DidFinishResolvingProxy might modify |results_|.
-    int rv = service_->DidFinishResolvingProxy(url_, method_, proxy_delegate_,
-                                               results_, result_code, net_log_);
-
-    // Make a note in the results which configuration was in use at the
-    // time of the resolve.
-    results_->did_use_pac_script_ = true;
-    results_->proxy_resolve_start_time_ = creation_time_;
-    results_->proxy_resolve_end_time_ = TimeTicks::Now();
-
-    // If annotation is not already set, e.g. through TryToCompleteSynchronously
-    // function, use in-progress-resolve annotation.
-    if (!results_->traffic_annotation_.is_valid())
-      results_->set_traffic_annotation(traffic_annotation_);
-
-    // If proxy is set without error, ensure that an annotation is provided.
-    if (!rv)
-      DCHECK(results_->traffic_annotation_.is_valid());
-
-    // Reset the state associated with in-progress-resolve.
-    traffic_annotation_.reset();
-
-    return rv;
-  }
+  // Helper to call if the request completes synchronously, since in that case
+  // the request will not be added to |pending_requests_| (in
+  // |ProxyResolutionService|).
+  int QueryDidCompleteSynchronously(int result_code);
 
   NetLogWithSource* net_log() { return &net_log_; }
 
-  LoadState GetLoadState() const {
-    if (is_started())
-      return resolve_job_->GetLoadState();
-    return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
-  }
+  // Request implementation:
+  LoadState GetLoadState() const override;
 
  private:
-  friend class base::RefCounted<ProxyResolutionService::Request>;
-
-  ~Request() = default;
-
-  // Callback for when the ProxyResolver request has completed.
-  void QueryComplete(int result_code) {
-    result_code = QueryDidComplete(result_code);
-
-    // Remove this completed Request from the service's pending list.
-    /// (which will probably cause deletion of |this|).
-    if (!user_callback_.is_null()) {
-      CompletionOnceCallback callback = std::move(user_callback_);
-      service_->RemovePendingRequest(this);
-      std::move(callback).Run(result_code);
-    }
-  }
-
   ProxyResolver* resolver() const { return service_->resolver_.get(); }
 
-  // Note that we don't hold a reference to the ProxyResolutionService.
+  // Note that Request holds a bare pointer to the ProxyResolutionService.
   // Outstanding requests are cancelled during ~ProxyResolutionService, so this
   // is guaranteed to be valid throughout our lifetime.
   ProxyResolutionService* service_;
@@ -984,9 +890,140 @@
   NetLogWithSource net_log_;
   // Time when the request was created.  Stored here rather than in |results_|
   // because the time in |results_| will be cleared.
-  TimeTicks creation_time_;
+  base::TimeTicks creation_time_;
+
+  DISALLOW_COPY_AND_ASSIGN(RequestImpl);
 };
 
+ProxyResolutionService::RequestImpl::RequestImpl(
+    ProxyResolutionService* service,
+    const GURL& url,
+    const std::string& method,
+    ProxyDelegate* proxy_delegate,
+    ProxyInfo* results,
+    CompletionOnceCallback user_callback,
+    const NetLogWithSource& net_log)
+    : service_(service),
+      user_callback_(std::move(user_callback)),
+      results_(results),
+      url_(url),
+      method_(method),
+      proxy_delegate_(proxy_delegate),
+      resolve_job_(nullptr),
+      net_log_(net_log),
+      creation_time_(base::TimeTicks::Now()) {
+  DCHECK(!user_callback_.is_null());
+}
+
+ProxyResolutionService::RequestImpl::~RequestImpl() {
+  if (service_) {
+    service_->RemovePendingRequest(this);
+    net_log_.AddEvent(NetLogEventType::CANCELLED);
+
+    if (is_started())
+      CancelResolveJob();
+
+    // This should be emitted last, after any message |CancelResolveJob()| may
+    // trigger.
+    net_log_.EndEvent(NetLogEventType::PROXY_RESOLUTION_SERVICE);
+  }
+}
+
+// Starts the resolve proxy request.
+int ProxyResolutionService::RequestImpl::Start() {
+  DCHECK(!was_completed());
+  DCHECK(!is_started());
+
+  DCHECK(service_->config_);
+  traffic_annotation_ = MutableNetworkTrafficAnnotationTag(
+      service_->config_->traffic_annotation());
+
+  return resolver()->GetProxyForURL(
+      url_, results_,
+      base::Bind(&ProxyResolutionService::RequestImpl::QueryComplete,
+                 base::Unretained(this)),
+      &resolve_job_, net_log_);
+}
+
+void ProxyResolutionService::RequestImpl::
+    StartAndCompleteCheckingForSynchronous() {
+  int rv =
+      service_->TryToCompleteSynchronously(url_, proxy_delegate_, results_);
+  if (rv == ERR_IO_PENDING)
+    rv = Start();
+  if (rv != ERR_IO_PENDING)
+    QueryComplete(rv);
+}
+
+void ProxyResolutionService::RequestImpl::CancelResolveJob() {
+  DCHECK(is_started());
+  // The request may already be running in the resolver.
+  resolve_job_.reset();
+  DCHECK(!is_started());
+}
+
+int ProxyResolutionService::RequestImpl::QueryDidComplete(int result_code) {
+  DCHECK(!was_completed());
+
+  // Clear |resolve_job_| so is_started() returns false while
+  // DidFinishResolvingProxy() runs.
+  resolve_job_.reset();
+
+  // Note that DidFinishResolvingProxy might modify |results_|.
+  int rv = service_->DidFinishResolvingProxy(url_, method_, proxy_delegate_,
+                                             results_, result_code, net_log_);
+
+  // Make a note in the results which configuration was in use at the
+  // time of the resolve.
+  results_->did_use_pac_script_ = true;
+  results_->proxy_resolve_start_time_ = creation_time_;
+  results_->proxy_resolve_end_time_ = TimeTicks::Now();
+
+  // If annotation is not already set, e.g. through TryToCompleteSynchronously
+  // function, use in-progress-resolve annotation.
+  if (!results_->traffic_annotation_.is_valid())
+    results_->set_traffic_annotation(traffic_annotation_);
+
+  // If proxy is set without error, ensure that an annotation is provided.
+  if (result_code != ERR_ABORTED && !rv)
+    DCHECK(results_->traffic_annotation_.is_valid());
+
+  // Reset the state associated with in-progress-resolve.
+  traffic_annotation_.reset();
+
+  return rv;
+}
+
+int ProxyResolutionService::RequestImpl::QueryDidCompleteSynchronously(
+    int result_code) {
+  int rv = QueryDidComplete(result_code);
+  service_ = nullptr;
+  return rv;
+}
+
+LoadState ProxyResolutionService::RequestImpl::GetLoadState() const {
+  if (service_ &&
+      service_->current_state_ == STATE_WAITING_FOR_INIT_PROXY_RESOLVER) {
+    return service_->init_proxy_resolver_->GetLoadState();
+  }
+
+  if (is_started())
+    return resolve_job_->GetLoadState();
+  return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
+}
+
+// Callback for when the ProxyResolver request has completed.
+void ProxyResolutionService::RequestImpl::QueryComplete(int result_code) {
+  result_code = QueryDidComplete(result_code);
+
+  CompletionOnceCallback callback = std::move(user_callback_);
+
+  service_->RemovePendingRequest(this);
+  service_ = nullptr;
+  user_callback_.Reset();
+  std::move(callback).Run(result_code);
+}
+
 // ProxyResolutionService -----------------------------------------------------
 
 ProxyResolutionService::ProxyResolutionService(
@@ -999,7 +1036,8 @@
       stall_proxy_auto_config_delay_(
           TimeDelta::FromMilliseconds(kDelayAfterNetworkChangesMs)),
       quick_check_enabled_(true),
-      sanitize_url_policy_(SanitizeUrlPolicy::SAFE) {
+      sanitize_url_policy_(SanitizeUrlPolicy::SAFE),
+      weak_ptr_factory_(this) {
   NetworkChangeNotifier::AddIPAddressObserver(this);
   NetworkChangeNotifier::AddDNSObserver(this);
   ResetConfigService(std::move(config_service));
@@ -1085,12 +1123,12 @@
                                          const std::string& method,
                                          ProxyInfo* result,
                                          CompletionOnceCallback callback,
-                                         Request** pac_request,
+                                         std::unique_ptr<Request>* out_request,
                                          ProxyDelegate* proxy_delegate,
                                          const NetLogWithSource& net_log) {
   DCHECK(!callback.is_null());
   return ResolveProxyHelper(raw_url, method, result, std::move(callback),
-                            pac_request, proxy_delegate, net_log);
+                            out_request, proxy_delegate, net_log);
 }
 
 int ProxyResolutionService::ResolveProxyHelper(
@@ -1098,10 +1136,11 @@
     const std::string& method,
     ProxyInfo* result,
     CompletionOnceCallback callback,
-    Request** pac_request,
+    std::unique_ptr<Request>* out_request,
     ProxyDelegate* proxy_delegate,
     const NetLogWithSource& net_log) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(out_request || callback.is_null());
 
   net_log.BeginEvent(NetLogEventType::PROXY_RESOLUTION_SERVICE);
 
@@ -1132,14 +1171,14 @@
   if (callback.is_null())
     return ERR_IO_PENDING;
 
-  scoped_refptr<Request> req(new Request(this, url, method, proxy_delegate,
-                                         result, std::move(callback), net_log));
+  std::unique_ptr<RequestImpl> req = std::make_unique<RequestImpl>(
+      this, url, method, proxy_delegate, result, std::move(callback), net_log);
 
   if (current_state_ == STATE_READY) {
     // Start the resolve request.
     rv = req->Start();
     if (rv != ERR_IO_PENDING)
-      return req->QueryDidComplete(rv);
+      return req->QueryDidCompleteSynchronously(rv);
   } else {
     req->net_log()->BeginEvent(
         NetLogEventType::PROXY_RESOLUTION_SERVICE_WAITING_FOR_INIT_PAC);
@@ -1147,12 +1186,11 @@
 
   DCHECK_EQ(ERR_IO_PENDING, rv);
   DCHECK(!ContainsPendingRequest(req.get()));
-  pending_requests_.insert(req);
+  pending_requests_.insert(req.get());
 
   // Completion will be notified through |callback|, unless the caller cancels
-  // the request using |pac_request|.
-  if (pac_request)
-    *pac_request = req.get();
+  // the request using |out_request|.
+  *out_request = std::move(req);
   return rv;  // ERR_IO_PENDING
 }
 
@@ -1163,7 +1201,7 @@
     ProxyDelegate* proxy_delegate,
     const NetLogWithSource& net_log) {
   return ResolveProxyHelper(raw_url, method, result, CompletionOnceCallback(),
-                            nullptr /* pac_request*/, proxy_delegate,
+                            nullptr /* out_request*/, proxy_delegate,
                             net_log) == OK;
 }
 
@@ -1200,10 +1238,15 @@
   config_service_->RemoveObserver(this);
 
   // Cancel any inprogress requests.
-  for (PendingRequests::iterator it = pending_requests_.begin();
-       it != pending_requests_.end();
-       ++it) {
-    (*it)->Cancel();
+  // This cancels the internal requests, but leaves the responsibility of
+  // canceling the high-level Request (by deleting it) to the client.
+  // Since |pending_requests_| might be modified in one of the requests'
+  // callbacks (if it deletes another request), iterating through the set in a
+  // for-loop will not work.
+  while (!pending_requests_.empty()) {
+    RequestImpl* req = *pending_requests_.begin();
+    req->QueryComplete(ERR_ABORTED);
+    pending_requests_.erase(req);
   }
 }
 
@@ -1211,7 +1254,7 @@
   for (PendingRequests::iterator it = pending_requests_.begin();
        it != pending_requests_.end();
        ++it) {
-    Request* req = it->get();
+    RequestImpl* req = *it;
     if (req->is_started()) {
       req->CancelResolveJob();
 
@@ -1225,22 +1268,26 @@
   DCHECK(!init_proxy_resolver_.get());
   current_state_ = STATE_READY;
 
-  // Make a copy in case |this| is deleted during the synchronous completion
-  // of one of the requests. If |this| is deleted then all of the Request
-  // instances will be Cancel()-ed.
-  PendingRequests pending_copy = pending_requests_;
+  // TODO(lilyhoughton): This is necessary because a callback invoked by
+  // |StartAndCompleteCheckingForSynchronous()| might delete |this|.  A better
+  // solution would be to disallow synchronous callbacks altogether.
+  base::WeakPtr<ProxyResolutionService> weak_this =
+      weak_ptr_factory_.GetWeakPtr();
 
-  for (PendingRequests::iterator it = pending_copy.begin();
-       it != pending_copy.end();
-       ++it) {
-    Request* req = it->get();
-    if (!req->is_started() && !req->was_cancelled()) {
+  auto pending_requests_copy = pending_requests_;
+  for (auto* req : pending_requests_copy) {
+    if (!ContainsPendingRequest(req))
+      continue;
+
+    if (!req->is_started()) {
       req->net_log()->EndEvent(
           NetLogEventType::PROXY_RESOLUTION_SERVICE_WAITING_FOR_INIT_PAC);
 
       // Note that we re-check for synchronous completion, in case we are
-      // no longer using a ProxyResolver (can happen if we fell-back to manual).
+      // no longer using a ProxyResolver (can happen if we fell-back to manual.)
       req->StartAndCompleteCheckingForSynchronous();
+      if (!weak_this)
+        return;  // Synchronous callback deleted |this|
     }
   }
 }
@@ -1355,25 +1402,11 @@
   }
 }
 
-void ProxyResolutionService::CancelRequest(Request* req) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(req);
-  req->Cancel();
-  RemovePendingRequest(req);
-}
-
-LoadState ProxyResolutionService::GetLoadState(const Request* req) const {
-  CHECK(req);
-  if (current_state_ == STATE_WAITING_FOR_INIT_PROXY_RESOLVER)
-    return init_proxy_resolver_->GetLoadState();
-  return req->GetLoadState();
-}
-
-bool ProxyResolutionService::ContainsPendingRequest(Request* req) {
+bool ProxyResolutionService::ContainsPendingRequest(RequestImpl* req) {
   return pending_requests_.count(req) == 1;
 }
 
-void ProxyResolutionService::RemovePendingRequest(Request* req) {
+void ProxyResolutionService::RemovePendingRequest(RequestImpl* req) {
   DCHECK(ContainsPendingRequest(req));
   pending_requests_.erase(req);
 }
@@ -1410,7 +1443,7 @@
         result_code);
 
     bool reset_config = result_code == ERR_PAC_SCRIPT_TERMINATED;
-    if (!config_->value().pac_mandatory()) {
+    if (config_ && !config_->value().pac_mandatory()) {
       // Fall-back to direct when the proxy resolver fails. This corresponds
       // with a javascript runtime error in the PAC script.
       //
diff --git a/net/proxy_resolution/proxy_resolution_service.h b/net/proxy_resolution/proxy_resolution_service.h
index 27485a2..d85001e7e 100644
--- a/net/proxy_resolution/proxy_resolution_service.h
+++ b/net/proxy_resolution/proxy_resolution_service.h
@@ -23,9 +23,11 @@
 #include "net/base/net_export.h"
 #include "net/base/network_change_notifier.h"
 #include "net/base/proxy_server.h"
+#include "net/log/net_log_with_source.h"
 #include "net/proxy_resolution/proxy_config_service.h"
 #include "net/proxy_resolution/proxy_config_with_annotation.h"
 #include "net/proxy_resolution/proxy_info.h"
+#include "net/proxy_resolution/proxy_resolver.h"
 #include "url/gurl.h"
 
 class GURL;
@@ -39,9 +41,7 @@
 
 class DhcpPacFileFetcher;
 class NetLog;
-class NetLogWithSource;
 class ProxyDelegate;
-class ProxyResolver;
 class ProxyResolverFactory;
 class PacFileData;
 class PacFileFetcher;
@@ -123,7 +123,17 @@
   ~ProxyResolutionService() override;
 
   // Used to track proxy resolution requests that complete asynchronously.
-  class Request;
+  class Request {
+   public:
+    virtual ~Request() = default;
+    virtual LoadState GetLoadState() const = 0;
+
+   protected:
+    Request() = default;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Request);
+  };
 
   // Determines the appropriate proxy for |url| for a |method| request and
   // stores the result in |results|. If |method| is empty, the caller can expect
@@ -135,10 +145,9 @@
   // ResolveProxy.
   //
   // The caller is responsible for ensuring that |results| and |callback|
-  // remain valid until the callback is run or until |request| is cancelled
-  // via CancelRequest.  |request| is only valid while the completion
-  // callback is still pending. NULL can be passed for |request| if
-  // the caller will not need to cancel the request.
+  // remain valid until the callback is run or until |request| is cancelled,
+  // which occurs when the unique pointer to it is deleted (by leaving scope or
+  // otherwise).  |request| must not be NULL.
   //
   // We use the three possible proxy access types in the following order,
   // doing fallback if one doesn't work.  See "pac_script_decider.h"
@@ -152,7 +161,7 @@
                    const std::string& method,
                    ProxyInfo* results,
                    CompletionOnceCallback callback,
-                   Request** request,
+                   std::unique_ptr<Request>* request,
                    ProxyDelegate* proxy_delegate,
                    const NetLogWithSource& net_log);
 
@@ -185,12 +194,6 @@
   void ReportSuccess(const ProxyInfo& proxy_info,
                      ProxyDelegate* proxy_delegate);
 
-  // Call this method with a non-null |request| to cancel the PAC request.
-  void CancelRequest(Request* request);
-
-  // Returns the LoadState for this |request| which must be non-NULL.
-  LoadState GetLoadState(const Request* request) const;
-
   // Sets the PacFileFetcher and DhcpPacFileFetcher dependencies. This
   // is needed if the ProxyResolver is of type ProxyResolverWithoutFetch.
   void SetPacFileFetchers(
@@ -312,11 +315,11 @@
                            UpdateConfigAfterFailedAutodetect);
   FRIEND_TEST_ALL_PREFIXES(ProxyResolutionServiceTest,
                            UpdateConfigFromPACToDirect);
-  friend class Request;
   class InitProxyResolver;
   class PacFileDeciderPoller;
+  class RequestImpl;
 
-  typedef std::set<scoped_refptr<Request>> PendingRequests;
+  typedef std::set<RequestImpl*> PendingRequests;
 
   enum State {
     STATE_NONE,
@@ -355,7 +358,7 @@
                          const std::string& method,
                          ProxyInfo* results,
                          CompletionOnceCallback callback,
-                         Request** request,
+                         std::unique_ptr<Request>* request,
                          ProxyDelegate* proxy_delegate,
                          const NetLogWithSource& net_log);
 
@@ -368,10 +371,10 @@
   void SetReady();
 
   // Returns true if |pending_requests_| contains |req|.
-  bool ContainsPendingRequest(Request* req);
+  bool ContainsPendingRequest(RequestImpl* req);
 
   // Removes |req| from the list of pending requests.
-  void RemovePendingRequest(Request* req);
+  void RemovePendingRequest(RequestImpl* req);
 
   // Called when proxy resolution has completed (either synchronously or
   // asynchronously). Handles logging the result, and cleaning out
@@ -472,6 +475,10 @@
 
   THREAD_CHECKER(thread_checker_);
 
+  // Flag used by |SetReady()| to check if |this| has been deleted by a
+  // synchronous callback.
+  base::WeakPtrFactory<ProxyResolutionService> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(ProxyResolutionService);
 };
 
diff --git a/net/proxy_resolution/proxy_resolution_service_unittest.cc b/net/proxy_resolution/proxy_resolution_service_unittest.cc
index 72258a1..43e7a8b 100644
--- a/net/proxy_resolution/proxy_resolution_service_unittest.cc
+++ b/net/proxy_resolution/proxy_resolution_service_unittest.cc
@@ -390,8 +390,9 @@
   ProxyInfo info;
   TestCompletionCallback callback;
   BoundTestNetLog log;
+  std::unique_ptr<ProxyResolutionService::Request> request;
   int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
-                                nullptr, nullptr, log.bound());
+                                &request, nullptr, log.bound());
   EXPECT_THAT(rv, IsOk());
   EXPECT_TRUE(factory->pending_requests().empty());
 
@@ -431,8 +432,9 @@
 
   // First, warm up the ProxyResolutionService and fake an error to mark the
   // first server as bad.
+  std::unique_ptr<ProxyResolutionService::Request> request;
   int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
-                                nullptr, nullptr, log.bound());
+                                &request, nullptr, log.bound());
   EXPECT_THAT(rv, IsOk());
   EXPECT_EQ("badproxy:8080", info.proxy_server().ToURI());
 
@@ -443,7 +445,7 @@
 
   // Verify that network delegate is invoked.
   TestResolveProxyDelegate delegate;
-  rv = service.ResolveProxy(url, "GET", &info, callback.callback(), nullptr,
+  rv = service.ResolveProxy(url, "GET", &info, callback.callback(), &request,
                             &delegate, log.bound());
   EXPECT_TRUE(delegate.on_resolve_proxy_called());
   EXPECT_THAT(delegate.proxy_retry_info(), ElementsAre(Key("badproxy:8080")));
@@ -455,21 +457,21 @@
   delegate.set_add_proxy(true);
 
   // Callback should interpose:
-  rv = service.ResolveProxy(url, "GET", &info, callback.callback(), nullptr,
+  rv = service.ResolveProxy(url, "GET", &info, callback.callback(), &request,
                             &delegate, log.bound());
   EXPECT_FALSE(info.is_direct());
   EXPECT_EQ(info.proxy_server().host_port_pair().host(), "delegate_proxy.com");
   delegate.set_add_proxy(false);
 
   // Check non-bypassed URL:
-  rv = service.ResolveProxy(url, "GET", &info, callback.callback(), nullptr,
+  rv = service.ResolveProxy(url, "GET", &info, callback.callback(), &request,
                             &delegate, log.bound());
   EXPECT_FALSE(info.is_direct());
   EXPECT_EQ(info.proxy_server().host_port_pair().host(), "foopy1");
 
   // Check bypassed URL:
   rv = service.ResolveProxy(bypass_url, "GET", &info, callback.callback(),
-                            nullptr, &delegate, log.bound());
+                            &request, &delegate, log.bound());
   EXPECT_TRUE(info.is_direct());
 }
 
@@ -493,31 +495,369 @@
   BoundTestNetLog log;
 
   // First, warm up the ProxyResolutionService.
+  std::unique_ptr<ProxyResolutionService::Request> request;
   int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
-                                nullptr, nullptr, log.bound());
+                                &request, nullptr, log.bound());
   EXPECT_THAT(rv, IsOk());
 
   TestResolveProxyDelegate delegate;
   delegate.set_remove_proxy(true);
 
   // Callback should interpose:
-  rv = service.ResolveProxy(url, "GET", &info, callback.callback(), nullptr,
+  rv = service.ResolveProxy(url, "GET", &info, callback.callback(), &request,
                             &delegate, log.bound());
   EXPECT_TRUE(info.is_direct());
   delegate.set_remove_proxy(false);
 
   // Check non-bypassed URL:
-  rv = service.ResolveProxy(url, "GET", &info, callback.callback(), nullptr,
+  rv = service.ResolveProxy(url, "GET", &info, callback.callback(), &request,
                             &delegate, log.bound());
   EXPECT_FALSE(info.is_direct());
   EXPECT_EQ(info.proxy_server().host_port_pair().host(), "foopy1");
 
   // Check bypassed URL:
   rv = service.ResolveProxy(bypass_url, "GET", &info, callback.callback(),
-                            nullptr, &delegate, log.bound());
+                            &request, &delegate, log.bound());
   EXPECT_TRUE(info.is_direct());
 }
 
+// Test callback that deletes an item when called.  This is used to test various
+// permutations of important objects being deleted in the middle of a series of
+// requests.
+template <typename T>
+class DeletingCallback : public TestCompletionCallbackBase {
+ public:
+  explicit DeletingCallback(std::unique_ptr<T>* deletee);
+  ~DeletingCallback() override;
+
+  const CompletionCallback& callback() const { return callback_; }
+
+ private:
+  void DeleteItem(std::unique_ptr<T>* deletee, int result) {
+    deletee->reset();
+    SetResult(result);
+  }
+
+  const CompletionCallback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeletingCallback);
+};
+
+template <typename T>
+DeletingCallback<T>::DeletingCallback(std::unique_ptr<T>* deletee)
+    : callback_(base::BindRepeating(&DeletingCallback::DeleteItem,
+                                    base::Unretained(this),
+                                    deletee)) {}
+
+template <typename T>
+DeletingCallback<T>::~DeletingCallback() = default;
+
+// Test that the ProxyResolutionService correctly handles the case where a
+// request callback deletes another request.
+TEST_F(ProxyResolutionServiceTest, CallbackDeletesRequest) {
+  MockProxyConfigService* config_service =
+      new MockProxyConfigService("http://foopy/proxy.pac");
+
+  MockAsyncProxyResolver resolver;
+  MockAsyncProxyResolverFactory* factory =
+      new MockAsyncProxyResolverFactory(false);
+
+  std::unique_ptr<ProxyResolutionService> service =
+      std::make_unique<ProxyResolutionService>(
+          base::WrapUnique(config_service), base::WrapUnique(factory), nullptr);
+
+  GURL url("http://www.google.com/");
+  GURL url2("http://www.example.com/");
+
+  ProxyInfo info;
+  std::unique_ptr<ProxyResolutionService::Request> request, request2;
+  DeletingCallback<ProxyResolutionService::Request> callback(&request2);
+  net::CompletionOnceCallback callback2 =
+      base::BindOnce([](int result) { ASSERT_FALSE(true); });
+
+  int rv = service->ResolveProxy(url, std::string(), &info, callback.callback(),
+                                 &request, nullptr, NetLogWithSource());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  rv = service->ResolveProxy(url2, std::string(), &info, std::move(callback2),
+                             &request2, nullptr, NetLogWithSource());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  // Run pending requests.
+  ASSERT_EQ(1u, factory->pending_requests().size());
+  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
+            factory->pending_requests()[0]->script_data()->url());
+  factory->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
+
+  ASSERT_EQ(2u, resolver.pending_jobs().size());
+  // Job order is nondeterministic, as requests are stored in an std::set, so
+  // this loop figures out which one is the correct one to start.
+  int deleting_job = 2;
+  for (int i = 0; i < 2; i++) {
+    if (resolver.pending_jobs()[i]->url() == url) {
+      deleting_job = i;
+      break;
+    }
+    ASSERT_LE(i, 1); // The loop should never actually make it to the end.
+  }
+
+  // Set the result in proxy resolver.
+  resolver.pending_jobs()[deleting_job]->results()->UseNamedProxy("foopy");
+  resolver.pending_jobs()[deleting_job]->CompleteNow(OK);
+
+  //// Only one of the callbacks should have been run:
+  EXPECT_TRUE(callback.have_result());
+  EXPECT_THAT(callback.WaitForResult(), IsOk());
+
+  ASSERT_EQ(0u, resolver.pending_jobs().size());
+  ASSERT_EQ(1u, resolver.cancelled_jobs().size());
+  ASSERT_EQ(url2, resolver.cancelled_jobs()[0]->url());
+}
+
+// Test that the ProxyResolutionService correctly handles the case where a
+// request callback deletes another request.  (Triggered by the loop in
+// ProxyResolutionService's destructor).
+TEST_F(ProxyResolutionServiceTest, CallbackDeletesRequestDuringDestructor) {
+  MockProxyConfigService* config_service =
+      new MockProxyConfigService("http://foopy/proxy.pac");
+
+  MockAsyncProxyResolver resolver;
+  MockAsyncProxyResolverFactory* factory =
+      new MockAsyncProxyResolverFactory(false);
+
+  std::unique_ptr<ProxyResolutionService> service =
+      std::make_unique<ProxyResolutionService>(
+          base::WrapUnique(config_service), base::WrapUnique(factory), nullptr);
+
+  GURL url("http://www.google.com/");
+
+  ProxyInfo info;
+  std::unique_ptr<ProxyResolutionService::Request> request, request2;
+  DeletingCallback<ProxyResolutionService::Request> callback(&request2),
+      callback2(&request);
+
+  int rv = service->ResolveProxy(url, std::string(), &info, callback.callback(),
+                                 &request, nullptr, NetLogWithSource());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  rv = service->ResolveProxy(url, std::string(), &info, callback2.callback(),
+                             &request2, nullptr, NetLogWithSource());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  // Make sure that ProxyResolutionServices is deleted before the requests, as
+  // this triggers completion of the pending requests.
+  service.reset();
+
+  // Only one of the callbacks should have been run:
+  EXPECT_TRUE(callback.have_result() ^ callback2.have_result());
+
+  // Callbacks run during destruction of ProxyResolutionService for Requests
+  // that have not been started are called with net::ERR_ABORTED
+  if (callback.have_result()) {
+    EXPECT_THAT(callback.WaitForResult(),
+                IsError(net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED));
+  }
+  if (callback2.have_result()) {
+    EXPECT_THAT(callback2.WaitForResult(),
+                IsError(net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED));
+  }
+}
+
+// Test that the ProxyResolutionService correctly handles the case where a
+// request callback deletes its own handle.
+TEST_F(ProxyResolutionServiceTest, CallbackDeletesSelf) {
+  MockProxyConfigService* config_service =
+      new MockProxyConfigService("http://foopy/proxy.pac");
+
+  MockAsyncProxyResolver resolver;
+  MockAsyncProxyResolverFactory* factory =
+      new MockAsyncProxyResolverFactory(false);
+
+  std::unique_ptr<ProxyResolutionService> service =
+      std::make_unique<ProxyResolutionService>(
+          base::WrapUnique(config_service), base::WrapUnique(factory), nullptr);
+
+  GURL url("http://www.google.com/");
+  ProxyInfo info;
+
+  std::unique_ptr<ProxyResolutionService::Request> request1;
+  TestCompletionCallback callback1;
+  int rv =
+      service->ResolveProxy(url, std::string(), &info, callback1.callback(),
+                            &request1, nullptr, NetLogWithSource());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  GURL url2("http://www.example.com/");
+  std::unique_ptr<ProxyResolutionService::Request> request2;
+  DeletingCallback<ProxyResolutionService::Request> callback2(&request2);
+  rv = service->ResolveProxy(url2, std::string(), &info, callback2.callback(),
+                             &request2, nullptr, NetLogWithSource());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  std::unique_ptr<ProxyResolutionService::Request> request3;
+  TestCompletionCallback callback3;
+  rv = service->ResolveProxy(url, std::string(), &info, callback3.callback(),
+                             &request3, nullptr, NetLogWithSource());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  ASSERT_EQ(1u, factory->pending_requests().size());
+  EXPECT_EQ(GURL("http://foopy/proxy.pac"),
+            factory->pending_requests()[0]->script_data()->url());
+  factory->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
+
+  ASSERT_EQ(3u, resolver.pending_jobs().size());
+  // Job order is nondeterministic, as requests are stored in an std::set, so
+  // this loop figures out which one is the correct one to start.
+  int self_deleting_job = 3;
+  for (int i = 0; i < 3; i++) {
+    if (resolver.pending_jobs()[i]->url() == url2) {
+      self_deleting_job = i;
+      break;
+    }
+    ASSERT_LE(i, 2); // The loop should never actually make it to the end.
+  }
+
+  // Set the result in proxy resolver.
+  resolver.pending_jobs()[self_deleting_job]->results()->UseNamedProxy("foopy");
+  resolver.pending_jobs()[self_deleting_job]->CompleteNow(OK);
+
+  ASSERT_EQ(2u, resolver.pending_jobs().size());
+  ASSERT_EQ(0u, resolver.cancelled_jobs().size());
+  ASSERT_EQ(url, resolver.pending_jobs()[0]->url());
+  ASSERT_EQ(url, resolver.pending_jobs()[1]->url());
+}
+
+// Test that the ProxyResolutionService correctly handles the case where a
+// request callback deletes its own handle, when triggered by
+// ProxyResolutionService's destructor.
+TEST_F(ProxyResolutionServiceTest, CallbackDeletesSelfDuringDestructor) {
+  MockProxyConfigService* config_service =
+      new MockProxyConfigService("http://foopy/proxy.pac");
+
+  MockAsyncProxyResolver resolver;
+  MockAsyncProxyResolverFactory* factory =
+      new MockAsyncProxyResolverFactory(false);
+
+  std::unique_ptr<ProxyResolutionService> service =
+      std::make_unique<ProxyResolutionService>(
+          base::WrapUnique(config_service), base::WrapUnique(factory), nullptr);
+
+  GURL url("http://www.google.com/");
+  ProxyInfo info;
+
+  std::unique_ptr<ProxyResolutionService::Request> request1;
+  TestCompletionCallback callback1;
+  int rv =
+      service->ResolveProxy(url, std::string(), &info, callback1.callback(),
+                            &request1, nullptr, NetLogWithSource());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  std::unique_ptr<ProxyResolutionService::Request> request2;
+  DeletingCallback<ProxyResolutionService::Request> callback2(&request2);
+  rv = service->ResolveProxy(url, std::string(), &info, callback2.callback(),
+                             &request2, nullptr, NetLogWithSource());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  std::unique_ptr<ProxyResolutionService::Request> request3;
+  TestCompletionCallback callback3;
+  rv = service->ResolveProxy(url, std::string(), &info, callback3.callback(),
+                             &request3, nullptr, NetLogWithSource());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  service.reset();
+
+  EXPECT_THAT(callback1.WaitForResult(),
+              IsError(net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED));
+  EXPECT_THAT(callback2.WaitForResult(),
+              IsError(net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED));
+  EXPECT_THAT(callback3.WaitForResult(),
+              IsError(net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED));
+}
+
+TEST_F(ProxyResolutionServiceTest, ProxyServiceDeletedBeforeRequest) {
+  MockProxyConfigService* config_service =
+      new MockProxyConfigService("http://foopy/proxy.pac");
+
+  MockAsyncProxyResolver resolver;
+  MockAsyncProxyResolverFactory* factory =
+      new MockAsyncProxyResolverFactory(false);
+
+  GURL url("http://www.google.com/");
+
+  ProxyInfo info;
+  TestCompletionCallback callback;
+  std::unique_ptr<ProxyResolutionService::Request> request;
+  BoundTestNetLog log;
+
+  int rv;
+  {
+    ProxyResolutionService service(base::WrapUnique(config_service),
+                                   base::WrapUnique(factory), nullptr);
+    rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
+                              &request, nullptr, log.bound());
+    EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+    EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, request->GetLoadState());
+
+    ASSERT_EQ(1u, factory->pending_requests().size());
+    EXPECT_EQ(GURL("http://foopy/proxy.pac"),
+              factory->pending_requests()[0]->script_data()->url());
+    factory->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
+    ASSERT_EQ(1u, resolver.pending_jobs().size());
+  }
+
+  ASSERT_EQ(0u, resolver.pending_jobs().size());
+
+  EXPECT_THAT(callback.WaitForResult(), IsOk());
+}
+
+// Test that the ProxyResolutionService correctly handles the case where a
+// request callback deletes the service.
+TEST_F(ProxyResolutionServiceTest, CallbackDeletesService) {
+  MockProxyConfigService* config_service =
+      new MockProxyConfigService("http://foopy/proxy.pac");
+
+  MockAsyncProxyResolver resolver;
+  MockAsyncProxyResolverFactory* factory =
+      new MockAsyncProxyResolverFactory(false);
+
+  std::unique_ptr<ProxyResolutionService> service =
+      std::make_unique<ProxyResolutionService>(
+          base::WrapUnique(config_service), base::WrapUnique(factory), nullptr);
+
+  GURL url("http://www.google.com/");
+
+  ProxyInfo info;
+
+  DeletingCallback<ProxyResolutionService> callback(&service);
+  std::unique_ptr<ProxyResolutionService::Request> request1;
+  int rv = service->ResolveProxy(url, std::string(), &info, callback.callback(),
+                                 &request1, nullptr, NetLogWithSource());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, request1->GetLoadState());
+
+  TestCompletionCallback callback2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
+  rv = service->ResolveProxy(url, std::string(), &info, callback2.callback(),
+                             &request2, nullptr, NetLogWithSource());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  TestCompletionCallback callback3;
+  std::unique_ptr<ProxyResolutionService::Request> request3;
+  rv = service->ResolveProxy(url, std::string(), &info, callback3.callback(),
+                             &request3, nullptr, NetLogWithSource());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  config_service->SetConfig(ProxyConfigWithAnnotation(
+      ProxyConfig::CreateDirect(), TRAFFIC_ANNOTATION_FOR_TESTS));
+
+  ASSERT_EQ(0u, resolver.pending_jobs().size());
+  ASSERT_THAT(callback.WaitForResult(), IsOk());
+  ASSERT_THAT(callback2.WaitForResult(), IsOk());
+  ASSERT_THAT(callback3.WaitForResult(), IsOk());
+}
+
 TEST_F(ProxyResolutionServiceTest, PAC) {
   MockProxyConfigService* config_service =
       new MockProxyConfigService("http://foopy/proxy.pac");
@@ -533,14 +873,14 @@
 
   ProxyInfo info;
   TestCompletionCallback callback;
-  ProxyResolutionService::Request* request;
+  std::unique_ptr<ProxyResolutionService::Request> request;
   BoundTestNetLog log;
 
   int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
                                 &request, nullptr, log.bound());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
-  EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, service.GetLoadState(request));
+  EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, request->GetLoadState());
 
   ASSERT_EQ(1u, factory->pending_requests().size());
   EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -597,8 +937,9 @@
 
   ProxyInfo info;
   TestCompletionCallback callback;
+  std::unique_ptr<ProxyResolutionService::Request> request;
   int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
-                                nullptr, nullptr, NetLogWithSource());
+                                &request, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -628,8 +969,9 @@
 
   ProxyInfo info;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
-                                nullptr, nullptr, NetLogWithSource());
+                                &request1, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -675,8 +1017,9 @@
 
   ProxyInfo info;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
-                                nullptr, nullptr, NetLogWithSource());
+                                &request1, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -732,8 +1075,9 @@
 
   ProxyInfo info;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
-                                nullptr, nullptr, NetLogWithSource());
+                                &request1, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -787,8 +1131,9 @@
   GURL url("http://www.google.com/");
   ProxyInfo info;
   TestCompletionCallback callback;
+  std::unique_ptr<ProxyResolutionService::Request> request;
   int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
-                                nullptr, nullptr, NetLogWithSource());
+                                &request, nullptr, NetLogWithSource());
   ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
   factory->pending_requests()[0]->CompleteNowWithForwarder(OK, &resolver);
   ASSERT_EQ(1u, resolver.pending_jobs().size());
@@ -826,8 +1171,9 @@
   GURL url("http://www.google.com/");
   ProxyInfo info;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request;
   int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
-                                nullptr, nullptr, NetLogWithSource());
+                                &request, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -854,7 +1200,7 @@
   // regardless of whether the first request failed in it.
   TestCompletionCallback callback2;
   rv = service.ResolveProxy(url, std::string(), &info, callback2.callback(),
-                            nullptr, nullptr, NetLogWithSource());
+                            &request, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   ASSERT_EQ(1u, resolver.pending_jobs().size());
@@ -888,8 +1234,9 @@
   GURL url("http://www.google.com/");
   ProxyInfo info;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request;
   int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
-                                nullptr, nullptr, NetLogWithSource());
+                                &request, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   ASSERT_EQ(1u, factory->pending_requests().size());
@@ -919,7 +1266,7 @@
 
   TestCompletionCallback callback2;
   rv = service.ResolveProxy(url, std::string(), &info, callback2.callback(),
-                            nullptr, nullptr, NetLogWithSource());
+                            &request, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   ASSERT_EQ(1u, factory->pending_requests().size());
@@ -959,13 +1306,14 @@
   GURL url2("https://www.google.com/");
   ProxyInfo info;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1, request2;
   int rv =
       service.ResolveProxy(url1, std::string(), &info, callback1.callback(),
-                           nullptr, nullptr, NetLogWithSource());
+                           &request1, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
   TestCompletionCallback callback2;
   rv = service.ResolveProxy(url2, std::string(), &info, callback2.callback(),
-                            nullptr, nullptr, NetLogWithSource());
+                            &request2, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   ASSERT_EQ(1u, factory->pending_requests().size());
@@ -1029,8 +1377,9 @@
   GURL url("http://www.google.com/");
   ProxyInfo info;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request;
   int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
-                                nullptr, nullptr, NetLogWithSource());
+                                &request, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -1050,7 +1399,7 @@
   // to DIRECT.
   TestCompletionCallback callback2;
   rv = service.ResolveProxy(url, std::string(), &info, callback2.callback(),
-                            nullptr, nullptr, NetLogWithSource());
+                            &request, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED));
   EXPECT_FALSE(info.is_direct());
 }
@@ -1081,8 +1430,9 @@
   GURL url("http://www.google.com/");
   ProxyInfo info;
   TestCompletionCallback callback;
+  std::unique_ptr<ProxyResolutionService::Request> request;
   int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
-                                nullptr, nullptr, NetLogWithSource());
+                                &request, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   // Check that nothing has been sent to the proxy resolver factory yet.
@@ -1127,8 +1477,9 @@
   GURL url("http://www.google.com/");
   ProxyInfo info;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request;
   int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
-                                nullptr, nullptr, NetLogWithSource());
+                                &request, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -1151,7 +1502,7 @@
   // regardless of whether the first request failed in it.
   TestCompletionCallback callback2;
   rv = service.ResolveProxy(url, std::string(), &info, callback2.callback(),
-                            nullptr, nullptr, NetLogWithSource());
+                            &request, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   ASSERT_EQ(1u, resolver.pending_jobs().size());
@@ -1186,8 +1537,9 @@
   // Get the proxy information.
   ProxyInfo info;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request;
   int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
-                                nullptr, nullptr, NetLogWithSource());
+                                &request, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -1232,7 +1584,7 @@
 
   TestCompletionCallback callback3;
   rv = service.ResolveProxy(url, std::string(), &info, callback3.callback(),
-                            nullptr, nullptr, NetLogWithSource());
+                            &request, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   ASSERT_EQ(1u, resolver.pending_jobs().size());
@@ -1279,7 +1631,7 @@
   // Look up proxies again
   TestCompletionCallback callback7;
   rv = service.ResolveProxy(url, std::string(), &info, callback7.callback(),
-                            nullptr, nullptr, NetLogWithSource());
+                            &request, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   ASSERT_EQ(1u, resolver.pending_jobs().size());
@@ -1320,8 +1672,9 @@
   // Get the proxy information.
   ProxyInfo info;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
-                                nullptr, nullptr, NetLogWithSource());
+                                &request1, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -1381,8 +1734,10 @@
   // Get the proxy information.
   ProxyInfo info;
   TestCompletionCallback callback1;
+  TestResolveProxyDelegate delegate1;
+  std::unique_ptr<ProxyResolutionService::Request> request;
   int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
-                                nullptr, nullptr, NetLogWithSource());
+                                &request, &delegate1, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -1413,9 +1768,10 @@
 
   // Fake a PAC failure.
   ProxyInfo info2;
-  TestCompletionCallback callback3;
-  rv = service.ResolveProxy(url, std::string(), &info2, callback3.callback(),
-                            nullptr, nullptr, NetLogWithSource());
+  TestCompletionCallback callback2;
+  TestResolveProxyDelegate delegate2;
+  rv = service.ResolveProxy(url, std::string(), &info2, callback2.callback(),
+                            &request, &delegate2, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   ASSERT_EQ(1u, resolver.pending_jobs().size());
@@ -1426,7 +1782,7 @@
 
   // Although the resolver failed, the ProxyResolutionService will implicitly
   // fall-back to a DIRECT connection.
-  EXPECT_THAT(callback3.WaitForResult(), IsOk());
+  EXPECT_THAT(callback2.WaitForResult(), IsOk());
   EXPECT_TRUE(info2.is_direct());
   EXPECT_FALSE(info2.is_empty());
 
@@ -1434,9 +1790,11 @@
   // proxy list. Since we have not marked the configuration as bad, it should
   // "just work" the next time we call it.
   ProxyInfo info3;
-  TestCompletionCallback callback4;
-  rv = service.ResolveProxy(url, std::string(), &info3, callback4.callback(),
-                            nullptr, nullptr, NetLogWithSource());
+  TestCompletionCallback callback3;
+  TestResolveProxyDelegate delegate3;
+  std::unique_ptr<ProxyResolutionService::Request> request3;
+  rv = service.ResolveProxy(url, std::string(), &info3, callback3.callback(),
+                            &request3, &delegate3, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   ASSERT_EQ(1u, resolver.pending_jobs().size());
@@ -1448,7 +1806,7 @@
 
   // The first proxy was deprioritized since it was added to the bad proxies
   // list by the earlier ReportSuccess().
-  EXPECT_THAT(callback4.WaitForResult(), IsOk());
+  EXPECT_THAT(callback3.WaitForResult(), IsOk());
   EXPECT_FALSE(info3.is_direct());
   EXPECT_EQ("foopy2:9090", info3.proxy_server().ToURI());
   EXPECT_EQ(2u, info3.proxy_list().size());
@@ -1456,6 +1814,10 @@
   EXPECT_FALSE(info.proxy_resolve_start_time().is_null());
   EXPECT_FALSE(info.proxy_resolve_end_time().is_null());
   EXPECT_LE(info.proxy_resolve_start_time(), info.proxy_resolve_end_time());
+
+  EXPECT_TRUE(delegate1.on_resolve_proxy_called());
+  EXPECT_TRUE(delegate2.on_resolve_proxy_called());
+  EXPECT_TRUE(delegate3.on_resolve_proxy_called());
 }
 
 TEST_F(ProxyResolutionServiceTest, ProxyFallback_BadConfigMandatory) {
@@ -1479,8 +1841,9 @@
   // Get the proxy information.
   ProxyInfo info;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv = service.ResolveProxy(url, std::string(), &info, callback1.callback(),
-                                nullptr, nullptr, NetLogWithSource());
+                                &request1, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -1512,8 +1875,9 @@
   // Fake a PAC failure.
   ProxyInfo info2;
   TestCompletionCallback callback3;
+  std::unique_ptr<ProxyResolutionService::Request> request3;
   rv = service.ResolveProxy(url, std::string(), &info2, callback3.callback(),
-                            nullptr, nullptr, NetLogWithSource());
+                            &request3, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   ASSERT_EQ(1u, resolver.pending_jobs().size());
@@ -1534,8 +1898,9 @@
   // "just work" the next time we call it.
   ProxyInfo info3;
   TestCompletionCallback callback4;
+  std::unique_ptr<ProxyResolutionService::Request> request4;
   rv = service.ResolveProxy(url, std::string(), &info3, callback4.callback(),
-                            nullptr, nullptr, NetLogWithSource());
+                            &request4, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   ASSERT_EQ(1u, resolver.pending_jobs().size());
@@ -1569,17 +1934,19 @@
   int rv;
   GURL url1("http://www.webkit.org");
   GURL url2("http://www.webkit.com");
+  std::unique_ptr<ProxyResolutionService::Request> request1;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
 
   // Request for a .org domain should bypass proxy.
   rv = service.ResolveProxy(url1, std::string(), &info[0],
-                            callback[0].callback(), nullptr, nullptr,
+                            callback[0].callback(), &request1, nullptr,
                             NetLogWithSource());
   EXPECT_THAT(rv, IsOk());
   EXPECT_TRUE(info[0].is_direct());
 
   // Request for a .com domain hits the proxy.
   rv = service.ResolveProxy(url2, std::string(), &info[1],
-                            callback[1].callback(), nullptr, nullptr,
+                            callback[1].callback(), &request2, nullptr,
                             NetLogWithSource());
   EXPECT_THAT(rv, IsOk());
   EXPECT_EQ("foopy1:8080", info[1].proxy_server().ToURI());
@@ -1624,6 +1991,7 @@
   ProxyConfig config;
   config.proxy_rules().ParseFromString("http=foopy1:8080;https=foopy2:8080");
   config.set_auto_detect(false);
+  std::unique_ptr<ProxyResolutionService::Request> request;
   {
     ProxyResolutionService service(
         std::make_unique<MockProxyConfigService>(config), nullptr, nullptr);
@@ -1631,7 +1999,7 @@
     ProxyInfo info;
     TestCompletionCallback callback;
     int rv = service.ResolveProxy(test_url, std::string(), &info,
-                                  callback.callback(), nullptr, nullptr,
+                                  callback.callback(), &request, nullptr,
                                   NetLogWithSource());
     EXPECT_THAT(rv, IsOk());
     EXPECT_FALSE(info.is_direct());
@@ -1644,7 +2012,7 @@
     ProxyInfo info;
     TestCompletionCallback callback;
     int rv = service.ResolveProxy(test_url, std::string(), &info,
-                                  callback.callback(), nullptr, nullptr,
+                                  callback.callback(), &request, nullptr,
                                   NetLogWithSource());
     EXPECT_THAT(rv, IsOk());
     EXPECT_TRUE(info.is_direct());
@@ -1657,7 +2025,7 @@
     ProxyInfo info;
     TestCompletionCallback callback;
     int rv = service.ResolveProxy(test_url, std::string(), &info,
-                                  callback.callback(), nullptr, nullptr,
+                                  callback.callback(), &request, nullptr,
                                   NetLogWithSource());
     EXPECT_THAT(rv, IsOk());
     EXPECT_FALSE(info.is_direct());
@@ -1671,7 +2039,7 @@
     ProxyInfo info;
     TestCompletionCallback callback;
     int rv = service.ResolveProxy(test_url, std::string(), &info,
-                                  callback.callback(), nullptr, nullptr,
+                                  callback.callback(), &request, nullptr,
                                   NetLogWithSource());
     EXPECT_THAT(rv, IsOk());
     EXPECT_FALSE(info.is_direct());
@@ -1683,6 +2051,7 @@
   // Test that the proxy config source is set correctly when resolving proxies
   // using manual proxy rules. Namely, the config source should only be set if
   // any of the rules were applied.
+  std::unique_ptr<ProxyResolutionService::Request> request;
   {
     ProxyConfig config;
     config.proxy_rules().ParseFromString("https=foopy2:8080");
@@ -1692,7 +2061,7 @@
     ProxyInfo info;
     TestCompletionCallback callback;
     int rv = service.ResolveProxy(test_url, std::string(), &info,
-                                  callback.callback(), nullptr, nullptr,
+                                  callback.callback(), &request, nullptr,
                                   NetLogWithSource());
     ASSERT_THAT(rv, IsOk());
     // Should be test, even if there are no HTTP proxies configured.
@@ -1708,7 +2077,7 @@
     ProxyInfo info;
     TestCompletionCallback callback;
     int rv = service.ResolveProxy(test_url, std::string(), &info,
-                                  callback.callback(), nullptr, nullptr,
+                                  callback.callback(), &request, nullptr,
                                   NetLogWithSource());
     ASSERT_THAT(rv, IsOk());
     // Used the HTTPS proxy. So traffic annotation should test.
@@ -1723,7 +2092,7 @@
     ProxyInfo info;
     TestCompletionCallback callback;
     int rv = service.ResolveProxy(test_url, std::string(), &info,
-                                  callback.callback(), nullptr, nullptr,
+                                  callback.callback(), &request, nullptr,
                                   NetLogWithSource());
     ASSERT_THAT(rv, IsOk());
     // ProxyConfig is empty. Traffic annotation should still be TEST.
@@ -1741,6 +2110,7 @@
   EXPECT_EQ(ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
             config.proxy_rules().type);
 
+  std::unique_ptr<ProxyResolutionService::Request> request;
   {
     ProxyResolutionService service(
         std::make_unique<MockProxyConfigService>(config), nullptr, nullptr);
@@ -1748,7 +2118,7 @@
     ProxyInfo info;
     TestCompletionCallback callback;
     int rv = service.ResolveProxy(test_url, std::string(), &info,
-                                  callback.callback(), nullptr, nullptr,
+                                  callback.callback(), &request, nullptr,
                                   NetLogWithSource());
     EXPECT_THAT(rv, IsOk());
     EXPECT_FALSE(info.is_direct());
@@ -1761,7 +2131,7 @@
     ProxyInfo info;
     TestCompletionCallback callback;
     int rv = service.ResolveProxy(test_url, std::string(), &info,
-                                  callback.callback(), nullptr, nullptr,
+                                  callback.callback(), &request, nullptr,
                                   NetLogWithSource());
     EXPECT_THAT(rv, IsOk());
     EXPECT_FALSE(info.is_direct());
@@ -1774,7 +2144,7 @@
     ProxyInfo info;
     TestCompletionCallback callback;
     int rv = service.ResolveProxy(test_url, std::string(), &info,
-                                  callback.callback(), nullptr, nullptr,
+                                  callback.callback(), &request, nullptr,
                                   NetLogWithSource());
     EXPECT_THAT(rv, IsOk());
     EXPECT_FALSE(info.is_direct());
@@ -1787,7 +2157,7 @@
     ProxyInfo info;
     TestCompletionCallback callback;
     int rv = service.ResolveProxy(test_url, std::string(), &info,
-                                  callback.callback(), nullptr, nullptr,
+                                  callback.callback(), &request, nullptr,
                                   NetLogWithSource());
     EXPECT_THAT(rv, IsOk());
     EXPECT_FALSE(info.is_direct());
@@ -1814,9 +2184,10 @@
 
   ProxyInfo info1;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv =
       service.ResolveProxy(url1, std::string(), &info1, callback1.callback(),
-                           nullptr, nullptr, NetLogWithSource());
+                           &request1, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   // Successfully initialize the PAC script.
@@ -1828,7 +2199,7 @@
 
   ProxyInfo info2;
   TestCompletionCallback callback2;
-  ProxyResolutionService::Request* request2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
   rv = service.ResolveProxy(url2, std::string(), &info2, callback2.callback(),
                             &request2, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
@@ -1837,13 +2208,14 @@
 
   ProxyInfo info3;
   TestCompletionCallback callback3;
+  std::unique_ptr<ProxyResolutionService::Request> request3;
   rv = service.ResolveProxy(url3, std::string(), &info3, callback3.callback(),
-                            nullptr, nullptr, NetLogWithSource());
+                            &request3, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
   GetPendingJobsForURLs(resolver, url1, url2, url3);
 
   // Cancel the second request
-  service.CancelRequest(request2);
+  request2.reset();
 
   JobMap jobs = GetPendingJobsForURLs(resolver, url1, url3);
 
@@ -1888,7 +2260,7 @@
 
   ProxyInfo info1;
   TestCompletionCallback callback1;
-  ProxyResolutionService::Request* request1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv =
       service.ResolveProxy(url1, std::string(), &info1, callback1.callback(),
                            &request1, nullptr, NetLogWithSource());
@@ -1900,14 +2272,14 @@
 
   ProxyInfo info2;
   TestCompletionCallback callback2;
-  ProxyResolutionService::Request* request2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
   rv = service.ResolveProxy(url2, std::string(), &info2, callback2.callback(),
                             &request2, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   ProxyInfo info3;
   TestCompletionCallback callback3;
-  ProxyResolutionService::Request* request3;
+  std::unique_ptr<ProxyResolutionService::Request> request3;
   rv = service.ResolveProxy(url3, std::string(), &info3, callback3.callback(),
                             &request3, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
@@ -1915,9 +2287,9 @@
   // Nothing has been sent to the factory yet.
   EXPECT_TRUE(factory->pending_requests().empty());
 
-  EXPECT_EQ(LOAD_STATE_DOWNLOADING_PAC_FILE, service.GetLoadState(request1));
-  EXPECT_EQ(LOAD_STATE_DOWNLOADING_PAC_FILE, service.GetLoadState(request2));
-  EXPECT_EQ(LOAD_STATE_DOWNLOADING_PAC_FILE, service.GetLoadState(request3));
+  EXPECT_EQ(LOAD_STATE_DOWNLOADING_PAC_FILE, request1->GetLoadState());
+  EXPECT_EQ(LOAD_STATE_DOWNLOADING_PAC_FILE, request2->GetLoadState());
+  EXPECT_EQ(LOAD_STATE_DOWNLOADING_PAC_FILE, request3->GetLoadState());
 
   // At this point the ProxyResolutionService should be waiting for the
   // PacFileFetcher to invoke its completion callback, notifying it of
@@ -1932,9 +2304,9 @@
 
   JobMap jobs = GetPendingJobsForURLs(resolver, url1, url2, url3);
 
-  EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, service.GetLoadState(request1));
-  EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, service.GetLoadState(request2));
-  EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, service.GetLoadState(request3));
+  EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, request1->GetLoadState());
+  EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, request2->GetLoadState());
+  EXPECT_EQ(LOAD_STATE_RESOLVING_PROXY_FOR_URL, request3->GetLoadState());
 
   // Complete all the jobs (in some order).
 
@@ -1993,9 +2365,10 @@
 
   ProxyInfo info1;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv =
       service.ResolveProxy(url1, std::string(), &info1, callback1.callback(),
-                           nullptr, nullptr, NetLogWithSource());
+                           &request1, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   // The first request should have triggered download of PAC script.
@@ -2004,8 +2377,9 @@
 
   ProxyInfo info2;
   TestCompletionCallback callback2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
   rv = service.ResolveProxy(url2, std::string(), &info2, callback2.callback(),
-                            nullptr, nullptr, NetLogWithSource());
+                            &request2, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   // At this point the ProxyResolutionService should be waiting for the
@@ -2052,7 +2426,7 @@
   // Start 3 requests.
   ProxyInfo info1;
   TestCompletionCallback callback1;
-  ProxyResolutionService::Request* request1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   BoundTestNetLog log1;
   int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1,
                                 callback1.callback(), &request1, nullptr,
@@ -2065,7 +2439,7 @@
 
   ProxyInfo info2;
   TestCompletionCallback callback2;
-  ProxyResolutionService::Request* request2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
   rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2,
                             callback2.callback(), &request2, nullptr,
                             NetLogWithSource());
@@ -2073,8 +2447,9 @@
 
   ProxyInfo info3;
   TestCompletionCallback callback3;
+  std::unique_ptr<ProxyResolutionService::Request> request3;
   rv = service.ResolveProxy(GURL("http://request3"), std::string(), &info3,
-                            callback3.callback(), nullptr, nullptr,
+                            callback3.callback(), &request3, nullptr,
                             NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -2082,8 +2457,8 @@
   EXPECT_TRUE(factory->pending_requests().empty());
 
   // Cancel the first 2 jobs.
-  service.CancelRequest(request1);
-  service.CancelRequest(request2);
+  request1.reset();
+  request2.reset();
 
   // At this point the ProxyResolutionService should be waiting for the
   // PacFileFetcher to invoke its completion callback, notifying it of
@@ -2153,14 +2528,15 @@
 
   ProxyInfo info1;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv =
       service.ResolveProxy(url1, std::string(), &info1, callback1.callback(),
-                           nullptr, nullptr, NetLogWithSource());
+                           &request1, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   ProxyInfo info2;
   TestCompletionCallback callback2;
-  ProxyResolutionService::Request* request2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
   rv = service.ResolveProxy(url2, std::string(), &info2, callback2.callback(),
                             &request2, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
@@ -2236,14 +2612,15 @@
 
   ProxyInfo info1;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv =
       service.ResolveProxy(url1, std::string(), &info1, callback1.callback(),
-                           nullptr, nullptr, NetLogWithSource());
+                           &request1, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   ProxyInfo info2;
   TestCompletionCallback callback2;
-  ProxyResolutionService::Request* request2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
   rv = service.ResolveProxy(url2, std::string(), &info2, callback2.callback(),
                             &request2, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
@@ -2312,14 +2689,15 @@
 
   ProxyInfo info1;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1,
-                                callback1.callback(), nullptr, nullptr,
+                                callback1.callback(), &request1, nullptr,
                                 NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   ProxyInfo info2;
   TestCompletionCallback callback2;
-  ProxyResolutionService::Request* request2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
   rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2,
                             callback2.callback(), &request2, nullptr,
                             NetLogWithSource());
@@ -2374,9 +2752,10 @@
 
   ProxyInfo info1;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv = service.ResolveProxy(GURL("http://www.google.com"), std::string(),
-                                &info1, callback1.callback(), nullptr, nullptr,
-                                NetLogWithSource());
+                                &info1, callback1.callback(), &request1,
+                                nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   // Check that nothing has been sent to the proxy resolver factory yet.
@@ -2405,8 +2784,9 @@
   // Start another request, it should pickup the bypass item.
   ProxyInfo info2;
   TestCompletionCallback callback2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
   rv = service.ResolveProxy(GURL("http://www.google.com"), std::string(),
-                            &info2, callback2.callback(), nullptr, nullptr,
+                            &info2, callback2.callback(), &request2, nullptr,
                             NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -2444,9 +2824,10 @@
 
   ProxyInfo info1;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv = service.ResolveProxy(GURL("http://www.google.com"), std::string(),
-                                &info1, callback1.callback(), nullptr, nullptr,
-                                NetLogWithSource());
+                                &info1, callback1.callback(), &request1,
+                                nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   // Check that nothing has been sent to the proxy resolver factory yet.
@@ -2477,8 +2858,9 @@
 
   ProxyInfo info;
   TestCompletionCallback callback;
+  std::unique_ptr<ProxyResolutionService::Request> request;
   int rv = service.ResolveProxy(url, std::string(), &info, callback.callback(),
-                                nullptr, nullptr, NetLogWithSource());
+                                &request, nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   EXPECT_EQ(GURL("http://foopy/proxy.pac"),
@@ -2494,8 +2876,9 @@
 
   ProxyInfo info;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info,
-                                callback1.callback(), nullptr, nullptr,
+                                callback1.callback(), &request1, nullptr,
                                 NetLogWithSource());
   EXPECT_THAT(rv, IsOk());
   EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
@@ -2505,8 +2888,9 @@
   config2.set_auto_detect(false);
   service.ResetConfigService(std::make_unique<MockProxyConfigService>(config2));
   TestCompletionCallback callback2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
   rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info,
-                            callback2.callback(), nullptr, nullptr,
+                            callback2.callback(), &request2, nullptr,
                             NetLogWithSource());
   EXPECT_THAT(rv, IsOk());
   EXPECT_EQ("foopy2:8080", info.proxy_server().ToURI());
@@ -2528,9 +2912,10 @@
 
   ProxyInfo info1;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv = service.ResolveProxy(GURL("http://www.google.com"), std::string(),
-                                &info1, callback1.callback(), nullptr, nullptr,
-                                NetLogWithSource());
+                                &info1, callback1.callback(), &request1,
+                                nullptr, NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
   // Successfully set the autodetect script.
@@ -2557,8 +2942,9 @@
   // Start another request -- the effective configuration has changed.
   ProxyInfo info2;
   TestCompletionCallback callback2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
   rv = service.ResolveProxy(GURL("http://www.google.com"), std::string(),
-                            &info2, callback2.callback(), nullptr, nullptr,
+                            &info2, callback2.callback(), &request2, nullptr,
                             NetLogWithSource());
   EXPECT_THAT(rv, IsOk());
 
@@ -2590,8 +2976,9 @@
 
   ProxyInfo info1;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1,
-                                callback1.callback(), nullptr, nullptr,
+                                callback1.callback(), &request1, nullptr,
                                 NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -2633,8 +3020,9 @@
   // Start a second request.
   ProxyInfo info2;
   TestCompletionCallback callback2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
   rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2,
-                            callback2.callback(), nullptr, nullptr,
+                            callback2.callback(), &request2, nullptr,
                             NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -2708,8 +3096,9 @@
 
   ProxyInfo info1;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1,
-                                callback1.callback(), nullptr, nullptr,
+                                callback1.callback(), &request1, nullptr,
                                 NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -2769,8 +3158,9 @@
   // Start a second request.
   ProxyInfo info2;
   TestCompletionCallback callback2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
   rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2,
-                            callback2.callback(), nullptr, nullptr,
+                            callback2.callback(), &request2, nullptr,
                             NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -2815,8 +3205,9 @@
 
   ProxyInfo info1;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1,
-                                callback1.callback(), nullptr, nullptr,
+                                callback1.callback(), &request1, nullptr,
                                 NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -2882,8 +3273,9 @@
   // Start a second request.
   ProxyInfo info2;
   TestCompletionCallback callback2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
   rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2,
-                            callback2.callback(), nullptr, nullptr,
+                            callback2.callback(), &request2, nullptr,
                             NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -2928,8 +3320,9 @@
 
   ProxyInfo info1;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1,
-                                callback1.callback(), nullptr, nullptr,
+                                callback1.callback(), &request1, nullptr,
                                 NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -2992,8 +3385,9 @@
   // Start a second request.
   ProxyInfo info2;
   TestCompletionCallback callback2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
   rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2,
-                            callback2.callback(), nullptr, nullptr,
+                            callback2.callback(), &request2, nullptr,
                             NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -3038,8 +3432,9 @@
 
   ProxyInfo info1;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1,
-                                callback1.callback(), nullptr, nullptr,
+                                callback1.callback(), &request1, nullptr,
                                 NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -3099,8 +3494,9 @@
   // Start a second request.
   ProxyInfo info2;
   TestCompletionCallback callback2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
   rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2,
-                            callback2.callback(), nullptr, nullptr,
+                            callback2.callback(), &request2, nullptr,
                             NetLogWithSource());
   EXPECT_THAT(rv, IsOk());
   EXPECT_TRUE(info2.is_direct());
@@ -3201,8 +3597,9 @@
 
   ProxyInfo info1;
   TestCompletionCallback callback1;
+  std::unique_ptr<ProxyResolutionService::Request> request1;
   int rv = service.ResolveProxy(GURL("http://request1"), std::string(), &info1,
-                                callback1.callback(), nullptr, nullptr,
+                                callback1.callback(), &request1, nullptr,
                                 NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -3246,8 +3643,9 @@
   // Start a second request.
   ProxyInfo info2;
   TestCompletionCallback callback2;
+  std::unique_ptr<ProxyResolutionService::Request> request2;
   rv = service.ResolveProxy(GURL("http://request2"), std::string(), &info2,
-                            callback2.callback(), nullptr, nullptr,
+                            callback2.callback(), &request2, nullptr,
                             NetLogWithSource());
   EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -3277,8 +3675,9 @@
   // since the PAC script poller experienced a failure.
   ProxyInfo info3;
   TestCompletionCallback callback3;
+  std::unique_ptr<ProxyResolutionService::Request> request3;
   rv = service.ResolveProxy(GURL("http://request3"), std::string(), &info3,
-                            callback3.callback(), nullptr, nullptr,
+                            callback3.callback(), &request3, nullptr,
                             NetLogWithSource());
   EXPECT_THAT(rv, IsOk());
   EXPECT_TRUE(info3.is_direct());
@@ -3359,9 +3758,10 @@
 
     ProxyInfo info;
     TestCompletionCallback callback;
+    std::unique_ptr<ProxyResolutionService::Request> request;
     int rv =
         service_->ResolveProxy(url, std::string(), &info, callback.callback(),
-                               nullptr, nullptr, NetLogWithSource());
+                               &request, nullptr, NetLogWithSource());
     EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
     // First step is to download the PAC script.
@@ -3391,8 +3791,9 @@
     // Issue a request and see what URL is sent to the proxy resolver.
     ProxyInfo info;
     TestCompletionCallback callback;
+    std::unique_ptr<ProxyResolutionService::Request> request1;
     int rv = service_->ResolveProxy(raw_url, std::string(), &info,
-                                    callback.callback(), nullptr, nullptr,
+                                    callback.callback(), &request1, nullptr,
                                     NetLogWithSource());
     EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
 
@@ -3575,7 +3976,7 @@
 
   ProxyInfo info;
   TestCompletionCallback callback;
-  ProxyResolutionService::Request* request;
+  std::unique_ptr<ProxyResolutionService::Request> request;
   int rv = service.ResolveProxy(GURL("http://request/"), std::string(), &info,
                                 callback.callback(), &request, nullptr,
                                 NetLogWithSource());
@@ -3610,7 +4011,7 @@
 
   ProxyInfo info;
   TestCompletionCallback callback;
-  ProxyResolutionService::Request* request;
+  std::unique_ptr<ProxyResolutionService::Request> request;
   int rv = service.ResolveProxy(GURL("http://request/"), std::string(), &info,
                                 callback.callback(), &request, nullptr,
                                 NetLogWithSource());
diff --git a/net/socket/udp_socket_posix.cc b/net/socket/udp_socket_posix.cc
index 7605385..cb98312 100644
--- a/net/socket/udp_socket_posix.cc
+++ b/net/socket/udp_socket_posix.cc
@@ -1023,8 +1023,9 @@
     case IPAddress::kIPv4AddressSize: {
       if (addr_family_ != AF_INET)
         return ERR_ADDRESS_INVALID;
-      ip_mreq mreq = {};
-      mreq.imr_interface.s_addr = INADDR_ANY;
+      ip_mreqn mreq = {};
+      mreq.imr_ifindex = multicast_interface_;
+      mreq.imr_address.s_addr = INADDR_ANY;
       memcpy(&mreq.imr_multiaddr, group_address.bytes().data(),
              IPAddress::kIPv4AddressSize);
       int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP,
diff --git a/net/third_party/quic/core/http/end_to_end_test.cc b/net/third_party/quic/core/http/end_to_end_test.cc
index 947afcb..df26fb2b8 100644
--- a/net/third_party/quic/core/http/end_to_end_test.cc
+++ b/net/third_party/quic/core/http/end_to_end_test.cc
@@ -11,7 +11,6 @@
 #include <utility>
 #include <vector>
 
-#include "net/test/test_with_scoped_task_environment.h"
 #include "net/third_party/quic/core/crypto/null_encrypter.h"
 #include "net/third_party/quic/core/http/quic_spdy_client_stream.h"
 #include "net/third_party/quic/core/quic_epoll_connection_helper.h"
@@ -263,8 +262,7 @@
   QuicClient* client_;
 };
 
-class EndToEndTest : public QuicTestWithParam<TestParams>,
-                     public net::WithScopedTaskEnvironment {
+class EndToEndTest : public QuicTestWithParam<TestParams> {
  protected:
   EndToEndTest()
       : initialized_(false),
@@ -594,6 +592,7 @@
         *client_->client()->client_session(), n);
   }
 
+  ScopedEnvironmentForThreads environment_;
   bool initialized_;
   QuicSocketAddress server_address_;
   QuicString server_hostname_;
diff --git a/net/third_party/quic/platform/api/quic_test.h b/net/third_party/quic/platform/api/quic_test.h
index 5f0f3c5..979c785 100644
--- a/net/third_party/quic/platform/api/quic_test.h
+++ b/net/third_party/quic/platform/api/quic_test.h
@@ -14,4 +14,7 @@
 template <class T>
 using QuicTestWithParam = QuicTestWithParamImpl<T>;
 
+// Class which needs to be instantiated in tests which use threads.
+using ScopedEnvironmentForThreads = ScopedEnvironmentForThreadsImpl;
+
 #endif  // NET_THIRD_PARTY_QUIC_PLATFORM_API_QUIC_TEST_H_
diff --git a/net/third_party/quic/platform/impl/quic_test_impl.h b/net/third_party/quic/platform/impl/quic_test_impl.h
index fe743104..1117842 100644
--- a/net/third_party/quic/platform/impl/quic_test_impl.h
+++ b/net/third_party/quic/platform/impl/quic_test_impl.h
@@ -7,6 +7,7 @@
 
 #include "base/logging.h"
 #include "net/third_party/quic/platform/api/quic_flags.h"
+#include "net/test/test_with_scoped_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"  // IWYU pragma: export
 #include "testing/gtest/include/gtest/gtest.h"  // IWYU pragma: export
 
@@ -50,4 +51,14 @@
   QuicFlagSaverImpl saver_;  // Save/restore all QUIC flag values.
 };
 
+class ScopedEnvironmentForThreadsImpl {
+ public:
+  ScopedEnvironmentForThreadsImpl()
+      : scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
+
+ public:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+};
+
 #endif  // NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_TEST_IMPL_H_
diff --git a/net/third_party/quic/quartc/quartc_clock_interface.h b/net/third_party/quic/quartc/quartc_clock_interface.h
deleted file mode 100644
index 53366d70..0000000
--- a/net/third_party/quic/quartc/quartc_clock_interface.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 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 NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_CLOCK_INTERFACE_H_
-#define NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_CLOCK_INTERFACE_H_
-
-#include <stdint.h>
-
-namespace quic {
-
-// Implemented by the Quartc API user to provide a timebase.
-class QuartcClockInterface {
- public:
-  virtual ~QuartcClockInterface() {}
-  virtual int64_t NowMicroseconds() = 0;
-};
-
-}  // namespace quic
-
-#endif  // NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_CLOCK_INTERFACE_H_
diff --git a/net/third_party/quic/quartc/quartc_factory.cc b/net/third_party/quic/quartc/quartc_factory.cc
index 099808c..e5e0287e 100644
--- a/net/third_party/quic/quartc/quartc_factory.cc
+++ b/net/third_party/quic/quartc/quartc_factory.cc
@@ -11,106 +11,17 @@
 
 namespace quic {
 
-namespace {
-
-// Implements the QuicAlarm with QuartcTaskRunnerInterface for the Quartc
-//  users other than Chromium. For example, WebRTC will create QuartcAlarm with
-// a QuartcTaskRunner implemented by WebRTC.
-class QuartcAlarm : public QuicAlarm, public QuartcTaskRunnerInterface::Task {
- public:
-  QuartcAlarm(const QuicClock* clock,
-              QuartcTaskRunnerInterface* task_runner,
-              QuicArenaScopedPtr<QuicAlarm::Delegate> delegate)
-      : QuicAlarm(std::move(delegate)),
-        clock_(clock),
-        task_runner_(task_runner) {}
-
-  ~QuartcAlarm() override {
-    // Cancel the scheduled task before getting deleted.
-    CancelImpl();
-  }
-
-  // QuicAlarm overrides.
-  void SetImpl() override {
-    DCHECK(deadline().IsInitialized());
-    // Cancel it if already set.
-    CancelImpl();
-
-    int64_t delay_ms = (deadline() - (clock_->Now())).ToMilliseconds();
-    if (delay_ms < 0) {
-      delay_ms = 0;
-    }
-
-    DCHECK(task_runner_);
-    DCHECK(!scheduled_task_);
-    scheduled_task_ = task_runner_->Schedule(this, delay_ms);
-  }
-
-  void CancelImpl() override {
-    if (scheduled_task_) {
-      scheduled_task_->Cancel();
-      scheduled_task_.reset();
-    }
-  }
-
-  // QuartcTaskRunner::Task overrides.
-  void Run() override {
-    // The alarm may have been cancelled.
-    if (!deadline().IsInitialized()) {
-      return;
-    }
-
-    // The alarm may have been re-set to a later time.
-    if (clock_->Now() < deadline()) {
-      SetImpl();
-      return;
-    }
-
-    Fire();
-  }
-
- private:
-  // Not owned by QuartcAlarm. Owned by the QuartcFactory.
-  const QuicClock* clock_;
-  // Not owned by QuartcAlarm. Owned by the QuartcFactory.
-  QuartcTaskRunnerInterface* task_runner_;
-  // Owned by QuartcAlarm.
-  std::unique_ptr<QuartcTaskRunnerInterface::ScheduledTask> scheduled_task_;
-};
-
-// Adapts QuartcClockInterface (provided by the user) to QuicClock
-// (expected by QUIC).
-class QuartcClock : public QuicClock {
- public:
-  explicit QuartcClock(QuartcClockInterface* clock) : clock_(clock) {}
-  QuicTime ApproximateNow() const override { return Now(); }
-  QuicTime Now() const override {
-    return QuicTime::Zero() +
-           QuicTime::Delta::FromMicroseconds(clock_->NowMicroseconds());
-  }
-  QuicWallTime WallNow() const override {
-    return QuicWallTime::FromUNIXMicroseconds(clock_->NowMicroseconds());
-  }
-
- private:
-  QuartcClockInterface* clock_;
-};
-
-}  // namespace
-
 QuartcFactory::QuartcFactory(const QuartcFactoryConfig& factory_config)
-    : task_runner_(factory_config.task_runner),
-      clock_(new QuartcClock(factory_config.clock)) {}
+    : alarm_factory_(factory_config.alarm_factory),
+      clock_(factory_config.clock) {}
 
 QuartcFactory::~QuartcFactory() {}
 
-std::unique_ptr<QuartcSessionInterface> QuartcFactory::CreateQuartcSession(
+std::unique_ptr<QuartcSession> QuartcFactory::CreateQuartcSession(
     const QuartcSessionConfig& quartc_session_config) {
   DCHECK(quartc_session_config.packet_transport);
 
-  Perspective perspective = quartc_session_config.is_server
-                                ? Perspective::IS_SERVER
-                                : Perspective::IS_CLIENT;
+  Perspective perspective = quartc_session_config.perspective;
 
   // QuartcSession will eventually own both |writer| and |quic_connection|.
   auto writer =
@@ -135,53 +46,50 @@
   // Enable time-based loss detection.
   copt.push_back(kTIME);
 
-  if (quartc_session_config.congestion_control ==
-      QuartcCongestionControl::kBBR) {
-    copt.push_back(kTBBR);
+  copt.push_back(kTBBR);
 
-    // Note: These settings have no effect for Exoblaze builds since
-    // SetQuicReloadableFlag() gets stubbed out.
-    SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true);
-    SetQuicReloadableFlag(quic_unified_iw_options, true);
-    for (const auto option : quartc_session_config.bbr_options) {
-      switch (option) {
-        case (QuartcBbrOptions::kSlowerStartup):
-          copt.push_back(kBBRS);
-          break;
-        case (QuartcBbrOptions::kFullyDrainQueue):
-          copt.push_back(kBBR3);
-          break;
-        case (QuartcBbrOptions::kReduceProbeRtt):
-          copt.push_back(kBBR6);
-          break;
-        case (QuartcBbrOptions::kSkipProbeRtt):
-          copt.push_back(kBBR7);
-          break;
-        case (QuartcBbrOptions::kSkipProbeRttAggressively):
-          copt.push_back(kBBR8);
-          break;
-        case (QuartcBbrOptions::kFillUpLinkDuringProbing):
-          quic_connection->set_fill_up_link_during_probing(true);
-          break;
-        case (QuartcBbrOptions::kInitialWindow3):
-          copt.push_back(kIW03);
-          break;
-        case (QuartcBbrOptions::kInitialWindow10):
-          copt.push_back(kIW10);
-          break;
-        case (QuartcBbrOptions::kInitialWindow20):
-          copt.push_back(kIW20);
-          break;
-        case (QuartcBbrOptions::kInitialWindow50):
-          copt.push_back(kIW50);
-          break;
-        case (QuartcBbrOptions::kStartup1RTT):
-          copt.push_back(k1RTT);
-          break;
-        case (QuartcBbrOptions::kStartup2RTT):
-          copt.push_back(k2RTT);
-          break;
-      }
+  // Note: These settings have no effect for Exoblaze builds since
+  // SetQuicReloadableFlag() gets stubbed out.
+  SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true);
+  SetQuicReloadableFlag(quic_unified_iw_options, true);
+  for (const auto option : quartc_session_config.bbr_options) {
+    switch (option) {
+      case (QuartcBbrOptions::kSlowerStartup):
+        copt.push_back(kBBRS);
+        break;
+      case (QuartcBbrOptions::kFullyDrainQueue):
+        copt.push_back(kBBR3);
+        break;
+      case (QuartcBbrOptions::kReduceProbeRtt):
+        copt.push_back(kBBR6);
+        break;
+      case (QuartcBbrOptions::kSkipProbeRtt):
+        copt.push_back(kBBR7);
+        break;
+      case (QuartcBbrOptions::kSkipProbeRttAggressively):
+        copt.push_back(kBBR8);
+        break;
+      case (QuartcBbrOptions::kFillUpLinkDuringProbing):
+        quic_connection->set_fill_up_link_during_probing(true);
+        break;
+      case (QuartcBbrOptions::kInitialWindow3):
+        copt.push_back(kIW03);
+        break;
+      case (QuartcBbrOptions::kInitialWindow10):
+        copt.push_back(kIW10);
+        break;
+      case (QuartcBbrOptions::kInitialWindow20):
+        copt.push_back(kIW20);
+        break;
+      case (QuartcBbrOptions::kInitialWindow50):
+        copt.push_back(kIW50);
+        break;
+      case (QuartcBbrOptions::kStartup1RTT):
+        copt.push_back(k1RTT);
+        break;
+      case (QuartcBbrOptions::kStartup2RTT):
+        copt.push_back(k2RTT);
+        break;
     }
   }
   QuicConfig quic_config;
@@ -202,15 +110,15 @@
       kStreamReceiveWindowLimit);
   quic_config.SetConnectionOptionsToSend(copt);
   quic_config.SetClientConnectionOptions(copt);
-  if (quartc_session_config.max_time_before_crypto_handshake_secs > 0) {
+  if (quartc_session_config.max_time_before_crypto_handshake >
+      QuicTime::Delta::Zero()) {
     quic_config.set_max_time_before_crypto_handshake(
-        QuicTime::Delta::FromSeconds(
-            quartc_session_config.max_time_before_crypto_handshake_secs));
+        quartc_session_config.max_time_before_crypto_handshake);
   }
-  if (quartc_session_config.max_idle_time_before_crypto_handshake_secs > 0) {
+  if (quartc_session_config.max_idle_time_before_crypto_handshake >
+      QuicTime::Delta::Zero()) {
     quic_config.set_max_idle_time_before_crypto_handshake(
-        QuicTime::Delta::FromSeconds(
-            quartc_session_config.max_idle_time_before_crypto_handshake_secs));
+        quartc_session_config.max_idle_time_before_crypto_handshake);
   }
   if (quartc_session_config.idle_network_timeout > QuicTime::Delta::Zero()) {
     quic_config.SetIdleNetworkTimeout(
@@ -224,7 +132,7 @@
   return QuicMakeUnique<QuartcSession>(
       std::move(quic_connection), quic_config,
       quartc_session_config.unique_remote_server_id, perspective,
-      this /*QuicConnectionHelperInterface*/, clock_.get(), std::move(writer));
+      this /*QuicConnectionHelperInterface*/, clock_, std::move(writer));
 }
 
 std::unique_ptr<QuicConnection> QuartcFactory::CreateQuicConnection(
@@ -236,28 +144,12 @@
   QuicSocketAddress dummy_address(QuicIpAddress::Any4(), 0 /*Port*/);
   return QuicMakeUnique<QuicConnection>(
       dummy_id, dummy_address, this, /*QuicConnectionHelperInterface*/
-      this /*QuicAlarmFactory*/, packet_writer, /*owns_writer=*/false,
+      alarm_factory_ /*QuicAlarmFactory*/, packet_writer, /*owns_writer=*/false,
       perspective, CurrentSupportedVersions());
 }
 
-QuicAlarm* QuartcFactory::CreateAlarm(QuicAlarm::Delegate* delegate) {
-  return new QuartcAlarm(GetClock(), task_runner_,
-                         QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate));
-}
-
-QuicArenaScopedPtr<QuicAlarm> QuartcFactory::CreateAlarm(
-    QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
-    QuicConnectionArena* arena) {
-  if (arena != nullptr) {
-    return arena->New<QuartcAlarm>(GetClock(), task_runner_,
-                                   std::move(delegate));
-  }
-  return QuicArenaScopedPtr<QuicAlarm>(
-      new QuartcAlarm(GetClock(), task_runner_, std::move(delegate)));
-}
-
 const QuicClock* QuartcFactory::GetClock() const {
-  return clock_.get();
+  return clock_;
 }
 
 QuicRandom* QuartcFactory::GetRandomGenerator() {
@@ -268,10 +160,9 @@
   return &buffer_allocator_;
 }
 
-std::unique_ptr<QuartcFactoryInterface> CreateQuartcFactory(
+std::unique_ptr<QuartcFactory> CreateQuartcFactory(
     const QuartcFactoryConfig& factory_config) {
-  return std::unique_ptr<QuartcFactoryInterface>(
-      new QuartcFactory(factory_config));
+  return std::unique_ptr<QuartcFactory>(new QuartcFactory(factory_config));
 }
 
 }  // namespace quic
diff --git a/net/third_party/quic/quartc/quartc_factory.h b/net/third_party/quic/quartc/quartc_factory.h
index f56c2499..8db0340 100644
--- a/net/third_party/quic/quartc/quartc_factory.h
+++ b/net/third_party/quic/quartc/quartc_factory.h
@@ -8,34 +8,83 @@
 #include "net/third_party/quic/core/quic_alarm_factory.h"
 #include "net/third_party/quic/core/quic_connection.h"
 #include "net/third_party/quic/core/quic_simple_buffer_allocator.h"
-#include "net/third_party/quic/platform/api/quic_export.h"
-#include "net/third_party/quic/quartc/quartc_factory_interface.h"
 #include "net/third_party/quic/quartc/quartc_packet_writer.h"
-#include "net/third_party/quic/quartc/quartc_task_runner_interface.h"
+#include "net/third_party/quic/quartc/quartc_session.h"
 
 namespace quic {
 
-// Implements the QuartcFactoryInterface to create the instances of
-// QuartcSessionInterface. Implements the QuicAlarmFactory to create alarms
-// using the QuartcTaskRunner. Implements the QuicConnectionHelperInterface used
-// by the QuicConnections. Only one QuartcFactory is expected to be created.
-class QUIC_EXPORT_PRIVATE QuartcFactory : public QuartcFactoryInterface,
-                                          public QuicAlarmFactory,
-                                          public QuicConnectionHelperInterface {
+// Options that control the BBR algorithm.
+enum class QuartcBbrOptions {
+  kSlowerStartup,    // Once a loss is encountered in STARTUP,
+                     // switches startup to a 1.5x pacing gain.
+  kFullyDrainQueue,  // Fully drains the queue once per cycle.
+  kReduceProbeRtt,   // Probe RTT reduces CWND to 0.75 * BDP instead of 4
+                     // packets.
+  kSkipProbeRtt,     // Skip Probe RTT and extend the existing min_rtt if a
+                     // recent min_rtt is within 12.5% of the current min_rtt.
+  kSkipProbeRttAggressively,  //  Skip ProbeRTT and extend the existing min_rtt
+                              //  as long as you've been app limited at least
+                              //  once.
+  kFillUpLinkDuringProbing,   // Sends probing retransmissions whenever we
+                              // become application limited.
+  kInitialWindow3,            // Use a 3-packet initial congestion window.
+  kInitialWindow10,           // Use a 10-packet initial congestion window.
+  kInitialWindow20,           // Use a 20-packet initial congestion window.
+  kInitialWindow50,           // Use a 50-packet initial congestion window.
+  kStartup1RTT,               // Stay in STARTUP for 1 RTT.
+  kStartup2RTT,               // Stay in STARTUP for 2 RTTs.
+};
+
+// The configuration for creating a QuartcFactory.
+struct QuartcFactoryConfig {
+  // Factory for |QuicAlarm|s. Implemented by the Quartc user with different
+  // mechanisms. For example in WebRTC, it is implemented with rtc::Thread.
+  // Owned by the user, and needs to stay alive for as long as the QuartcFactory
+  // exists.
+  QuicAlarmFactory* alarm_factory = nullptr;
+  // The clock used by |QuicAlarm|s. Implemented by the Quartc user. Owned by
+  // the user, and needs to stay alive for as long as the QuartcFactory exists.
+  QuicClock* clock = nullptr;
+};
+
+struct QuartcSessionConfig {
+  // When using Quartc, there are two endpoints. The QuartcSession on one
+  // endpoint must act as a server and the one on the other side must act as a
+  // client.
+  Perspective perspective = Perspective::IS_CLIENT;
+  // This is only needed when is_server = false.  It must be unique
+  // for each endpoint the local endpoint may communicate with. For example,
+  // a WebRTC client could use the remote endpoint's crypto fingerprint
+  QuicString unique_remote_server_id;
+  // The way the QuicConnection will send and receive packets, like a virtual
+  // UDP socket. For WebRTC, this will typically be an IceTransport.
+  QuartcPacketTransport* packet_transport = nullptr;
+  // The maximum size of the packet can be written with the packet writer.
+  // 1200 bytes by default.
+  QuicPacketLength max_packet_size = 1200;
+  // Options to control the BBR algorithm. In case the congestion control is
+  // set to anything but BBR, these options are ignored.
+  std::vector<QuartcBbrOptions> bbr_options;
+  // Timeouts for the crypto handshake. Set them to higher values to
+  // prevent closing the session before it started on a slow network.
+  // Zero entries are ignored and QUIC defaults are used in that case.
+  QuicTime::Delta max_idle_time_before_crypto_handshake =
+      QuicTime::Delta::Zero();
+  QuicTime::Delta max_time_before_crypto_handshake = QuicTime::Delta::Zero();
+  QuicTime::Delta idle_network_timeout = QuicTime::Delta::Zero();
+};
+
+// Factory that creates instances of QuartcSession.  Implements the
+// QuicConnectionHelperInterface used by the QuicConnections. Only one
+// QuartcFactory is expected to be created.
+class QUIC_EXPORT_PRIVATE QuartcFactory : public QuicConnectionHelperInterface {
  public:
   explicit QuartcFactory(const QuartcFactoryConfig& factory_config);
   ~QuartcFactory() override;
 
-  // QuartcFactoryInterface overrides.
-  std::unique_ptr<QuartcSessionInterface> CreateQuartcSession(
-      const QuartcSessionConfig& quartc_session_config) override;
-
-  // QuicAlarmFactory overrides.
-  QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override;
-
-  QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
-      QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
-      QuicConnectionArena* arena) override;
+  // Creates a new QuartcSession using the given configuration.
+  std::unique_ptr<QuartcSession> CreateQuartcSession(
+      const QuartcSessionConfig& quartc_session_config);
 
   // QuicConnectionHelperInterface overrides.
   const QuicClock* GetClock() const override;
@@ -49,15 +98,19 @@
       Perspective perspective,
       QuartcPacketWriter* packet_writer);
 
-  // Used to implement QuicAlarmFactory..
-  QuartcTaskRunnerInterface* task_runner_;
-  // Used to implement the QuicConnectionHelperInterface.
-  // The QuicClock wrapper held in this variable is owned by QuartcFactory,
-  // but the QuartcClockInterface inside of it belongs to the user!
-  std::unique_ptr<QuicClock> clock_;
+  // Used to implement QuicAlarmFactory.  Owned by the user and must outlive
+  // QuartcFactory.
+  QuicAlarmFactory* alarm_factory_;
+  // Used to implement the QuicConnectionHelperInterface.  Owned by the user and
+  // must outlive QuartcFactory.
+  QuicClock* clock_;
   SimpleBufferAllocator buffer_allocator_;
 };
 
+// Creates a new instance of QuartcFactory.
+std::unique_ptr<QuartcFactory> CreateQuartcFactory(
+    const QuartcFactoryConfig& factory_config);
+
 }  // namespace quic
 
 #endif  // NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_FACTORY_H_
diff --git a/net/third_party/quic/quartc/quartc_factory_interface.cc b/net/third_party/quic/quartc/quartc_factory_interface.cc
deleted file mode 100644
index 12897fa..0000000
--- a/net/third_party/quic/quartc/quartc_factory_interface.cc
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 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 "net/third_party/quic/quartc/quartc_factory_interface.h"
-
-namespace quic {
-
-QuartcFactoryInterface::QuartcSessionConfig::QuartcSessionConfig() = default;
-QuartcFactoryInterface::QuartcSessionConfig::~QuartcSessionConfig() = default;
-
-}  // namespace quic
diff --git a/net/third_party/quic/quartc/quartc_factory_interface.h b/net/third_party/quic/quartc/quartc_factory_interface.h
deleted file mode 100644
index 8013bc9..0000000
--- a/net/third_party/quic/quartc/quartc_factory_interface.h
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright (c) 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 NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_FACTORY_INTERFACE_H_
-#define NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_FACTORY_INTERFACE_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-
-#include "net/third_party/quic/platform/api/quic_export.h"
-#include "net/third_party/quic/quartc/quartc_clock_interface.h"
-#include "net/third_party/quic/quartc/quartc_session_interface.h"
-#include "net/third_party/quic/quartc/quartc_task_runner_interface.h"
-
-namespace quic {
-
-// Algorithm to use for congestion control.
-enum class QuartcCongestionControl {
-  kDefault,  // Use an arbitrary algorithm chosen by QUIC.
-  kBBR,      // Use BBR.
-};
-
-// Options that control the BBR algorithm.
-enum class QuartcBbrOptions {
-  kSlowerStartup,    // Once a loss is encountered in STARTUP,
-                     // switches startup to a 1.5x pacing gain.
-  kFullyDrainQueue,  // Fully drains the queue once per cycle.
-  kReduceProbeRtt,   // Probe RTT reduces CWND to 0.75 * BDP instead of 4
-                     // packets.
-  kSkipProbeRtt,     // Skip Probe RTT and extend the existing min_rtt if a
-                     // recent min_rtt is within 12.5% of the current min_rtt.
-  kSkipProbeRttAggressively,  //  Skip ProbeRTT and extend the existing min_rtt
-                              //  as long as you've been app limited at least
-                              //  once.
-  kFillUpLinkDuringProbing,   // Sends probing retransmissions whenever we
-                              // become application limited.
-  kInitialWindow3,            // Use a 3-packet initial congestion window.
-  kInitialWindow10,           // Use a 10-packet initial congestion window.
-  kInitialWindow20,           // Use a 20-packet initial congestion window.
-  kInitialWindow50,           // Use a 50-packet initial congestion window.
-  kStartup1RTT,               // Stay in STARTUP for 1 RTT.
-  kStartup2RTT,               // Stay in STARTUP for 2 RTTs.
-};
-
-// Used to create instances for Quartc objects such as QuartcSession.
-class QUIC_EXPORT_PRIVATE QuartcFactoryInterface {
- public:
-  virtual ~QuartcFactoryInterface() {}
-
-  struct QuartcSessionConfig {
-    QuartcSessionConfig();
-    ~QuartcSessionConfig();
-
-    // When using Quartc, there are two endpoints. The QuartcSession on one
-    // endpoint must act as a server and the one on the other side must act as a
-    // client.
-    bool is_server = false;
-    // This is only needed when is_server = false.  It must be unique
-    // for each endpoint the local endpoint may communicate with. For example,
-    // a WebRTC client could use the remote endpoint's crypto fingerprint
-    std::string unique_remote_server_id;
-    // The way the QuicConnection will send and receive packets, like a virtual
-    // UDP socket. For WebRTC, this will typically be an IceTransport.
-    QuartcPacketTransport* packet_transport = nullptr;
-    // The maximum size of the packet can be written with the packet writer.
-    // 1200 bytes by default.
-    uint64_t max_packet_size = 1200;
-    // Algorithm to use for congestion control.  By default, uses an arbitrary
-    // congestion control algorithm chosen by QUIC.
-    QuartcCongestionControl congestion_control =
-        QuartcCongestionControl::kDefault;
-    // Options to control the BBR algorithm. In case the congestion control is
-    // set to anything but BBR, these options are ignored.
-    std::vector<QuartcBbrOptions> bbr_options;
-    // Timeouts for the crypto handshake. Set them to higher values to
-    // prevent closing the session before it started on a slow network.
-    // Zero entries are ignored and QUIC defaults are used in that case.
-    uint32_t max_idle_time_before_crypto_handshake_secs = 0;
-    uint32_t max_time_before_crypto_handshake_secs = 0;
-    QuicTime::Delta idle_network_timeout = QuicTime::Delta::Zero();
-  };
-
-  virtual std::unique_ptr<QuartcSessionInterface> CreateQuartcSession(
-      const QuartcSessionConfig& quartc_config) = 0;
-};
-
-// The configuration for creating a QuartcFactory.
-struct QuartcFactoryConfig {
-  // The task runner used by the QuartcAlarm. Implemented by the Quartc user
-  // with different mechanism. For example in WebRTC, it is implemented with
-  // rtc::Thread. Owned by the user, and needs to stay alive for as long
-  // as the QuartcFactory exists.
-  QuartcTaskRunnerInterface* task_runner = nullptr;
-  // The clock used by QuartcAlarms. Implemented by the Quartc user. Owned by
-  // the user, and needs to stay alive for as long as the QuartcFactory exists.
-  QuartcClockInterface* clock = nullptr;
-};
-
-// Creates a new instance of QuartcFactoryInterface.
-std::unique_ptr<QuartcFactoryInterface> CreateQuartcFactory(
-    const QuartcFactoryConfig& factory_config);
-
-}  // namespace quic
-
-#endif  // NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_FACTORY_INTERFACE_H_
diff --git a/net/third_party/quic/quartc/quartc_packet_writer.h b/net/third_party/quic/quartc/quartc_packet_writer.h
index a1cabb7..a4dca96 100644
--- a/net/third_party/quic/quartc/quartc_packet_writer.h
+++ b/net/third_party/quic/quartc/quartc_packet_writer.h
@@ -5,12 +5,31 @@
 #ifndef NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_PACKET_WRITER_H_
 #define NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_PACKET_WRITER_H_
 
+#include "net/third_party/quic/core/quic_connection.h"
 #include "net/third_party/quic/core/quic_packet_writer.h"
+#include "net/third_party/quic/core/quic_types.h"
 #include "net/third_party/quic/platform/api/quic_export.h"
-#include "net/third_party/quic/quartc/quartc_session_interface.h"
 
 namespace quic {
 
+// Send and receive packets, like a virtual UDP socket. For example, this
+// could be implemented by WebRTC's IceTransport.
+class QUIC_EXPORT_PRIVATE QuartcPacketTransport {
+ public:
+  // Additional metadata provided for each packet written.
+  struct PacketInfo {
+    QuicPacketNumber packet_number;
+  };
+
+  virtual ~QuartcPacketTransport() {}
+
+  // Called by the QuartcPacketWriter when writing packets to the network.
+  // Return the number of written bytes. Return 0 if the write is blocked.
+  virtual int Write(const char* buffer,
+                    size_t buf_len,
+                    const PacketInfo& info) = 0;
+};
+
 // Implements a QuicPacketWriter using a QuartcPacketTransport, which allows a
 // QuicConnection to use (for example), a WebRTC IceTransport.
 class QUIC_EXPORT_PRIVATE QuartcPacketWriter : public QuicPacketWriter {
@@ -20,7 +39,7 @@
   ~QuartcPacketWriter() override {}
 
   // The QuicConnection calls WritePacket and the QuicPacketWriter writes them
-  // to the QuartcSessionInterface::PacketTransport.
+  // to the QuartcSession::PacketTransport.
   WriteResult WritePacket(const char* buffer,
                           size_t buf_len,
                           const QuicIpAddress& self_address,
diff --git a/net/third_party/quic/quartc/quartc_session.cc b/net/third_party/quic/quartc/quartc_session.cc
index c8d48c2..f61da4e 100644
--- a/net/third_party/quic/quartc/quartc_session.cc
+++ b/net/third_party/quic/quartc/quartc_session.cc
@@ -8,8 +8,6 @@
 #include "net/third_party/quic/core/tls_server_handshaker.h"
 #include "net/third_party/quic/platform/api/quic_ptr_util.h"
 
-using std::string;
-
 namespace quic {
 
 namespace {
@@ -31,14 +29,14 @@
 
   // ProofSource override.
   void GetProof(const QuicSocketAddress& server_addr,
-                const string& hostname,
-                const string& server_config,
+                const QuicString& hostname,
+                const QuicString& server_config,
                 QuicTransportVersion transport_version,
                 QuicStringPiece chlo_hash,
                 std::unique_ptr<Callback> callback) override {
     QuicReferenceCountedPointer<ProofSource::Chain> chain;
     QuicCryptoProof proof;
-    std::vector<string> certs;
+    std::vector<QuicString> certs;
     certs.push_back("Dummy cert");
     chain = new ProofSource::Chain(certs);
     proof.signature = "Dummy signature";
@@ -48,13 +46,13 @@
 
   QuicReferenceCountedPointer<Chain> GetCertChain(
       const QuicSocketAddress& server_address,
-      const string& hostname) override {
+      const QuicString& hostname) override {
     return QuicReferenceCountedPointer<Chain>();
   }
 
   void ComputeTlsSignature(
       const QuicSocketAddress& server_address,
-      const string& hostname,
+      const QuicString& hostname,
       uint16_t signature_algorithm,
       QuicStringPiece in,
       std::unique_ptr<SignatureCallback> callback) override {
@@ -72,26 +70,26 @@
 
   // ProofVerifier override.
   QuicAsyncStatus VerifyProof(
-      const string& hostname,
+      const QuicString& hostname,
       const uint16_t port,
-      const string& server_config,
+      const QuicString& server_config,
       QuicTransportVersion transport_version,
       QuicStringPiece chlo_hash,
-      const std::vector<string>& certs,
-      const string& cert_sct,
-      const string& signature,
+      const std::vector<QuicString>& certs,
+      const QuicString& cert_sct,
+      const QuicString& signature,
       const ProofVerifyContext* context,
-      string* error_details,
+      QuicString* error_details,
       std::unique_ptr<ProofVerifyDetails>* verify_details,
       std::unique_ptr<ProofVerifierCallback> callback) override {
     return QUIC_SUCCESS;
   }
 
   QuicAsyncStatus VerifyCertChain(
-      const string& hostname,
-      const std::vector<string>& certs,
+      const QuicString& hostname,
+      const std::vector<QuicString>& certs,
       const ProofVerifyContext* context,
-      string* error_details,
+      QuicString* error_details,
       std::unique_ptr<ProofVerifyDetails>* details,
       std::unique_ptr<ProofVerifierCallback> callback) override {
     return QUIC_SUCCESS;
@@ -114,65 +112,13 @@
     const QuicSocketAddress& client_address,
     const QuicSocketAddress& peer_address,
     const QuicSocketAddress& self_address,
-    string* error_details) const {
+    QuicString* error_details) const {
   return true;
 }
 
-QuartcSessionVisitorAdapter::~QuartcSessionVisitorAdapter() {}
-
-QuartcSessionVisitorAdapter::QuartcSessionVisitorAdapter() {}
-
-void QuartcSessionVisitorAdapter::OnPacketSent(
-    const SerializedPacket& serialized_packet,
-    QuicPacketNumber original_packet_number,
-    TransmissionType transmission_type,
-    QuicTime sent_time) {
-  for (QuartcSessionVisitor* visitor : visitors_) {
-    visitor->OnPacketSent(serialized_packet, original_packet_number,
-                          transmission_type, sent_time);
-  }
-}
-
-void QuartcSessionVisitorAdapter::OnIncomingAck(
-    const QuicAckFrame& ack_frame,
-    QuicTime ack_receive_time,
-    QuicPacketNumber largest_observed,
-    bool rtt_updated,
-    QuicPacketNumber least_unacked_sent_packet) {
-  for (QuartcSessionVisitor* visitor : visitors_) {
-    visitor->OnIncomingAck(ack_frame, ack_receive_time, largest_observed,
-                           rtt_updated, least_unacked_sent_packet);
-  }
-}
-
-void QuartcSessionVisitorAdapter::OnPacketLoss(
-    QuicPacketNumber lost_packet_number,
-    TransmissionType transmission_type,
-    QuicTime detection_time) {
-  for (QuartcSessionVisitor* visitor : visitors_) {
-    visitor->OnPacketLoss(lost_packet_number, transmission_type,
-                          detection_time);
-  }
-}
-
-void QuartcSessionVisitorAdapter::OnWindowUpdateFrame(
-    const QuicWindowUpdateFrame& frame,
-    const QuicTime& receive_time) {
-  for (QuartcSessionVisitor* visitor : visitors_) {
-    visitor->OnWindowUpdateFrame(frame, receive_time);
-  }
-}
-
-void QuartcSessionVisitorAdapter::OnSuccessfulVersionNegotiation(
-    const ParsedQuicVersion& version) {
-  for (QuartcSessionVisitor* visitor : visitors_) {
-    visitor->OnSuccessfulVersionNegotiation(version);
-  }
-}
-
 QuartcSession::QuartcSession(std::unique_ptr<QuicConnection> connection,
                              const QuicConfig& config,
-                             const string& unique_remote_server_id,
+                             const QuicString& unique_remote_server_id,
                              Perspective perspective,
                              QuicConnectionHelperInterface* helper,
                              QuicClock* clock,
@@ -200,7 +146,7 @@
     helper_->GetRandomGenerator()->RandBytes(source_address_token_secret,
                                              kInputKeyingMaterialLength);
     quic_crypto_server_config_ = QuicMakeUnique<QuicCryptoServerConfig>(
-        string(source_address_token_secret, kInputKeyingMaterialLength),
+        QuicString(source_address_token_secret, kInputKeyingMaterialLength),
         helper_->GetRandomGenerator(), std::move(proof_source),
         TlsServerHandshaker::CreateSslCtx());
     // Provide server with serialized config string to prove ownership.
@@ -241,15 +187,6 @@
   }
 }
 
-void QuartcSession::CloseStream(QuicStreamId stream_id) {
-  if (IsClosedStream(stream_id)) {
-    // When CloseStream has been called recursively (via
-    // QuicStream::OnClose), the stream is already closed so return.
-    return;
-  }
-  QuicSession::CloseStream(stream_id);
-}
-
 void QuartcSession::CancelStream(QuicStreamId stream_id) {
   ResetStream(stream_id, QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED);
 }
@@ -265,21 +202,12 @@
   }
 }
 
-bool QuartcSession::IsOpenStream(QuicStreamId stream_id) {
-  return QuicSession::IsOpenStream(stream_id);
-}
-
-QuicConnectionStats QuartcSession::GetStats() {
-  return connection_->GetStats();
-}
-
 void QuartcSession::OnConnectionClosed(QuicErrorCode error,
-                                       const string& error_details,
+                                       const QuicString& error_details,
                                        ConnectionCloseSource source) {
   QuicSession::OnConnectionClosed(error, error_details, source);
   DCHECK(session_delegate_);
-  session_delegate_->OnConnectionClosed(
-      error, source == ConnectionCloseSource::FROM_PEER);
+  session_delegate_->OnConnectionClosed(error, error_details, source);
 }
 
 void QuartcSession::SetPreSharedKey(QuicStringPiece key) {
@@ -313,35 +241,13 @@
   }
 }
 
-bool QuartcSession::ExportKeyingMaterial(const string& label,
-                                         const uint8_t* context,
-                                         size_t context_len,
-                                         bool used_context,
-                                         uint8_t* result,
-                                         size_t result_len) {
-  string quic_context(reinterpret_cast<const char*>(context), context_len);
-  string quic_result;
-  bool success = crypto_stream_->ExportKeyingMaterial(label, quic_context,
-                                                      result_len, &quic_result);
-  quic_result.copy(reinterpret_cast<char*>(result), result_len);
-  DCHECK(quic_result.length() == result_len);
-  return success;
-}
-
-void QuartcSession::CloseConnection(const string& details) {
+void QuartcSession::CloseConnection(const QuicString& details) {
   connection_->CloseConnection(
       QuicErrorCode::QUIC_CONNECTION_CANCELLED, details,
       ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET_WITH_NO_ACK);
 }
 
-QuartcStreamInterface* QuartcSession::CreateOutgoingStream(
-    const OutgoingStreamParameters& param) {
-  // The |param| is for forward-compatibility. Not used for now.
-  return CreateOutgoingDynamicStream();
-}
-
-void QuartcSession::SetDelegate(
-    QuartcSessionInterface::Delegate* session_delegate) {
+void QuartcSession::SetDelegate(Delegate* session_delegate) {
   if (session_delegate_) {
     LOG(WARNING) << "The delegate for the session has already been set.";
   }
@@ -349,25 +255,6 @@
   DCHECK(session_delegate_);
 }
 
-void QuartcSession::AddSessionVisitor(QuartcSessionVisitor* visitor) {
-  // If there aren't any visitors yet, install the adapter as a connection debug
-  // visitor to delegate any future calls.
-  if (session_visitor_adapter_.visitors().empty()) {
-    connection_->set_debug_visitor(&session_visitor_adapter_);
-  }
-  session_visitor_adapter_.mutable_visitors().insert(visitor);
-  visitor->OnQuicConnection(connection_.get());
-}
-
-void QuartcSession::RemoveSessionVisitor(QuartcSessionVisitor* visitor) {
-  session_visitor_adapter_.mutable_visitors().erase(visitor);
-  // If the last visitor is removed, uninstall the connection debug visitor to
-  // avoid delegating debug calls unnecessarily.
-  if (session_visitor_adapter_.visitors().empty()) {
-    connection_->set_debug_visitor(nullptr);
-  }
-}
-
 void QuartcSession::OnTransportCanWrite() {
   connection()->writer()->SetWritable();
   if (HasDataToWrite()) {
@@ -376,29 +263,12 @@
 }
 
 bool QuartcSession::OnTransportReceived(const char* data, size_t data_len) {
-  // If the session is currently bundling packets, it must stop and flush writes
-  // before processing incoming data.  QUIC expects pending packets to be
-  // written before receiving data, because received data may change the
-  // contents of ACK frames in pending packets.
-  FlushWrites();
-
   QuicReceivedPacket packet(data, data_len, clock_->Now());
   ProcessUdpPacket(connection()->self_address(), connection()->peer_address(),
                    packet);
   return true;
 }
 
-void QuartcSession::BundleWrites() {
-  if (!packet_flusher_) {
-    packet_flusher_ = QuicMakeUnique<QuicConnection::ScopedPacketFlusher>(
-        connection_.get(), QuicConnection::SEND_ACK_IF_QUEUED);
-  }
-}
-
-void QuartcSession::FlushWrites() {
-  packet_flusher_ = nullptr;
-}
-
 void QuartcSession::OnProofValid(
     const QuicCryptoClientConfig::CachedState& cached) {
   // TODO(zhihuang): Handle the proof verification.
@@ -409,16 +279,6 @@
   // TODO(zhihuang): Handle the proof verification.
 }
 
-void QuartcSession::SetClientCryptoConfig(
-    QuicCryptoClientConfig* client_config) {
-  quic_crypto_client_config_.reset(client_config);
-}
-
-void QuartcSession::SetServerCryptoConfig(
-    QuicCryptoServerConfig* server_config) {
-  quic_crypto_server_config_.reset(server_config);
-}
-
 QuicStream* QuartcSession::CreateIncomingDynamicStream(QuicStreamId id) {
   return ActivateDataStream(CreateDataStream(id, QuicStream::kDefaultPriority));
 }
diff --git a/net/third_party/quic/quartc/quartc_session.h b/net/third_party/quic/quartc/quartc_session.h
index ac1eb24c..82a43338 100644
--- a/net/third_party/quic/quartc/quartc_session.h
+++ b/net/third_party/quic/quartc/quartc_session.h
@@ -11,9 +11,7 @@
 #include "net/third_party/quic/core/quic_error_codes.h"
 #include "net/third_party/quic/core/quic_session.h"
 #include "net/third_party/quic/platform/api/quic_export.h"
-#include "net/third_party/quic/quartc/quartc_clock_interface.h"
 #include "net/third_party/quic/quartc/quartc_packet_writer.h"
-#include "net/third_party/quic/quartc/quartc_session_interface.h"
 #include "net/third_party/quic/quartc/quartc_stream.h"
 
 namespace quic {
@@ -28,58 +26,23 @@
                             const QuicSocketAddress& client_address,
                             const QuicSocketAddress& peer_address,
                             const QuicSocketAddress& self_address,
-                            std::string* error_details) const override;
+                            QuicString* error_details) const override;
 };
 
-// Adapts |QuartcSessionVisitor|s to the |QuicConnectionDebugVisitor| interface.
-// Keeps a set of |QuartcSessionVisitor|s and forwards QUIC debug callbacks to
-// each visitor in the set.
-class QuartcSessionVisitorAdapter : public QuicConnectionDebugVisitor {
- public:
-  QuartcSessionVisitorAdapter();
-  ~QuartcSessionVisitorAdapter() override;
-
-  void OnPacketSent(const SerializedPacket& serialized_packet,
-                    QuicPacketNumber original_packet_number,
-                    TransmissionType transmission_type,
-                    QuicTime sent_time) override;
-  void OnIncomingAck(const QuicAckFrame& ack_frame,
-                     QuicTime ack_receive_time,
-                     QuicPacketNumber largest_observed,
-                     bool rtt_updated,
-                     QuicPacketNumber least_unacked_sent_packet) override;
-  void OnPacketLoss(QuicPacketNumber lost_packet_number,
-                    TransmissionType transmission_type,
-                    QuicTime detection_time) override;
-  void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame,
-                           const QuicTime& receive_time) override;
-  void OnSuccessfulVersionNegotiation(
-      const ParsedQuicVersion& version) override;
-
-  const std::set<QuartcSessionVisitor*>& visitors() const { return visitors_; }
-  std::set<QuartcSessionVisitor*>& mutable_visitors() { return visitors_; }
-
-  // Disallow copy and assign.
-  QuartcSessionVisitorAdapter(const QuartcSessionVisitorAdapter&) = delete;
-  QuartcSessionVisitorAdapter operator=(const QuartcSessionVisitorAdapter&) =
-      delete;
-
- private:
-  std::set<QuartcSessionVisitor*> visitors_;
-};
-
+// QuartcSession owns and manages a QUIC connection.
 class QUIC_EXPORT_PRIVATE QuartcSession
     : public QuicSession,
-      public QuartcSessionInterface,
       public QuicCryptoClientStream::ProofHandler {
  public:
   QuartcSession(std::unique_ptr<QuicConnection> connection,
                 const QuicConfig& config,
-                const std::string& unique_remote_server_id,
+                const QuicString& unique_remote_server_id,
                 Perspective perspective,
                 QuicConnectionHelperInterface* helper,
                 QuicClock* clock,
                 std::unique_ptr<QuartcPacketWriter> packet_writer);
+  QuartcSession(const QuartcSession&) = delete;
+  QuartcSession& operator=(const QuartcSession&) = delete;
   ~QuartcSession() override;
 
   // QuicSession overrides.
@@ -91,48 +54,67 @@
 
   void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override;
 
-  void CloseStream(QuicStreamId stream_id) override;
-
   // QuicConnectionVisitorInterface overrides.
   void OnConnectionClosed(QuicErrorCode error,
-                          const std::string& error_details,
+                          const QuicString& error_details,
                           ConnectionCloseSource source) override;
 
-  // QuartcSessionInterface overrides
-  void SetPreSharedKey(QuicStringPiece key) override;
+  // QuartcSession methods.
 
-  void StartCryptoHandshake() override;
+  // Sets a pre-shared key for use during the crypto handshake.  Must be set
+  // before StartCryptoHandshake() is called.
+  void SetPreSharedKey(QuicStringPiece key);
 
-  bool ExportKeyingMaterial(const std::string& label,
-                            const uint8_t* context,
-                            size_t context_len,
-                            bool used_context,
-                            uint8_t* result,
-                            size_t result_len) override;
+  void StartCryptoHandshake();
 
-  void CloseConnection(const std::string& details) override;
+  // Closes the connection with the given human-readable error details.
+  // The connection closes with the QUIC_CONNECTION_CANCELLED error code to
+  // indicate the application closed it.
+  //
+  // Informs the peer that the connection has been closed.  This prevents the
+  // peer from waiting until the connection times out.
+  //
+  // Cleans up the underlying QuicConnection's state.  Closing the connection
+  // makes it safe to delete the QuartcSession.
+  void CloseConnection(const QuicString& details);
 
-  QuartcStreamInterface* CreateOutgoingStream(
-      const OutgoingStreamParameters& param) override;
+  // If the given stream is still open, sends a reset frame to cancel it.
+  // Note:  This method cancels a stream by QuicStreamId rather than by pointer
+  // (or by a method on QuartcStream) because QuartcSession (and not
+  // the caller) owns the streams.  Streams may finish and be deleted before the
+  // caller tries to cancel them, rendering the caller's pointers invalid.
+  void CancelStream(QuicStreamId stream_id);
 
-  void CancelStream(QuicStreamId stream_id) override;
+  // Callbacks called by the QuartcSession to notify the user of the
+  // QuartcSession of certain events.
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
 
-  bool IsOpenStream(QuicStreamId stream_id) override;
+    // Called when the crypto handshake is complete.
+    virtual void OnCryptoHandshakeComplete() = 0;
 
-  QuicConnectionStats GetStats() override;
+    // Called when a new stream is received from the remote endpoint.
+    virtual void OnIncomingStream(QuartcStream* stream) = 0;
 
-  void SetDelegate(QuartcSessionInterface::Delegate* session_delegate) override;
+    // Called when the connection is closed. This means all of the streams will
+    // be closed and no new streams can be created.
+    virtual void OnConnectionClosed(QuicErrorCode error_code,
+                                    const QuicString& error_details,
+                                    ConnectionCloseSource source) = 0;
 
-  void AddSessionVisitor(QuartcSessionVisitor* visitor) override;
-  void RemoveSessionVisitor(QuartcSessionVisitor* visitor) override;
+    // TODO(zhihuang): Add proof verification.
+  };
 
-  void OnTransportCanWrite() override;
+  // The |delegate| is not owned by QuartcSession.
+  void SetDelegate(Delegate* session_delegate);
 
-  // Decrypts an incoming QUIC packet to a data stream.
-  bool OnTransportReceived(const char* data, size_t data_len) override;
+  // Called when CanWrite() changes from false to true.
+  void OnTransportCanWrite();
 
-  void BundleWrites() override;
-  void FlushWrites() override;
+  // Called when a packet has been received and should be handled by the
+  // QuicConnection.
+  bool OnTransportReceived(const char* data, size_t data_len);
 
   // ProofHandler overrides.
   void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override;
@@ -143,12 +125,6 @@
   void OnProofVerifyDetailsAvailable(
       const ProofVerifyDetails& verify_details) override;
 
-  // Override the default crypto configuration.
-  // The session will take the ownership of the configurations.
-  void SetClientCryptoConfig(QuicCryptoClientConfig* client_config);
-
-  void SetServerCryptoConfig(QuicCryptoServerConfig* server_config);
-
  protected:
   // QuicSession override.
   QuicStream* CreateIncomingDynamicStream(QuicStreamId id) override;
@@ -164,7 +140,7 @@
  private:
   // For crypto handshake.
   std::unique_ptr<QuicCryptoStream> crypto_stream_;
-  const std::string unique_remote_server_id_;
+  const QuicString unique_remote_server_id_;
   Perspective perspective_;
 
   // Packet writer used by |connection_|.
@@ -179,7 +155,7 @@
   // For recording packet receipt time
   QuicClock* clock_;
   // Not owned by QuartcSession.
-  QuartcSessionInterface::Delegate* session_delegate_ = nullptr;
+  Delegate* session_delegate_ = nullptr;
   // Used by QUIC crypto server stream to track most recently compressed certs.
   std::unique_ptr<QuicCompressedCertsCache> quic_compressed_certs_cache_;
   // This helper is needed when create QuicCryptoServerStream.
@@ -188,14 +164,6 @@
   std::unique_ptr<QuicCryptoClientConfig> quic_crypto_client_config_;
   // Config for QUIC crypto server stream, used by the server.
   std::unique_ptr<QuicCryptoServerConfig> quic_crypto_server_config_;
-
-  // Holds pointers to QuartcSessionVisitors and adapts them to the
-  // QuicConnectionDebugVisitor interface.
-  QuartcSessionVisitorAdapter session_visitor_adapter_;
-
-  std::unique_ptr<QuicConnection::ScopedPacketFlusher> packet_flusher_;
-
-  DISALLOW_COPY_AND_ASSIGN(QuartcSession);
 };
 
 }  // namespace quic
diff --git a/net/third_party/quic/quartc/quartc_session_interface.h b/net/third_party/quic/quartc/quartc_session_interface.h
deleted file mode 100644
index 2db5f35..0000000
--- a/net/third_party/quic/quartc/quartc_session_interface.h
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright (c) 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 NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_SESSION_INTERFACE_H_
-#define NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_SESSION_INTERFACE_H_
-
-#include <stddef.h>
-#include <stdint.h>
-#include <string>
-
-#include "net/third_party/quic/core/quic_bandwidth.h"
-#include "net/third_party/quic/core/quic_error_codes.h"
-#include "net/third_party/quic/core/quic_time.h"
-#include "net/third_party/quic/core/quic_types.h"
-#include "net/third_party/quic/platform/api/quic_export.h"
-#include "net/third_party/quic/quartc/quartc_session_visitor_interface.h"
-#include "net/third_party/quic/quartc/quartc_stream_interface.h"
-
-namespace quic {
-
-// Send and receive packets, like a virtual UDP socket. For example, this
-// could be implemented by WebRTC's IceTransport.
-class QUIC_EXPORT_PRIVATE QuartcPacketTransport {
- public:
-  // Additional metadata provided for each packet written.
-  struct PacketInfo {
-    QuicPacketNumber packet_number;
-  };
-
-  virtual ~QuartcPacketTransport() {}
-
-  // Called by the QuartcPacketWriter when writing packets to the network.
-  // Return the number of written bytes. Return 0 if the write is blocked.
-  virtual int Write(const char* buffer,
-                    size_t buf_len,
-                    const PacketInfo& info) = 0;
-};
-
-// Given a PacketTransport, provides a way to send and receive separate streams
-// of reliable, in-order, encrypted data. For example, this can build on top of
-// a WebRTC IceTransport for sending and receiving data over QUIC.
-class QUIC_EXPORT_PRIVATE QuartcSessionInterface {
- public:
-  virtual ~QuartcSessionInterface() {}
-
-  // Sets a pre-shared key for use during the crypto handshake.  Must be set
-  // before StartCryptoHandshake() is called.
-  virtual void SetPreSharedKey(QuicStringPiece key) = 0;
-
-  virtual void StartCryptoHandshake() = 0;
-
-  // Only needed when using SRTP with QuicTransport
-  // Key Exporter interface from RFC 5705
-  // Arguments are:
-  // label               -- the exporter label.
-  //                        part of the RFC defining each exporter usage (IN)
-  // context/context_len -- a context to bind to for this connection;
-  //                        optional, can be NULL, 0 (IN)
-  // use_context         -- whether to use the context value
-  //                        (needed to distinguish no context from
-  //                        zero-length ones).
-  // result              -- where to put the computed value
-  // result_len          -- the length of the computed value
-  virtual bool ExportKeyingMaterial(const std::string& label,
-                                    const uint8_t* context,
-                                    size_t context_len,
-                                    bool used_context,
-                                    uint8_t* result,
-                                    size_t result_len) = 0;
-
-  // Closes the connection with the given human-readable error details.
-  // The connection closes with the QUIC_CONNECTION_CANCELLED error code to
-  // indicate the application closed it.
-  //
-  // Informs the peer that the connection has been closed.  This prevents the
-  // peer from waiting until the connection times out.
-  //
-  // Cleans up the underlying QuicConnection's state.  Closing the connection
-  // makes it safe to delete the QuartcSession.
-  virtual void CloseConnection(const std::string& error_details) = 0;
-
-  // For forward-compatibility. More parameters could be added through the
-  // struct without changing the API.
-  struct OutgoingStreamParameters {};
-
-  virtual QuartcStreamInterface* CreateOutgoingStream(
-      const OutgoingStreamParameters& params) = 0;
-
-  // If the given stream is still open, sends a reset frame to cancel it.
-  // Note:  This method cancels a stream by QuicStreamId rather than by pointer
-  // (or by a method on QuartcStreamInterface) because QuartcSession (and not
-  // the caller) owns the streams.  Streams may finish and be deleted before the
-  // caller tries to cancel them, rendering the caller's pointers invalid.
-  virtual void CancelStream(QuicStreamId stream_id) = 0;
-
-  // This method verifies if a stream is still open and stream pointer can be
-  // used. When true is returned, the interface pointer is good for making a
-  // call immediately on the same thread, but may be rendered invalid by ANY
-  // other QUIC activity.
-  virtual bool IsOpenStream(QuicStreamId stream_id) = 0;
-
-  // Gets stats associated with the current QUIC connection.
-  virtual QuicConnectionStats GetStats() = 0;
-
-  // Called when CanWrite() changes from false to true.
-  virtual void OnTransportCanWrite() = 0;
-
-  // Called when a packet has been received and should be handled by the
-  // QuicConnection.
-  virtual bool OnTransportReceived(const char* data, size_t data_len) = 0;
-
-  // Bundles subsequent writes on a best-effort basis.
-  // Data is sent whenever enough data is accumulated to fill a packet.
-  // The session stops bundling writes and sends data immediately as soon as
-  // FlushWrites() is called or a packet is received.
-  virtual void BundleWrites() = 0;
-
-  // Stop bundling writes and flush any pending writes immediately.
-  virtual void FlushWrites() = 0;
-
-  // Callbacks called by the QuartcSession to notify the user of the
-  // QuartcSession of certain events.
-  class Delegate {
-   public:
-    virtual ~Delegate() {}
-
-    // Called when the crypto handshake is complete.
-    virtual void OnCryptoHandshakeComplete() = 0;
-
-    // Called when a new stream is received from the remote endpoint.
-    virtual void OnIncomingStream(QuartcStreamInterface* stream) = 0;
-
-    // Called when the connection is closed. This means all of the streams will
-    // be closed and no new streams can be created.
-    // TODO(zhihuang): Create mapping from integer error code to WebRTC error
-    // code.
-    virtual void OnConnectionClosed(int error_code, bool from_remote) = 0;
-
-    // TODO(zhihuang): Add proof verification.
-  };
-
-  // The |delegate| is not owned by QuartcSession.
-  virtual void SetDelegate(Delegate* delegate) = 0;
-
-  // Add or remove session visitors.  Session visitors observe internals of the
-  // Quartc/QUIC session for the purpose of gathering metrics or debug
-  // information.
-  virtual void AddSessionVisitor(QuartcSessionVisitor* visitor) = 0;
-  virtual void RemoveSessionVisitor(QuartcSessionVisitor* visitor) = 0;
-};
-
-}  // namespace quic
-
-#endif  // NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_SESSION_INTERFACE_H_
diff --git a/net/third_party/quic/quartc/quartc_session_test.cc b/net/third_party/quic/quartc/quartc_session_test.cc
index aedd3675..da48a90 100644
--- a/net/third_party/quic/quartc/quartc_session_test.cc
+++ b/net/third_party/quic/quartc/quartc_session_test.cc
@@ -4,6 +4,7 @@
 
 #include "net/third_party/quic/quartc/quartc_session.h"
 
+#include "build/build_config.h"
 #include "net/third_party/quic/core/crypto/crypto_server_config_protobuf.h"
 #include "net/third_party/quic/core/quic_simple_buffer_allocator.h"
 #include "net/third_party/quic/core/quic_types.h"
@@ -13,229 +14,100 @@
 #include "net/third_party/quic/platform/api/quic_test.h"
 #include "net/third_party/quic/platform/api/quic_test_mem_slice_vector.h"
 #include "net/third_party/quic/quartc/quartc_factory.h"
-#include "net/third_party/quic/quartc/quartc_factory_interface.h"
 #include "net/third_party/quic/quartc/quartc_packet_writer.h"
-#include "net/third_party/quic/quartc/quartc_stream_interface.h"
 #include "net/third_party/quic/test_tools/mock_clock.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using std::string;
-
+// Tests flaky on iOS.
+// TODO(vasilvv): figure out what's wrong and re-enable if possible.
+#if !defined(OS_IOS)
 namespace quic {
 
 namespace {
 
-static const char kExporterLabel[] = "label";
-static const uint8_t kExporterContext[] = "context";
-static const size_t kExporterContextLen = sizeof(kExporterContext);
-static const size_t kOutputKeyLength = 20;
-static QuartcStreamInterface::WriteParameters kDefaultWriteParam;
-static QuartcSessionInterface::OutgoingStreamParameters kDefaultStreamParam;
 static QuicByteCount kDefaultMaxPacketSize = 1200;
 
-// Single-threaded scheduled task runner based on a MockClock.
+// Single-threaded alarm implementation based on a MockClock.
 //
-// Simulates asynchronous execution on a single thread by holding scheduled
-// tasks until Run() is called. Performs no synchronization, assumes that
-// Schedule() and Run() are called on the same thread.
-class FakeTaskRunner : public QuartcTaskRunnerInterface {
+// Simulates asynchronous execution on a single thread by holding alarms
+// until Run() is called. Performs no synchronization, assumes that
+// CreateAlarm(), Set(), Cancel(), and Run() are called on the same thread.
+class FakeAlarmFactory : public QuicAlarmFactory {
  public:
-  explicit FakeTaskRunner(MockClock* clock)
-      : tasks_([this](const TaskType& l, const TaskType& r) {
-          // Items at a later time should run after items at an earlier time.
-          // Priority queue comparisons should return true if l appears after r.
-          return l->time() > r->time();
-        }),
-        clock_(clock) {}
+  class FakeAlarm : public QuicAlarm {
+   public:
+    FakeAlarm(QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+              FakeAlarmFactory* parent)
+        : QuicAlarm(std::move(delegate)), parent_(parent) {}
 
-  ~FakeTaskRunner() override {}
+    ~FakeAlarm() override { parent_->RemoveAlarm(this); }
 
-  // Runs all tasks scheduled in the next total_ms milliseconds.  Advances the
+    void SetImpl() override { parent_->AddAlarm(this); }
+
+    void CancelImpl() override { parent_->RemoveAlarm(this); }
+
+    void Run() { Fire(); }
+
+   private:
+    FakeAlarmFactory* parent_;
+  };
+
+  explicit FakeAlarmFactory(MockClock* clock) : clock_(clock) {}
+  FakeAlarmFactory(const FakeAlarmFactory&) = delete;
+  FakeAlarmFactory& operator=(const FakeAlarmFactory&) = delete;
+
+  QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override {
+    return new FakeAlarm(QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate),
+                         this);
+  }
+
+  QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
+      QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+      QuicConnectionArena* arena) override {
+    return arena->New<FakeAlarm>(std::move(delegate), this);
+  }
+
+  // Runs all alarms scheduled in the next total_ms milliseconds.  Advances the
   // clock by total_ms.  Runs tasks in time order.  Executes tasks scheduled at
   // the same in an arbitrary order.
   void Run(uint32_t total_ms) {
     for (uint32_t i = 0; i < total_ms; ++i) {
-      while (!tasks_.empty() && tasks_.top()->time() <= clock_->Now()) {
-        tasks_.top()->Run();
-        tasks_.pop();
+      while (!alarms_.empty() && alarms_.top()->deadline() <= clock_->Now()) {
+        alarms_.top()->Run();
+        alarms_.pop();
       }
       clock_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
     }
   }
 
  private:
-  class InnerTask {
-   public:
-    InnerTask(std::function<void()> task, QuicTime time)
-        : task_(std::move(task)), time_(time) {}
-
-    void Cancel() { cancelled_ = true; }
-
-    void Run() {
-      if (!cancelled_) {
-        task_();
+  void RemoveAlarm(FakeAlarm* alarm) {
+    std::vector<FakeAlarm*> leftovers;
+    while (!alarms_.empty()) {
+      FakeAlarm* top = alarms_.top();
+      alarms_.pop();
+      if (top == alarm) {
+        break;
       }
+      leftovers.push_back(top);
     }
-
-    QuicTime time() const { return time_; }
-
-   private:
-    bool cancelled_ = false;
-    std::function<void()> task_;
-    QuicTime time_;
-  };
-
- public:
-  // Hook for cancelling a scheduled task.
-  class ScheduledTask : public QuartcTaskRunnerInterface::ScheduledTask {
-   public:
-    explicit ScheduledTask(std::shared_ptr<InnerTask> inner)
-        : inner_(std::move(inner)) {}
-
-    // Cancel if the caller deletes the ScheduledTask.  This behavior is
-    // consistent with the actual task runner Quartc uses.
-    ~ScheduledTask() override { Cancel(); }
-
-    // ScheduledTask implementation.
-    void Cancel() override { inner_->Cancel(); }
-
-   private:
-    std::shared_ptr<InnerTask> inner_;
-  };
-
-  // See QuartcTaskRunnerInterface.
-  std::unique_ptr<QuartcTaskRunnerInterface::ScheduledTask> Schedule(
-      Task* task,
-      uint64_t delay_ms) override {
-    auto inner = std::shared_ptr<InnerTask>(new InnerTask(
-        [task] { task->Run(); },
-        clock_->Now() + QuicTime::Delta::FromMilliseconds(delay_ms)));
-    tasks_.push(inner);
-    return std::unique_ptr<QuartcTaskRunnerInterface::ScheduledTask>(
-        new ScheduledTask(inner));
-  }
-
-  // Schedules a function to run immediately.
-  void Schedule(std::function<void()> task) {
-    tasks_.push(std::shared_ptr<InnerTask>(
-        new InnerTask(std::move(task), clock_->Now())));
-  }
-
- private:
-  // InnerTasks are shared by the queue and ScheduledTask (which hooks into it
-  // to implement Cancel()).
-  using TaskType = std::shared_ptr<InnerTask>;
-  std::priority_queue<TaskType,
-                      std::vector<TaskType>,
-                      std::function<bool(const TaskType&, const TaskType&)>>
-      tasks_;
-  MockClock* clock_;
-};
-
-// QuartcClock that wraps a MockClock.
-//
-// This is silly because Quartc wraps it as a QuicClock, and MockClock is
-// already a QuicClock.  But we don't have much choice.  We need to pass a
-// QuartcClockInterface into the Quartc wrappers.
-class MockQuartcClock : public QuartcClockInterface {
- public:
-  explicit MockQuartcClock(MockClock* clock) : clock_(clock) {}
-
-  int64_t NowMicroseconds() override {
-    return clock_->WallNow().ToUNIXMicroseconds();
-  }
-
- private:
-  MockClock* clock_;
-};
-
-// Used by QuicCryptoServerConfig to provide server credentials, returning a
-// canned response equal to |success|.
-class FakeProofSource : public ProofSource {
- public:
-  explicit FakeProofSource(bool success) : success_(success) {}
-
-  // ProofSource override.
-  void GetProof(const QuicSocketAddress& server_ip,
-                const string& hostname,
-                const string& server_config,
-                QuicTransportVersion transport_version,
-                QuicStringPiece chlo_hash,
-                std::unique_ptr<Callback> callback) override {
-    QuicReferenceCountedPointer<ProofSource::Chain> chain;
-    QuicCryptoProof proof;
-    if (success_) {
-      std::vector<string> certs;
-      certs.push_back("Required to establish handshake");
-      chain = new ProofSource::Chain(certs);
-      proof.signature = "Signature";
-      proof.leaf_cert_scts = "Time";
+    for (FakeAlarm* leftover : leftovers) {
+      alarms_.push(leftover);
     }
-    callback->Run(success_, chain, proof, nullptr /* details */);
   }
 
-  QuicReferenceCountedPointer<Chain> GetCertChain(
-      const QuicSocketAddress& server_address,
-      const string& hostname) override {
-    return QuicReferenceCountedPointer<Chain>();
-  }
+  void AddAlarm(FakeAlarm* alarm) { alarms_.push(alarm); }
 
-  void ComputeTlsSignature(
-      const QuicSocketAddress& server_address,
-      const string& hostname,
-      uint16_t signature_algorithm,
-      QuicStringPiece in,
-      std::unique_ptr<SignatureCallback> callback) override {
-    callback->Run(true, "Signature");
-  }
+  MockClock* clock_;
 
- private:
-  // Whether or not obtaining proof source succeeds.
-  bool success_;
-};
-
-// Used by QuicCryptoClientConfig to verify server credentials, returning a
-// canned response of QUIC_SUCCESS if |success| is true.
-class FakeProofVerifier : public ProofVerifier {
- public:
-  explicit FakeProofVerifier(bool success) : success_(success) {}
-
-  // ProofVerifier override
-  QuicAsyncStatus VerifyProof(
-      const string& hostname,
-      const uint16_t port,
-      const string& server_config,
-      QuicTransportVersion transport_version,
-      QuicStringPiece chlo_hash,
-      const std::vector<string>& certs,
-      const string& cert_sct,
-      const string& signature,
-      const ProofVerifyContext* context,
-      string* error_details,
-      std::unique_ptr<ProofVerifyDetails>* verify_details,
-      std::unique_ptr<ProofVerifierCallback> callback) override {
-    return success_ ? QUIC_SUCCESS : QUIC_FAILURE;
-  }
-
-  QuicAsyncStatus VerifyCertChain(
-      const string& hostname,
-      const std::vector<string>& certs,
-      const ProofVerifyContext* context,
-      string* error_details,
-      std::unique_ptr<ProofVerifyDetails>* details,
-      std::unique_ptr<ProofVerifierCallback> callback) override {
-    LOG(INFO) << "VerifyProof() ignoring credentials and returning success";
-    return success_ ? QUIC_SUCCESS : QUIC_FAILURE;
-  }
-
-  std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override {
-    return nullptr;
-  }
-
- private:
-  // Whether or not proof verification succeeds.
-  bool success_;
+  using AlarmCompare = std::function<bool(const FakeAlarm*, const FakeAlarm*)>;
+  const AlarmCompare alarm_later_ = [](const FakeAlarm* l, const FakeAlarm* r) {
+    // Sort alarms so that the earliest deadline appears first.
+    return l->deadline() > r->deadline();
+  };
+  std::priority_queue<FakeAlarm*, std::vector<FakeAlarm*>, AlarmCompare>
+      alarms_{alarm_later_};
 };
 
 // Used by the FakeTransportChannel.
@@ -244,15 +116,17 @@
   virtual ~FakeTransportChannelObserver() {}
 
   // Called when the other peer is trying to send message.
-  virtual void OnTransportChannelReadPacket(const string& data) = 0;
+  virtual void OnTransportChannelReadPacket(const QuicString& data) = 0;
 };
 
 // Simulate the P2P communication transport. Used by the
-// QuartcSessionInterface::Transport.
-class FakeTransportChannel {
+// QuartcSession::Transport.
+class FakeTransportChannel : QuicAlarm::Delegate {
  public:
-  explicit FakeTransportChannel(FakeTaskRunner* task_runner, MockClock* clock)
-      : task_runner_(task_runner), clock_(clock) {}
+  explicit FakeTransportChannel(QuicAlarmFactory* alarm_factory,
+                                MockClock* clock)
+      : alarm_(alarm_factory->CreateAlarm(new AlarmDelegate(this))),
+        clock_(clock) {}
 
   void SetDestination(FakeTransportChannel* dest) {
     if (!dest_) {
@@ -268,21 +142,16 @@
     }
     // Advance the time 10us to ensure the RTT is never 0ms.
     clock_->AdvanceTime(QuicTime::Delta::FromMicroseconds(10));
-    if (async_ && task_runner_) {
-      string packet(data, len);
-      task_runner_->Schedule([this, packet] { send(packet); });
+    if (async_) {
+      packet_queue_.emplace_back(data, len);
+      alarm_->Cancel();
+      alarm_->Set(clock_->Now());
     } else {
-      send(string(data, len));
+      Send(QuicString(data, len));
     }
     return static_cast<int>(len);
   }
 
-  void send(const string& data) {
-    DCHECK(dest_);
-    DCHECK(dest_->observer());
-    dest_->observer()->OnTransportChannelReadPacket(data);
-  }
-
   FakeTransportChannelObserver* observer() { return observer_; }
 
   void SetObserver(FakeTransportChannelObserver* observer) {
@@ -292,14 +161,43 @@
   void SetAsync(bool async) { async_ = async; }
 
  private:
+  class AlarmDelegate : public QuicAlarm::Delegate {
+   public:
+    explicit AlarmDelegate(FakeTransportChannel* channel) : channel_(channel) {}
+
+    void OnAlarm() override { channel_->OnAlarm(); }
+
+   private:
+    FakeTransportChannel* channel_;
+  };
+
+  void Send(const QuicString& data) {
+    DCHECK(dest_);
+    DCHECK(dest_->observer());
+    dest_->observer()->OnTransportChannelReadPacket(data);
+  }
+
+  void OnAlarm() override {
+    QUIC_LOG(WARNING) << "Sending packet: " << packet_queue_.front();
+    Send(packet_queue_.front());
+    packet_queue_.pop_front();
+
+    if (!packet_queue_.empty()) {
+      alarm_->Cancel();
+      alarm_->Set(clock_->Now());
+    }
+  }
+
   // The writing destination of this channel.
   FakeTransportChannel* dest_ = nullptr;
   // The observer of this channel. Called when the received the data.
   FakeTransportChannelObserver* observer_ = nullptr;
   // If async, will send packets by running asynchronous tasks.
   bool async_ = false;
-  // Used to send data asynchronously.
-  FakeTaskRunner* task_runner_;
+  // If async, packets are queued here to send.
+  QuicDeque<QuicString> packet_queue_;
+  // Alarm used to send data asynchronously.
+  QuicArenaScopedPtr<QuicAlarm> alarm_;
   // The test clock.  Used to ensure the RTT is not 0.
   MockClock* clock_;
 };
@@ -331,51 +229,52 @@
   QuicPacketCount packets_to_lose_ = 0;
 };
 
-class FakeQuartcSessionDelegate : public QuartcSessionInterface::Delegate {
+class FakeQuartcSessionDelegate : public QuartcSession::Delegate {
  public:
-  explicit FakeQuartcSessionDelegate(
-      QuartcStreamInterface::Delegate* stream_delegate)
+  explicit FakeQuartcSessionDelegate(QuartcStream::Delegate* stream_delegate)
       : stream_delegate_(stream_delegate) {}
   // Called when peers have established forward-secure encryption
   void OnCryptoHandshakeComplete() override {
     LOG(INFO) << "Crypto handshake complete!";
   }
   // Called when connection closes locally, or remotely by peer.
-  void OnConnectionClosed(int error_code, bool from_remote) override {
+  void OnConnectionClosed(QuicErrorCode error_code,
+                          const QuicString& error_details,
+                          ConnectionCloseSource source) override {
     connected_ = false;
   }
   // Called when an incoming QUIC stream is created.
-  void OnIncomingStream(QuartcStreamInterface* quartc_stream) override {
+  void OnIncomingStream(QuartcStream* quartc_stream) override {
     last_incoming_stream_ = quartc_stream;
     last_incoming_stream_->SetDelegate(stream_delegate_);
   }
 
-  QuartcStreamInterface* incoming_stream() { return last_incoming_stream_; }
+  QuartcStream* incoming_stream() { return last_incoming_stream_; }
 
   bool connected() { return connected_; }
 
  private:
-  QuartcStreamInterface* last_incoming_stream_;
+  QuartcStream* last_incoming_stream_;
   bool connected_ = true;
   QuartcStream::Delegate* stream_delegate_;
 };
 
-class FakeQuartcStreamDelegate : public QuartcStreamInterface::Delegate {
+class FakeQuartcStreamDelegate : public QuartcStream::Delegate {
  public:
-  void OnReceived(QuartcStreamInterface* stream,
+  void OnReceived(QuartcStream* stream,
                   const char* data,
                   size_t size) override {
-    received_data_[stream->stream_id()] += string(data, size);
+    received_data_[stream->id()] += QuicString(data, size);
   }
 
-  void OnClose(QuartcStreamInterface* stream) override {}
+  void OnClose(QuartcStream* stream) override {}
 
-  void OnBufferChanged(QuartcStreamInterface* stream) override {}
+  void OnBufferChanged(QuartcStream* stream) override {}
 
-  std::map<QuicStreamId, string> data() { return received_data_; }
+  std::map<QuicStreamId, QuicString> data() { return received_data_; }
 
  private:
-  std::map<QuicStreamId, string> received_data_;
+  std::map<QuicStreamId, QuicString> received_data_;
 };
 
 class QuartcSessionForTest : public QuartcSession,
@@ -383,7 +282,7 @@
  public:
   QuartcSessionForTest(std::unique_ptr<QuicConnection> connection,
                        const QuicConfig& config,
-                       const string& remote_fingerprint_value,
+                       const QuicString& remote_fingerprint_value,
                        Perspective perspective,
                        QuicConnectionHelperInterface* helper,
                        QuicClock* clock,
@@ -403,11 +302,11 @@
   }
 
   // QuartcPacketWriter override.
-  void OnTransportChannelReadPacket(const string& data) override {
+  void OnTransportChannelReadPacket(const QuicString& data) override {
     OnTransportReceived(data.c_str(), data.length());
   }
 
-  std::map<QuicStreamId, string> data() { return stream_delegate_->data(); }
+  std::map<QuicStreamId, QuicString> data() { return stream_delegate_->data(); }
 
   bool has_data() { return !data().empty(); }
 
@@ -431,9 +330,9 @@
     // Quic crashes if packets are sent at time 0, and the clock defaults to 0.
     clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000));
     client_channel_ =
-        QuicMakeUnique<FakeTransportChannel>(&task_runner_, &clock_);
+        QuicMakeUnique<FakeTransportChannel>(&alarm_factory_, &clock_);
     server_channel_ =
-        QuicMakeUnique<FakeTransportChannel>(&task_runner_, &clock_);
+        QuicMakeUnique<FakeTransportChannel>(&alarm_factory_, &clock_);
     // Make the channel asynchronous so that two peer will not keep calling each
     // other when they exchange information.
     client_channel_->SetAsync(true);
@@ -453,8 +352,7 @@
 
   // The parameters are used to control whether the handshake will success or
   // not.
-  void CreateClientAndServerSessions(bool client_handshake_success = true,
-                                     bool server_handshake_success = true) {
+  void CreateClientAndServerSessions() {
     Init();
     client_peer_ =
         CreateSession(Perspective::IS_CLIENT, std::move(client_writer_));
@@ -463,26 +361,6 @@
 
     client_channel_->SetObserver(client_peer_.get());
     server_channel_->SetObserver(server_peer_.get());
-
-    client_peer_->SetClientCryptoConfig(new QuicCryptoClientConfig(
-        std::unique_ptr<ProofVerifier>(
-            new FakeProofVerifier(client_handshake_success)),
-        TlsClientHandshaker::CreateSslCtx()));
-
-    QuicCryptoServerConfig* server_config = new QuicCryptoServerConfig(
-        "TESTING", QuicRandom::GetInstance(),
-        std::unique_ptr<FakeProofSource>(
-            new FakeProofSource(server_handshake_success)),
-        TlsServerHandshaker::CreateSslCtx());
-    // Provide server with serialized config string to prove ownership.
-    QuicCryptoServerConfig::ConfigOptions options;
-    std::unique_ptr<QuicServerConfigProtobuf> primary_config(
-        server_config->GenerateConfig(QuicRandom::GetInstance(), &clock_,
-                                      options));
-    std::unique_ptr<CryptoHandshakeMessage> message(
-        server_config->AddConfig(std::move(primary_config), clock_.WallNow()));
-
-    server_peer_->SetServerCryptoConfig(server_config);
   }
 
   std::unique_ptr<QuartcSessionForTest> CreateSession(
@@ -490,7 +368,7 @@
       std::unique_ptr<QuartcPacketWriter> writer) {
     std::unique_ptr<QuicConnection> quic_connection =
         CreateConnection(perspective, writer.get());
-    string remote_fingerprint_value = "value";
+    QuicString remote_fingerprint_value = "value";
     QuicConfig config;
     return QuicMakeUnique<QuartcSessionForTest>(
         std::move(quic_connection), config, remote_fingerprint_value,
@@ -501,22 +379,14 @@
                                                    QuartcPacketWriter* writer) {
     QuicIpAddress ip;
     ip.FromString("0.0.0.0");
-    if (!alarm_factory_) {
-      // QuartcFactory is only used as an alarm factory.
-      QuartcFactoryConfig config;
-      config.clock = &quartc_clock_;
-      config.task_runner = &task_runner_;
-      alarm_factory_ = QuicMakeUnique<QuartcFactory>(config);
-    }
-
     return QuicMakeUnique<QuicConnection>(
         0, QuicSocketAddress(ip, 0), this /*QuicConnectionHelperInterface*/,
-        alarm_factory_.get(), writer, /*owns_writer=*/false, perspective,
+        &alarm_factory_, writer, /*owns_writer=*/false, perspective,
         CurrentSupportedVersions());
   }
 
   // Runs all tasks scheduled in the next 200 ms.
-  void RunTasks() { task_runner_.Run(200); }
+  void RunTasks() { alarm_factory_.Run(200); }
 
   void StartHandshake() {
     server_peer_->StartCryptoHandshake();
@@ -532,23 +402,9 @@
     ASSERT_TRUE(server_peer_->IsEncryptionEstablished());
     ASSERT_TRUE(client_peer_->IsEncryptionEstablished());
 
-    uint8_t server_key[kOutputKeyLength];
-    uint8_t client_key[kOutputKeyLength];
-    bool use_context = true;
-    bool server_success = server_peer_->ExportKeyingMaterial(
-        kExporterLabel, kExporterContext, kExporterContextLen, use_context,
-        server_key, kOutputKeyLength);
-    ASSERT_TRUE(server_success);
-    bool client_success = client_peer_->ExportKeyingMaterial(
-        kExporterLabel, kExporterContext, kExporterContextLen, use_context,
-        client_key, kOutputKeyLength);
-    ASSERT_TRUE(client_success);
-    EXPECT_EQ(0, memcmp(server_key, client_key, sizeof(server_key)));
-
     // Now we can establish encrypted outgoing stream.
-    QuartcStreamInterface* outgoing_stream =
-        server_peer_->CreateOutgoingStream(kDefaultStreamParam);
-    QuicStreamId stream_id = outgoing_stream->stream_id();
+    QuartcStream* outgoing_stream = server_peer_->CreateOutgoingDynamicStream();
+    QuicStreamId stream_id = outgoing_stream->id();
     ASSERT_NE(nullptr, outgoing_stream);
     EXPECT_TRUE(server_peer_->HasOpenDynamicStreams());
 
@@ -558,16 +414,16 @@
     char kTestMessage[] = "Hello";
     test::QuicTestMemSliceVector data(
         {std::make_pair(kTestMessage, strlen(kTestMessage))});
-    outgoing_stream->Write(data.span(), kDefaultWriteParam);
+    outgoing_stream->WriteMemSlices(data.span(), /*fin=*/false);
     RunTasks();
 
     // Wait for peer 2 to receive messages.
     ASSERT_TRUE(client_peer_->has_data());
 
-    QuartcStreamInterface* incoming =
+    QuartcStream* incoming =
         client_peer_->session_delegate()->incoming_stream();
     ASSERT_TRUE(incoming);
-    EXPECT_EQ(incoming->stream_id(), stream_id);
+    EXPECT_EQ(incoming->id(), stream_id);
     EXPECT_TRUE(client_peer_->HasOpenDynamicStreams());
 
     EXPECT_EQ(client_peer_->data()[stream_id], kTestMessage);
@@ -575,7 +431,7 @@
     char kTestResponse[] = "Response";
     test::QuicTestMemSliceVector response(
         {std::make_pair(kTestResponse, strlen(kTestResponse))});
-    incoming->Write(response.span(), kDefaultWriteParam);
+    incoming->WriteMemSlices(response.span(), /*fin=*/false);
     RunTasks();
     // Wait for peer 1 to receive messages.
     ASSERT_TRUE(server_peer_->has_data());
@@ -606,10 +462,9 @@
   }
 
  protected:
-  std::unique_ptr<QuicAlarmFactory> alarm_factory_;
-  SimpleBufferAllocator buffer_allocator_;
   MockClock clock_;
-  MockQuartcClock quartc_clock_{&clock_};
+  FakeAlarmFactory alarm_factory_{&clock_};
+  SimpleBufferAllocator buffer_allocator_;
 
   std::unique_ptr<FakeTransportChannel> client_channel_;
   std::unique_ptr<FakeTransportChannel> server_channel_;
@@ -619,8 +474,6 @@
   std::unique_ptr<QuartcPacketWriter> server_writer_;
   std::unique_ptr<QuartcSessionForTest> client_peer_;
   std::unique_ptr<QuartcSessionForTest> server_peer_;
-
-  FakeTaskRunner task_runner_{&clock_};
 };
 
 TEST_F(QuartcSessionTest, StreamConnection) {
@@ -629,42 +482,19 @@
   TestStreamConnection();
 }
 
-TEST_F(QuartcSessionTest, ClientRejection) {
-  CreateClientAndServerSessions(false /*client_handshake_success*/,
-                                true /*server_handshake_success*/);
+TEST_F(QuartcSessionTest, PreSharedKeyHandshake) {
+  CreateClientAndServerSessions();
+  client_peer_->SetPreSharedKey("foo");
+  server_peer_->SetPreSharedKey("foo");
   StartHandshake();
-  TestDisconnectAfterFailedHandshake();
-}
-
-TEST_F(QuartcSessionTest, ServerRejection) {
-  CreateClientAndServerSessions(true /*client_handshake_success*/,
-                                false /*server_handshake_success*/);
-  StartHandshake();
-  TestDisconnectAfterFailedHandshake();
+  TestStreamConnection();
 }
 
 // Test that data streams are not created before handshake.
 TEST_F(QuartcSessionTest, CannotCreateDataStreamBeforeHandshake) {
   CreateClientAndServerSessions();
-  EXPECT_EQ(nullptr, server_peer_->CreateOutgoingStream(kDefaultStreamParam));
-  EXPECT_EQ(nullptr, client_peer_->CreateOutgoingStream(kDefaultStreamParam));
-}
-
-TEST_F(QuartcSessionTest, CloseQuartcStream) {
-  CreateClientAndServerSessions();
-  StartHandshake();
-  ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
-  ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
-  QuartcStreamInterface* stream =
-      client_peer_->CreateOutgoingStream(kDefaultStreamParam);
-  ASSERT_NE(nullptr, stream);
-
-  uint32_t id = stream->stream_id();
-  EXPECT_FALSE(client_peer_->IsClosedStream(id));
-  stream->SetDelegate(client_peer_->stream_delegate());
-  stream->Close();
-  RunTasks();
-  EXPECT_TRUE(client_peer_->IsClosedStream(id));
+  EXPECT_EQ(nullptr, server_peer_->CreateOutgoingDynamicStream());
+  EXPECT_EQ(nullptr, client_peer_->CreateOutgoingDynamicStream());
 }
 
 TEST_F(QuartcSessionTest, CancelQuartcStream) {
@@ -673,11 +503,10 @@
   ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
   ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
 
-  QuartcStreamInterface* stream =
-      client_peer_->CreateOutgoingStream(kDefaultStreamParam);
+  QuartcStream* stream = client_peer_->CreateOutgoingDynamicStream();
   ASSERT_NE(nullptr, stream);
 
-  uint32_t id = stream->stream_id();
+  uint32_t id = stream->id();
   EXPECT_FALSE(client_peer_->IsClosedStream(id));
   stream->SetDelegate(client_peer_->stream_delegate());
   client_peer_->CancelStream(id);
@@ -686,103 +515,19 @@
   EXPECT_TRUE(client_peer_->IsClosedStream(id));
 }
 
-TEST_F(QuartcSessionTest, BundleWrites) {
-  CreateClientAndServerSessions();
-  StartHandshake();
-  ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
-  ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
-
-  client_peer_->BundleWrites();
-  QuartcStreamInterface* first =
-      client_peer_->CreateOutgoingStream(kDefaultStreamParam);
-  QuicStreamId first_id = first->stream_id();
-  first->SetDelegate(client_peer_->stream_delegate());
-
-  char kFirstMessage[] = "Hello";
-  test::QuicTestMemSliceVector first_data(
-      {std::make_pair(kFirstMessage, strlen(kFirstMessage))});
-  first->Write(first_data.span(), kDefaultWriteParam);
-  RunTasks();
-
-  // Server should not receive any data until the client flushes writes.
-  EXPECT_FALSE(server_peer_->has_data());
-
-  QuartcStreamInterface* second =
-      client_peer_->CreateOutgoingStream(kDefaultStreamParam);
-  QuicStreamId second_id = second->stream_id();
-  second->SetDelegate(client_peer_->stream_delegate());
-
-  char kSecondMessage[] = "World";
-  test::QuicTestMemSliceVector second_data(
-      {std::make_pair(kSecondMessage, strlen(kSecondMessage))});
-  second->Write(second_data.span(), kDefaultWriteParam);
-  RunTasks();
-
-  EXPECT_FALSE(server_peer_->has_data());
-
-  client_peer_->FlushWrites();
-  RunTasks();
-
-  ASSERT_TRUE(server_peer_->has_data());
-  EXPECT_EQ(server_peer_->data()[first_id], kFirstMessage);
-  EXPECT_EQ(server_peer_->data()[second_id], kSecondMessage);
-}
-
-TEST_F(QuartcSessionTest, StopBundlingOnIncomingData) {
-  CreateClientAndServerSessions();
-  StartHandshake();
-  ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
-  ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
-
-  client_peer_->BundleWrites();
-  QuartcStreamInterface* first =
-      client_peer_->CreateOutgoingStream(kDefaultStreamParam);
-  QuicStreamId first_id = first->stream_id();
-  first->SetDelegate(client_peer_->stream_delegate());
-
-  char kFirstMessage[] = "Hello";
-  test::QuicTestMemSliceVector first_data(
-      {std::make_pair(kFirstMessage, strlen(kFirstMessage))});
-  first->Write(first_data.span(), kDefaultWriteParam);
-  RunTasks();
-
-  // Server should not receive any data until the client flushes writes.
-  EXPECT_FALSE(server_peer_->has_data());
-
-  QuartcStreamInterface* second =
-      server_peer_->CreateOutgoingStream(kDefaultStreamParam);
-  QuicStreamId second_id = second->stream_id();
-  second->SetDelegate(server_peer_->stream_delegate());
-
-  char kSecondMessage[] = "World";
-  test::QuicTestMemSliceVector second_data(
-      {std::make_pair(kSecondMessage, strlen(kSecondMessage))});
-  second->Write(second_data.span(), kDefaultWriteParam);
-  RunTasks();
-
-  ASSERT_TRUE(client_peer_->has_data());
-  EXPECT_EQ(client_peer_->data()[second_id], kSecondMessage);
-
-  // Server should receive data as well, since the client stops bundling to
-  // process incoming packets.
-  ASSERT_TRUE(server_peer_->has_data());
-  EXPECT_EQ(server_peer_->data()[first_id], kFirstMessage);
-}
-
 TEST_F(QuartcSessionTest, WriterGivesPacketNumberToTransport) {
   CreateClientAndServerSessions();
   StartHandshake();
   ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
   ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
 
-  QuartcStreamInterface* stream =
-      client_peer_->CreateOutgoingStream(kDefaultStreamParam);
+  QuartcStream* stream = client_peer_->CreateOutgoingDynamicStream();
   stream->SetDelegate(client_peer_->stream_delegate());
 
   char kClientMessage[] = "Hello";
   test::QuicTestMemSliceVector stream_data(
       {std::make_pair(kClientMessage, strlen(kClientMessage))});
-  stream->Write(stream_data.span(), kDefaultWriteParam);
+  stream->WriteMemSlices(stream_data.span(), /*fin=*/false);
   RunTasks();
 
   // The transport should see the latest packet number sent by QUIC.
@@ -791,33 +536,6 @@
       client_peer_->connection()->sent_packet_manager().GetLargestSentPacket());
 }
 
-TEST_F(QuartcSessionTest, GetStats) {
-  CreateClientAndServerSessions();
-  StartHandshake();
-  ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
-  ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
-
-  QuicConnectionStats stats = server_peer_->GetStats();
-  EXPECT_GT(stats.estimated_bandwidth, QuicBandwidth::Zero());
-  EXPECT_GT(stats.srtt_us, 0);
-  EXPECT_GT(stats.packets_sent, 0u);
-  EXPECT_EQ(stats.packets_lost, 0u);
-}
-
-TEST_F(QuartcSessionTest, DISABLED_PacketLossStats) {
-  CreateClientAndServerSessions();
-  StartHandshake();
-  ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
-  ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
-
-  // Packet loss doesn't count until the handshake is done.
-  server_transport_->set_packets_to_lose(1);
-  TestStreamConnection();
-
-  QuicConnectionStats stats = server_peer_->GetStats();
-  EXPECT_EQ(stats.packets_lost, 1u);
-}
-
 TEST_F(QuartcSessionTest, CloseConnection) {
   CreateClientAndServerSessions();
   StartHandshake();
@@ -833,3 +551,4 @@
 }  // namespace
 
 }  // namespace quic
+#endif  // !defined(OS_IOS)
diff --git a/net/third_party/quic/quartc/quartc_session_visitor_interface.h b/net/third_party/quic/quartc/quartc_session_visitor_interface.h
deleted file mode 100644
index 7cd75c6..0000000
--- a/net/third_party/quic/quartc/quartc_session_visitor_interface.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 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 NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_SESSION_VISITOR_INTERFACE_H_
-#define NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_SESSION_VISITOR_INTERFACE_H_
-
-#include "net/third_party/quic/core/quic_connection.h"
-#include "net/third_party/quic/platform/api/quic_export.h"
-
-namespace quic {
-
-// QuartcSessionVisitor observes internals of a Quartc/QUIC session for the
-// purpose of gathering metrics or debug information.
-class QUIC_EXPORT_PRIVATE QuartcSessionVisitor {
- public:
-  virtual ~QuartcSessionVisitor() {}
-
-  // Informs this visitor of a |QuicConnection| for the session.
-  // Called once when the visitor is attached to a QuartcSession, or when a new
-  // |QuicConnection| starts.
-  virtual void OnQuicConnection(QuicConnection* connection) {}
-
-  // Called when a packet has been sent.
-  virtual void OnPacketSent(const SerializedPacket& serialized_packet,
-                            QuicPacketNumber original_packet_number,
-                            TransmissionType transmission_type,
-                            QuicTime sent_time) {}
-
-  // Called when an ack is received.
-  virtual void OnIncomingAck(const QuicAckFrame& ack_frame,
-                             QuicTime ack_receive_time,
-                             QuicPacketNumber largest_observed,
-                             bool rtt_updated,
-                             QuicPacketNumber least_unacked_sent_packet) {}
-
-  // Called when a packet is lost.
-  virtual void OnPacketLoss(QuicPacketNumber lost_packet_number,
-                            TransmissionType transmission_type,
-                            QuicTime detection_time) {}
-
-  // Called when a WindowUpdateFrame is received.
-  virtual void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame,
-                                   const QuicTime& receive_time) {}
-
-  // Called when version negotiation succeeds.
-  virtual void OnSuccessfulVersionNegotiation(
-      const ParsedQuicVersion& version) {}
-};
-
-}  // namespace quic
-
-#endif  // NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_SESSION_VISITOR_INTERFACE_H_
diff --git a/net/third_party/quic/quartc/quartc_stream.cc b/net/third_party/quic/quartc/quartc_stream.cc
index 8c628cf..6cbce4a 100644
--- a/net/third_party/quic/quartc/quartc_stream.cc
+++ b/net/third_party/quic/quartc/quartc_stream.cc
@@ -50,39 +50,11 @@
   delegate_->OnBufferChanged(this);
 }
 
-uint32_t QuartcStream::stream_id() {
-  return id();
-}
-
-uint64_t QuartcStream::bytes_buffered() {
-  return BufferedDataBytes();
-}
-
-bool QuartcStream::fin_sent() {
-  return QuicStream::fin_sent();
-}
-
-int QuartcStream::stream_error() {
-  return QuicStream::stream_error();
-}
-
-void QuartcStream::Write(QuicMemSliceSpan data, const WriteParameters& param) {
-  WriteMemSlices(data, param.fin);
-}
-
 void QuartcStream::FinishWriting() {
   WriteOrBufferData(QuicStringPiece(nullptr, 0), true, nullptr);
 }
 
-void QuartcStream::FinishReading() {
-  QuicStream::StopReading();
-}
-
-void QuartcStream::Close() {
-  QuicStream::session()->CloseStream(id());
-}
-
-void QuartcStream::SetDelegate(QuartcStreamInterface::Delegate* delegate) {
+void QuartcStream::SetDelegate(Delegate* delegate) {
   if (delegate_) {
     LOG(WARNING) << "The delegate for Stream " << id()
                  << " has already been set.";
diff --git a/net/third_party/quic/quartc/quartc_stream.h b/net/third_party/quic/quartc/quartc_stream.h
index 7a7173e..830d45f 100644
--- a/net/third_party/quic/quartc/quartc_stream.h
+++ b/net/third_party/quic/quartc/quartc_stream.h
@@ -8,13 +8,15 @@
 #include "net/third_party/quic/core/quic_session.h"
 #include "net/third_party/quic/core/quic_stream.h"
 #include "net/third_party/quic/platform/api/quic_export.h"
-#include "net/third_party/quic/quartc/quartc_stream_interface.h"
+#include "net/third_party/quic/platform/api/quic_mem_slice_span.h"
 
 namespace quic {
 
-// Implements a QuartcStreamInterface using a QuicStream.
-class QUIC_EXPORT_PRIVATE QuartcStream : public QuicStream,
-                                         public QuartcStreamInterface {
+// Sends and receives data with a particular QUIC stream ID, reliably and
+// in-order. To send/receive data out of order, use separate streams. To
+// send/receive unreliably, close a stream after reliability is no longer
+// needed.
+class QUIC_EXPORT_PRIVATE QuartcStream : public QuicStream {
  public:
   QuartcStream(QuicStreamId id, QuicSession* session);
 
@@ -33,27 +35,43 @@
       const QuicReferenceCountedPointer<QuicAckListenerInterface>& ack_listener)
       override;
 
-  // QuartcStreamInterface overrides.
-  uint32_t stream_id() override;
+  // QuartcStream interface methods.
 
-  uint64_t bytes_buffered() override;
+  // Marks this stream as finished writing.  Asynchronously sends a FIN and
+  // closes the write-side.  It is not necessary to call FinishWriting() if the
+  // last call to Write() sends a FIN.
+  void FinishWriting();
 
-  bool fin_sent() override;
+  // Implemented by the user of the QuartcStream to receive incoming
+  // data and be notified of state changes.
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
 
-  int stream_error() override;
+    // Called when the stream receives data.  Called with |size| == 0 after all
+    // stream data has been delivered (once the stream receives a FIN bit).
+    // Note that the same packet may include both data and a FIN bit, causing
+    // this method to be called twice.
+    virtual void OnReceived(QuartcStream* stream,
+                            const char* data,
+                            size_t size) = 0;
 
-  void Write(QuicMemSliceSpan data, const WriteParameters& param) override;
+    // Called when the stream is closed, either locally or by the remote
+    // endpoint.  Streams close when (a) fin bits are both sent and received,
+    // (b) Close() is called, or (c) the stream is reset.
+    // TODO(zhihuang) Creates a map from the integer error_code to WebRTC native
+    // error code.
+    virtual void OnClose(QuartcStream* stream) = 0;
 
-  void FinishWriting() override;
+    // Called when the contents of the stream's buffer changes.
+    virtual void OnBufferChanged(QuartcStream* stream) = 0;
+  };
 
-  void FinishReading() override;
-
-  void Close() override;
-
-  void SetDelegate(QuartcStreamInterface::Delegate* delegate) override;
+  // The |delegate| is not owned by QuartcStream.
+  void SetDelegate(Delegate* delegate);
 
  private:
-  QuartcStreamInterface::Delegate* delegate_ = nullptr;
+  Delegate* delegate_ = nullptr;
 };
 
 }  // namespace quic
diff --git a/net/third_party/quic/quartc/quartc_stream_interface.h b/net/third_party/quic/quartc/quartc_stream_interface.h
deleted file mode 100644
index 9f3f600..0000000
--- a/net/third_party/quic/quartc/quartc_stream_interface.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 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 NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_STREAM_INTERFACE_H_
-#define NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_STREAM_INTERFACE_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "net/third_party/quic/platform/api/quic_export.h"
-#include "net/third_party/quic/platform/api/quic_mem_slice_span.h"
-
-namespace quic {
-
-// Sends and receives data with a particular QUIC stream ID, reliably and
-// in-order. To send/receive data out of order, use separate streams. To
-// send/receive unreliably, close a stream after reliability is no longer
-// needed.
-class QUIC_EXPORT_PRIVATE QuartcStreamInterface {
- public:
-  virtual ~QuartcStreamInterface() {}
-
-  // The QUIC stream ID.
-  virtual uint32_t stream_id() = 0;
-
-  // The amount of data buffered on this stream.
-  virtual uint64_t bytes_buffered() = 0;
-
-  // Return true if the FIN has been sent. Used by the outgoing streams to
-  // determine if all the data has been sent
-  virtual bool fin_sent() = 0;
-
-  virtual int stream_error() = 0;
-
-  struct WriteParameters {
-    // |fin| is set to be true when there is no more data need to be send
-    // through a particular stream. The receiving side will used it to determine
-    // if the sender finish sending data.
-    bool fin = false;
-  };
-
-  // Sends data reliably and in-order.  Returns the amount sent.
-  // Does not buffer data.
-  virtual void Write(QuicMemSliceSpan data, const WriteParameters& param) = 0;
-
-  // Marks this stream as finished writing.  Asynchronously sends a FIN and
-  // closes the write-side.  The stream will no longer call OnCanWrite().
-  // It is not necessary to call FinishWriting() if the last call to Write()
-  // sends a FIN.
-  virtual void FinishWriting() = 0;
-
-  // Marks this stream as finished reading.  Further incoming data is discarded.
-  // The stream will no longer call OnReceived().
-  // It is never necessary to call FinishReading().  The read-side closes when a
-  // FIN is received, regardless of whether FinishReading() has been called.
-  virtual void FinishReading() = 0;
-
-  // Once Close is called, no more data can be sent, all buffered data will be
-  // dropped and no data will be retransmitted.
-  virtual void Close() = 0;
-
-  // Implemented by the user of the QuartcStreamInterface to receive incoming
-  // data and be notified of state changes.
-  class Delegate {
-   public:
-    virtual ~Delegate() {}
-
-    // Called when the stream receives the data.  Called with |size| == 0 after
-    // all stream data has been delivered.
-    virtual void OnReceived(QuartcStreamInterface* stream,
-                            const char* data,
-                            size_t size) = 0;
-
-    // Called when the stream is closed, either locally or by the remote
-    // endpoint.  Streams close when (a) fin bits are both sent and received,
-    // (b) Close() is called, or (c) the stream is reset.
-    // TODO(zhihuang) Creates a map from the integer error_code to WebRTC native
-    // error code.
-    virtual void OnClose(QuartcStreamInterface* stream) = 0;
-
-    // Called when the contents of the stream's buffer changes.
-    virtual void OnBufferChanged(QuartcStreamInterface* stream) = 0;
-  };
-
-  // The |delegate| is not owned by QuartcStream.
-  virtual void SetDelegate(Delegate* delegate) = 0;
-};
-
-}  // namespace quic
-
-#endif  // NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_STREAM_INTERFACE_H_
diff --git a/net/third_party/quic/quartc/quartc_stream_test.cc b/net/third_party/quic/quartc/quartc_stream_test.cc
index 66e3673..353990ec 100644
--- a/net/third_party/quic/quartc/quartc_stream_test.cc
+++ b/net/third_party/quic/quartc/quartc_stream_test.cc
@@ -11,9 +11,9 @@
 #include "net/third_party/quic/platform/api/quic_ptr_util.h"
 #include "net/third_party/quic/platform/api/quic_test.h"
 #include "net/third_party/quic/platform/api/quic_test_mem_slice_vector.h"
-#include "net/third_party/quic/quartc/quartc_clock_interface.h"
 #include "net/third_party/quic/quartc/quartc_factory.h"
 #include "net/third_party/quic/test_tools/mock_clock.h"
+#include "net/third_party/quic/test_tools/quic_test_utils.h"
 #include "net/third_party/spdy/core/spdy_protocol.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -23,7 +23,6 @@
 namespace {
 
 static const QuicStreamId kStreamId = 5;
-static const QuartcStreamInterface::WriteParameters kDefaultParam;
 
 // MockQuicSession that does not create streams and writes data from
 // QuicStream to a string.
@@ -31,7 +30,7 @@
  public:
   MockQuicSession(QuicConnection* connection,
                   const QuicConfig& config,
-                  std::string* write_buffer)
+                  QuicString* write_buffer)
       : QuicSession(connection, nullptr /*visitor*/, config),
         write_buffer_(write_buffer) {}
 
@@ -92,7 +91,7 @@
 
  private:
   // Stores written data from ReliableQuicStreamAdapter.
-  std::string* write_buffer_;
+  QuicString* write_buffer_;
   // Whether data is written to write_buffer_.
   bool writable_ = true;
 };
@@ -132,23 +131,23 @@
   WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); }
 };
 
-class MockQuartcStreamDelegate : public QuartcStreamInterface::Delegate {
+class MockQuartcStreamDelegate : public QuartcStream::Delegate {
  public:
-  MockQuartcStreamDelegate(int id, std::string* read_buffer)
+  MockQuartcStreamDelegate(int id, QuicString* read_buffer)
       : id_(id), read_buffer_(read_buffer) {}
 
-  void OnBufferChanged(QuartcStreamInterface* stream) override {
-    last_bytes_buffered_ = stream->bytes_buffered();
+  void OnBufferChanged(QuartcStream* stream) override {
+    last_bytes_buffered_ = stream->BufferedDataBytes();
   }
 
-  void OnReceived(QuartcStreamInterface* stream,
+  void OnReceived(QuartcStream* stream,
                   const char* data,
                   size_t size) override {
-    EXPECT_EQ(id_, stream->stream_id());
+    EXPECT_EQ(id_, stream->id());
     read_buffer_->append(data, size);
   }
 
-  void OnClose(QuartcStreamInterface* stream) override { closed_ = true; }
+  void OnClose(QuartcStream* stream) override { closed_ = true; }
 
   bool closed() { return closed_; }
 
@@ -157,7 +156,7 @@
  protected:
   uint32_t id_;
   // Data read by the QuicStream.
-  std::string* read_buffer_;
+  QuicString* read_buffer_;
   // Whether the QuicStream is closed.
   bool closed_ = false;
 
@@ -174,9 +173,7 @@
     ip.FromString("0.0.0.0");
     bool owns_writer = true;
 
-    // We only use QuartcFactory for its role as an alarm factory.
-    QuartcFactoryConfig config;
-    alarm_factory_ = QuicMakeUnique<QuartcFactory>(config);
+    alarm_factory_ = QuicMakeUnique<test::MockAlarmFactory>();
 
     connection_ = QuicMakeUnique<QuicConnection>(
         0, QuicSocketAddress(ip, 0), this /*QuicConnectionHelperInterface*/,
@@ -210,9 +207,9 @@
   std::unique_ptr<MockQuartcStreamDelegate> mock_stream_delegate_;
   std::unique_ptr<MockQuicSession> session_;
   // Data written by the ReliableQuicStreamAdapterTest.
-  std::string write_buffer_;
+  QuicString write_buffer_;
   // Data read by the ReliableQuicStreamAdapterTest.
-  std::string read_buffer_;
+  QuicString read_buffer_;
   std::unique_ptr<QuicAlarmFactory> alarm_factory_;
   std::unique_ptr<QuicConnection> connection_;
   // Used to implement the QuicConnectionHelperInterface.
@@ -225,7 +222,7 @@
   CreateReliableQuicStream();
   char message[] = "Foo bar";
   test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
-  stream_->Write(data.span(), kDefaultParam);
+  stream_->WriteMemSlices(data.span(), /*fin=*/false);
   EXPECT_EQ("Foo bar", write_buffer_);
 }
 
@@ -234,7 +231,7 @@
   CreateReliableQuicStream();
   char message[] = "Foo bar";
   test::QuicTestMemSliceVector data({std::make_pair(message, 5)});
-  stream_->Write(data.span(), kDefaultParam);
+  stream_->WriteMemSlices(data.span(), /*fin=*/false);
   EXPECT_EQ("Foo b", write_buffer_);
 }
 
@@ -247,11 +244,11 @@
 
   // The stream is not yet writable, so data will be buffered.
   session_->set_writable(false);
-  stream_->Write(data.span(), kDefaultParam);
+  stream_->WriteMemSlices(data.span(), /*fin=*/false);
 
   // Check that data is buffered.
   EXPECT_TRUE(stream_->HasBufferedData());
-  EXPECT_EQ(7u, stream_->bytes_buffered());
+  EXPECT_EQ(7u, stream_->BufferedDataBytes());
 
   // Check that the stream told its delegate about the buffer change.
   EXPECT_EQ(7u, mock_stream_delegate_->last_bytes_buffered());
@@ -265,10 +262,10 @@
   test::QuicTestMemSliceVector data1({std::make_pair(message1, 5)});
 
   // More writes go into the buffer.
-  stream_->Write(data1.span(), kDefaultParam);
+  stream_->WriteMemSlices(data1.span(), /*fin=*/false);
 
   EXPECT_TRUE(stream_->HasBufferedData());
-  EXPECT_EQ(12u, stream_->bytes_buffered());
+  EXPECT_EQ(12u, stream_->BufferedDataBytes());
   EXPECT_EQ(12u, mock_stream_delegate_->last_bytes_buffered());
   EXPECT_EQ(0ul, write_buffer_.size());
 
@@ -277,7 +274,7 @@
   stream_->OnCanWrite();
 
   EXPECT_FALSE(stream_->HasBufferedData());
-  EXPECT_EQ(0u, stream_->bytes_buffered());
+  EXPECT_EQ(0u, stream_->BufferedDataBytes());
   EXPECT_EQ(0u, mock_stream_delegate_->last_bytes_buffered());
   EXPECT_EQ("Foo barxyzzy", write_buffer_);
 }
@@ -317,10 +314,11 @@
   EXPECT_EQ("Hello", read_buffer_);
 }
 
-// Streams do not call OnReceived() after FinishReading().
-TEST_F(QuartcStreamTest, FinishReading) {
+// Streams do not call OnReceived() after StopReading().
+// Note: this is tested here because Quartc relies on this behavior.
+TEST_F(QuartcStreamTest, StopReading) {
   CreateReliableQuicStream();
-  stream_->FinishReading();
+  stream_->StopReading();
 
   QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!");
   stream_->OnStreamFrame(frame);
@@ -348,10 +346,8 @@
   QuicStreamFrame frame(kStreamId, true, 0, 0);
   stream_->OnStreamFrame(frame);
 
-  QuartcStreamInterface::WriteParameters param;
-  param.fin = true;
   test::QuicTestMemSliceVector data({});
-  stream_->Write(data.span(), param);
+  stream_->WriteMemSlices(data.span(), /*fin=*/true);
 
   // Check that the OnClose() callback occurred.
   EXPECT_TRUE(mock_stream_delegate_->closed());
diff --git a/net/third_party/quic/quartc/quartc_task_runner_interface.h b/net/third_party/quic/quartc/quartc_task_runner_interface.h
deleted file mode 100644
index b3560b3c..0000000
--- a/net/third_party/quic/quartc/quartc_task_runner_interface.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 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 NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_TASK_RUNNER_INTERFACE_H_
-#define NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_TASK_RUNNER_INTERFACE_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-namespace quic {
-
-// Used by platform specific QuicAlarms. For example, WebRTC will use it to set
-// and cancel an alarm. When setting an alarm, the task runner will schedule a
-// task on rtc::Thread. When canceling an alarm, the canceler for that task will
-// be called.
-class QuartcTaskRunnerInterface {
- public:
-  virtual ~QuartcTaskRunnerInterface() {}
-
-  class Task {
-   public:
-    virtual ~Task() {}
-
-    // Called when it's time to start the task.
-    virtual void Run() = 0;
-  };
-
-  // A handler used to cancel a scheduled task. In some cases, a task cannot
-  // be directly canceled with its pointer. For example, in WebRTC, the task
-  // will be scheduled on rtc::Thread. When canceling a task, its pointer cannot
-  // locate the scheduled task in the thread message queue. So when scheduling a
-  // task, an additional handler (ScheduledTask) will be returned.
-  class ScheduledTask {
-   public:
-    virtual ~ScheduledTask() {}
-
-    // Cancels a scheduled task, meaning the task will not be run.
-    virtual void Cancel() = 0;
-  };
-
-  // Schedules a task, which will be run after the given delay. A ScheduledTask
-  // may be used to cancel the task.
-  virtual std::unique_ptr<ScheduledTask> Schedule(Task* task,
-                                                  uint64_t delay_ms) = 0;
-};
-
-}  // namespace quic
-
-#endif  // NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_TASK_RUNNER_INTERFACE_H_
diff --git a/net/url_request/url_request_ftp_job.cc b/net/url_request/url_request_ftp_job.cc
index 8e5b990b..cebe3a8be 100644
--- a/net/url_request/url_request_ftp_job.cc
+++ b/net/url_request/url_request_ftp_job.cc
@@ -46,7 +46,6 @@
       priority_(DEFAULT_PRIORITY),
       proxy_resolution_service_(
           request_->context()->proxy_resolution_service()),
-      proxy_resolve_request_(NULL),
       http_response_info_(NULL),
       read_in_progress_(false),
       ftp_transaction_factory_(ftp_transaction_factory),
@@ -129,8 +128,7 @@
 
 void URLRequestFtpJob::Kill() {
   if (proxy_resolve_request_) {
-    proxy_resolution_service_->CancelRequest(proxy_resolve_request_);
-    proxy_resolve_request_ = nullptr;
+    proxy_resolve_request_.reset();
   }
   if (ftp_transaction_)
     ftp_transaction_.reset();
@@ -282,7 +280,7 @@
 
 LoadState URLRequestFtpJob::GetLoadState() const {
   if (proxy_resolve_request_)
-    return proxy_resolution_service_->GetLoadState(proxy_resolve_request_);
+    return proxy_resolve_request_->GetLoadState();
   if (proxy_info_.is_direct()) {
     return ftp_transaction_ ?
         ftp_transaction_->GetLoadState() : LOAD_STATE_IDLE;
diff --git a/net/url_request/url_request_ftp_job.h b/net/url_request/url_request_ftp_job.h
index 9b56e7c..1e701c96 100644
--- a/net/url_request/url_request_ftp_job.h
+++ b/net/url_request/url_request_ftp_job.h
@@ -81,7 +81,7 @@
 
   ProxyResolutionService* proxy_resolution_service_;
   ProxyInfo proxy_info_;
-  ProxyResolutionService::Request* proxy_resolve_request_;
+  std::unique_ptr<ProxyResolutionService::Request> proxy_resolve_request_;
 
   FtpRequestInfo ftp_request_info_;
   std::unique_ptr<FtpTransaction> ftp_transaction_;
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 4b2b45f..a3585e47 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -2022,7 +2022,7 @@
   // Before there's a proxy configuration, proxy requests should hang.
   net::ProxyInfo proxy_info;
   net::TestCompletionCallback test_callback;
-  net::ProxyResolutionService::Request* request = nullptr;
+  std::unique_ptr<net::ProxyResolutionService::Request> request = nullptr;
   ASSERT_EQ(net::ERR_IO_PENDING, proxy_resolution_service->ResolveProxy(
                                      GURL("http://bar/"), "GET", &proxy_info,
                                      test_callback.callback(), &request,
diff --git a/services/network/proxy_resolving_client_socket.cc b/services/network/proxy_resolving_client_socket.cc
index 27d701b..145ba1ca 100644
--- a/services/network/proxy_resolving_client_socket.cc
+++ b/services/network/proxy_resolving_client_socket.cc
@@ -37,7 +37,6 @@
     : network_session_(network_session),
       socket_handle_(std::make_unique<net::ClientSocketHandle>()),
       ssl_config_(ssl_config),
-      proxy_resolve_request_(nullptr),
       url_(url),
       use_tls_(use_tls),
       net_log_(net::NetLogWithSource::Make(network_session_->net_log(),
@@ -117,9 +116,7 @@
 void ProxyResolvingClientSocket::Disconnect() {
   CloseSocket(true /*close_connection*/);
   if (proxy_resolve_request_) {
-    network_session_->proxy_resolution_service()->CancelRequest(
-        proxy_resolve_request_);
-    proxy_resolve_request_ = nullptr;
+    proxy_resolve_request_.reset();
   }
   user_connect_callback_.Reset();
 }
diff --git a/services/network/proxy_resolving_client_socket.h b/services/network/proxy_resolving_client_socket.h
index d5e82b88..da4d179a 100644
--- a/services/network/proxy_resolving_client_socket.h
+++ b/services/network/proxy_resolving_client_socket.h
@@ -127,7 +127,7 @@
   std::unique_ptr<net::ClientSocketHandle> socket_handle_;
 
   const net::SSLConfig ssl_config_;
-  net::ProxyResolutionService::Request* proxy_resolve_request_;
+  std::unique_ptr<net::ProxyResolutionService::Request> proxy_resolve_request_;
   net::ProxyInfo proxy_info_;
   const GURL url_;
   const bool use_tls_;
diff --git a/services/network/public/cpp/network_ipc_param_traits.h b/services/network/public/cpp/network_ipc_param_traits.h
index 76ecabe..f330a76c 100644
--- a/services/network/public/cpp/network_ipc_param_traits.h
+++ b/services/network/public/cpp/network_ipc_param_traits.h
@@ -204,7 +204,6 @@
   IPC_STRUCT_TRAITS_MEMBER(ssl_info)
   IPC_STRUCT_TRAITS_MEMBER(cors_exposed_header_names)
   IPC_STRUCT_TRAITS_MEMBER(async_revalidation_requested)
-  IPC_STRUCT_TRAITS_MEMBER(did_mime_sniff)
 IPC_STRUCT_TRAITS_END()
 
 IPC_ENUM_TRAITS_MAX_VALUE(network::mojom::FetchResponseType,
diff --git a/services/network/public/cpp/resource_response.cc b/services/network/public/cpp/resource_response.cc
index bfc4f4a..7b26664 100644
--- a/services/network/public/cpp/resource_response.cc
+++ b/services/network/public/cpp/resource_response.cc
@@ -60,7 +60,6 @@
       head.should_report_corb_blocking;
   new_response->head.async_revalidation_requested =
       head.async_revalidation_requested;
-  new_response->head.did_mime_sniff = head.did_mime_sniff;
   return new_response;
 }
 
diff --git a/services/network/public/cpp/resource_response_info.cc b/services/network/public/cpp/resource_response_info.cc
index 1d06888d..343ab0a 100644
--- a/services/network/public/cpp/resource_response_info.cc
+++ b/services/network/public/cpp/resource_response_info.cc
@@ -29,8 +29,7 @@
       cert_status(0),
       did_service_worker_navigation_preload(false),
       should_report_corb_blocking(false),
-      async_revalidation_requested(false),
-      did_mime_sniff(false) {}
+      async_revalidation_requested(false) {}
 
 ResourceResponseInfo::ResourceResponseInfo(const ResourceResponseInfo& other) =
     default;
diff --git a/services/network/public/cpp/resource_response_info.h b/services/network/public/cpp/resource_response_info.h
index 3c57609..a55dec1 100644
--- a/services/network/public/cpp/resource_response_info.h
+++ b/services/network/public/cpp/resource_response_info.h
@@ -179,10 +179,6 @@
   // possibly be set if the load_flags indicated SUPPORT_ASYNC_REVALIDATION.
   bool async_revalidation_requested;
 
-  // True if mime sniffing has been done. In that case, we don't need to do
-  // mime sniffing anymore.
-  bool did_mime_sniff;
-
   // NOTE: When adding or changing fields here, also update
   // ResourceResponse::DeepCopy in resource_response.cc.
 };
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index a318975f..86d6409 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -794,7 +794,6 @@
       // the mime type. However, even if it returns false, it returns a new type
       // that is probably better than the current one.
       response_->head.mime_type.assign(new_type);
-      response_->head.did_mime_sniff = true;
     }
 
     if (is_more_corb_sniffing_needed_) {
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc
index 2751de8..68a4dcd3 100644
--- a/services/network/url_loader_unittest.cc
+++ b/services/network/url_loader_unittest.cc
@@ -521,12 +521,6 @@
     DCHECK(ran_);
     return client_.response_head().mime_type;
   }
-
-  bool did_mime_sniff() const {
-    DCHECK(ran_);
-    return client_.response_head().did_mime_sniff;
-  }
-
   const base::Optional<net::SSLInfo>& ssl_info() const {
     DCHECK(ran_);
     return client_.ssl_info();
@@ -733,7 +727,6 @@
 TEST_F(URLLoaderTest, DoNotSniffUnlessSpecified) {
   EXPECT_EQ(net::OK,
             Load(test_server()->GetURL("/content-sniffer-test0.html")));
-  EXPECT_FALSE(did_mime_sniff());
   ASSERT_TRUE(mime_type().empty());
 }
 
@@ -741,22 +734,19 @@
   set_sniff();
   EXPECT_EQ(net::OK,
             Load(test_server()->GetURL("/content-sniffer-test0.html")));
-  EXPECT_TRUE(did_mime_sniff());
   ASSERT_EQ(std::string("text/html"), mime_type());
 }
 
 TEST_F(URLLoaderTest, RespectNoSniff) {
   set_sniff();
   EXPECT_EQ(net::OK, Load(test_server()->GetURL("/nosniff-test.html")));
-  EXPECT_FALSE(did_mime_sniff());
   ASSERT_TRUE(mime_type().empty());
 }
 
-TEST_F(URLLoaderTest, SniffTextPlainDoesNotResultInHTML) {
+TEST_F(URLLoaderTest, DoNotSniffHTMLFromTextPlain) {
   set_sniff();
   EXPECT_EQ(net::OK,
             Load(test_server()->GetURL("/content-sniffer-test1.html")));
-  EXPECT_TRUE(did_mime_sniff());
   ASSERT_EQ(std::string("text/plain"), mime_type());
 }
 
@@ -764,7 +754,6 @@
   set_sniff();
   EXPECT_EQ(net::OK,
             Load(test_server()->GetURL("/content-sniffer-test2.html")));
-  EXPECT_FALSE(did_mime_sniff());
   ASSERT_EQ(std::string("image/gif"), mime_type());
 }
 
@@ -772,7 +761,6 @@
   set_sniff();
   EXPECT_EQ(net::OK,
             Load(test_server()->GetURL("/content-sniffer-test4.html")));
-  EXPECT_TRUE(did_mime_sniff());
   ASSERT_EQ(std::string("text/plain"), mime_type());
 }
 
@@ -788,7 +776,6 @@
   std::string body;
   EXPECT_EQ(net::OK, Load(MultipleWritesInterceptor::GetURL(), &body));
   EXPECT_EQ(kBody, body);
-  EXPECT_TRUE(did_mime_sniff());
   ASSERT_EQ(std::string("text/plain"), mime_type());
 }
 
@@ -803,7 +790,6 @@
   EXPECT_LE(first.size() + second.size(),
             static_cast<uint32_t>(net::kMaxBytesToSniff));
   LoadPacketsAndVerifyContents(first, second);
-  EXPECT_TRUE(did_mime_sniff());
   ASSERT_EQ(std::string("application/octet-stream"), mime_type());
 }
 
@@ -816,7 +802,6 @@
   EXPECT_GE(first.size() + second.size(),
             static_cast<uint32_t>(net::kMaxBytesToSniff));
   LoadPacketsAndVerifyContents(first, second);
-  EXPECT_TRUE(did_mime_sniff());
   ASSERT_EQ(std::string("application/octet-stream"), mime_type());
 }
 
@@ -826,7 +811,6 @@
   set_sniff();
   std::string first(net::kMaxBytesToSniff - 100, 'a');
   LoadPacketsAndVerifyContents(first, std::string());
-  EXPECT_TRUE(did_mime_sniff());
   ASSERT_EQ(std::string("text/plain"), mime_type());
 }
 
@@ -835,7 +819,6 @@
   set_sniff();
   std::string first(net::kMaxBytesToSniff + 100, 'a');
   LoadPacketsAndVerifyContents(first, std::string());
-  EXPECT_TRUE(did_mime_sniff());
   ASSERT_EQ(std::string("text/plain"), mime_type());
 }
 
diff --git a/storage/browser/quota/quota_database.cc b/storage/browser/quota/quota_database.cc
index dc8a3c3f..39699a5b 100644
--- a/storage/browser/quota/quota_database.cc
+++ b/storage/browser/quota/quota_database.cc
@@ -45,24 +45,6 @@
 
 const int kCommitIntervalMs = 30000;
 
-enum OriginType {
-  // This enum is logged to UMA so only append to it - don't change
-  // the meaning of the existing values.
-  OTHER = 0,
-  NONE = 1,
-  GOOGLE_DURABLE = 2,
-  NON_GOOGLE_DURABLE = 3,
-  GOOGLE_UNLIMITED_EXTENSION = 4,
-  NON_GOOGLE_UNLIMITED_EXTENSION = 5,
-  IN_USE = 6,
-
-  MAX_ORIGIN_TYPE
-};
-
-void HistogramOriginType(const OriginType& entry) {
-  UMA_HISTOGRAM_ENUMERATION("Quota.LRUOriginTypes", entry, MAX_ORIGIN_TYPE);
-}
-
 void LogDaysSinceLastAccess(base::Time this_time,
                             const QuotaDatabase::OriginInfoTableEntry& entry) {
   base::TimeDelta time_since = this_time - std::max(entry.last_access_time,
@@ -450,37 +432,29 @@
   if (!LazyOpen(false))
     return false;
 
-  const char* kSql = "SELECT origin FROM OriginInfoTable"
-                     " WHERE type = ?"
-                     " ORDER BY last_access_time ASC";
+  static const char kSql[] =
+      "SELECT origin FROM OriginInfoTable"
+      " WHERE type = ?"
+      " ORDER BY last_access_time ASC";
 
   sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE, kSql));
   statement.BindInt(0, static_cast<int>(type));
 
   while (statement.Step()) {
     GURL url(statement.ColumnString(0));
-    if (base::ContainsKey(exceptions, url)) {
-      HistogramOriginType(IN_USE);
+    if (base::ContainsKey(exceptions, url))
+      continue;
+
+    if (special_storage_policy && (
+        special_storage_policy->IsStorageDurable(url) ||
+        special_storage_policy->IsStorageUnlimited(url))) {
       continue;
     }
-    if (special_storage_policy) {
-      bool is_google = url.DomainIs("google.com");
-      if (special_storage_policy->IsStorageDurable(url)) {
-        HistogramOriginType(is_google ? GOOGLE_DURABLE : NON_GOOGLE_DURABLE);
-        continue;
-      }
-      if (special_storage_policy->IsStorageUnlimited(url)) {
-        HistogramOriginType(is_google ? GOOGLE_UNLIMITED_EXTENSION
-                                      : NON_GOOGLE_UNLIMITED_EXTENSION);
-        continue;
-      }
-    }
-    HistogramOriginType(OTHER);
+
     *origin = url;
     return true;
   }
 
-  HistogramOriginType(NONE);
   *origin = GURL();
   return statement.Succeeded();
 }
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 4ab245d..958f2eb 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -601,7 +601,6 @@
           "script": "//tools/perf/process_perf_results.py"
         },
         "name": "heap_profiling.mobile",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6337,7 +6336,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index f4f4487..2c29707 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -3074,7 +3074,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -19222,7 +19221,6 @@
       {
         "isolate_name": "monochrome_apk_checker",
         "name": "monochrome_apk_checker",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -21893,7 +21891,6 @@
       {
         "isolate_name": "components_perftests",
         "name": "components_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -21908,7 +21905,6 @@
       {
         "isolate_name": "monochrome_apk_checker",
         "name": "monochrome_apk_checker",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -21927,7 +21923,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index 04d473c..2243bab 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -220,8 +220,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
@@ -932,8 +931,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
@@ -10115,7 +10113,6 @@
       {
         "isolate_name": "monochrome_apk_checker",
         "name": "monochrome_apk_checker",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12985,8 +12982,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
@@ -13693,8 +13689,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
@@ -14371,8 +14366,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
@@ -15059,8 +15053,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
@@ -15757,8 +15750,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
@@ -16721,7 +16713,6 @@
         ],
         "isolate_name": "chromedriver_py_tests",
         "name": "chromedriver_py_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -16729,7 +16720,6 @@
       {
         "isolate_name": "components_perftests",
         "name": "components_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -16737,7 +16727,6 @@
       {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -16745,7 +16734,6 @@
       {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -16753,7 +16741,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -16761,7 +16748,6 @@
       {
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "hard_timeout": 960,
@@ -16774,7 +16760,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -16783,7 +16768,6 @@
       {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -16797,7 +16781,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -16814,7 +16797,6 @@
       {
         "isolate_name": "webkit_python_tests",
         "name": "webkit_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -24187,8 +24169,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 4d116cdf..c319d4d9 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -812,7 +812,6 @@
         ],
         "isolate_name": "chromedriver_py_tests",
         "name": "chromedriver_py_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -820,7 +819,6 @@
       {
         "isolate_name": "components_perftests",
         "name": "components_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -828,7 +826,6 @@
       {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -836,7 +833,6 @@
       {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -844,7 +840,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -852,7 +847,6 @@
       {
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "hard_timeout": 960,
@@ -865,7 +859,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -874,7 +867,6 @@
       {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -888,7 +880,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -898,7 +889,6 @@
       {
         "isolate_name": "webkit_python_tests",
         "name": "webkit_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1052,7 +1042,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "hard_timeout": 960,
@@ -1066,7 +1055,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests_viz",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "hard_timeout": 960,
@@ -1076,7 +1064,6 @@
       {
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -1088,7 +1075,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests_viz",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -1576,7 +1562,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -1709,7 +1694,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -1773,8 +1757,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
@@ -1854,7 +1837,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -1883,7 +1865,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -1912,7 +1893,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -2989,7 +2969,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3015,7 +2994,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3463,7 +3441,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true
@@ -3728,7 +3705,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -3990,7 +3966,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -4010,7 +3985,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -4254,8 +4228,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
@@ -4735,7 +4708,6 @@
         ],
         "isolate_name": "chromedriver_py_tests",
         "name": "chromedriver_py_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -4743,7 +4715,6 @@
       {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -4751,7 +4722,6 @@
       {
         "isolate_name": "devtools_closure_compile",
         "name": "devtools_closure_compile",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -4759,7 +4729,6 @@
       {
         "isolate_name": "devtools_eslint",
         "name": "devtools_eslint",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -4767,7 +4736,6 @@
       {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -4789,7 +4757,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "site_per_process_webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -4804,7 +4771,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -4812,7 +4778,6 @@
       {
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "hard_timeout": 960,
@@ -4825,7 +4790,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -4834,7 +4798,6 @@
       {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -4848,7 +4811,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -4858,7 +4820,6 @@
       {
         "isolate_name": "webkit_python_tests",
         "name": "webkit_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -5587,7 +5548,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -5613,7 +5573,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -5639,7 +5598,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -5666,7 +5624,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -5694,7 +5651,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -5730,7 +5686,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -5756,7 +5711,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index adb2085..fe9ec4f 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -82,7 +82,6 @@
         ],
         "isolate_name": "angle_perftests",
         "name": "angle_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -178,7 +177,6 @@
         ],
         "isolate_name": "angle_perftests",
         "name": "angle_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -362,7 +360,6 @@
         ],
         "isolate_name": "angle_perftests",
         "name": "angle_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -458,7 +455,6 @@
         ],
         "isolate_name": "angle_perftests",
         "name": "angle_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -747,7 +743,6 @@
         ],
         "isolate_name": "angle_perftests",
         "name": "angle_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -771,7 +766,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -795,7 +789,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -819,7 +812,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -843,7 +835,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -871,7 +862,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -902,7 +892,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -938,7 +927,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -966,7 +954,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -990,7 +977,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1015,7 +1001,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1182,7 +1167,6 @@
         ],
         "isolate_name": "angle_perftests",
         "name": "angle_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1206,7 +1190,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1230,7 +1213,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1254,7 +1236,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1278,7 +1259,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1306,7 +1286,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1337,7 +1316,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1373,7 +1351,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -1401,7 +1378,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1425,7 +1401,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1450,7 +1425,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1545,7 +1519,6 @@
         ],
         "isolate_name": "angle_perftests",
         "name": "angle_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1568,7 +1541,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1591,7 +1563,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1614,7 +1585,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1637,7 +1607,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1664,7 +1633,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1694,7 +1662,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1729,7 +1696,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -1756,7 +1722,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1779,7 +1744,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1803,7 +1767,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1973,7 +1936,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1997,7 +1959,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2021,7 +1982,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2045,7 +2005,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2073,7 +2032,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2104,7 +2062,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2140,7 +2097,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -2168,7 +2124,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2192,7 +2147,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2217,7 +2171,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2419,7 +2372,6 @@
         ],
         "isolate_name": "angle_perftests",
         "name": "angle_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2443,7 +2395,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2467,7 +2418,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2491,7 +2441,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2515,7 +2464,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2543,7 +2491,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2574,7 +2521,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2610,7 +2556,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -2638,7 +2583,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2662,7 +2606,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2687,7 +2630,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2854,7 +2796,6 @@
         ],
         "isolate_name": "angle_perftests",
         "name": "angle_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2878,7 +2819,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2902,7 +2842,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2926,7 +2865,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2950,7 +2888,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2978,7 +2915,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3009,7 +2945,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3045,7 +2980,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -3073,7 +3007,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3097,7 +3030,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3122,7 +3054,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3399,7 +3330,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3422,7 +3352,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3445,7 +3374,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3468,7 +3396,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3495,7 +3422,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3525,7 +3451,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3560,7 +3485,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -3587,7 +3511,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3610,7 +3533,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3634,7 +3556,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "viz_screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3657,7 +3578,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_gl_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3681,7 +3601,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3821,7 +3740,6 @@
         ],
         "isolate_name": "angle_perftests",
         "name": "angle_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3996,7 +3914,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4020,7 +3937,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4044,7 +3960,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4068,7 +3983,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4096,7 +4010,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4127,7 +4040,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4163,7 +4075,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -4191,7 +4102,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4215,7 +4125,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4240,7 +4149,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "viz_screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4266,7 +4174,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4291,7 +4198,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_gl_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4316,7 +4222,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4482,7 +4387,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4505,7 +4409,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4528,7 +4431,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4551,7 +4453,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4578,7 +4479,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4608,7 +4508,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4643,7 +4542,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -4670,7 +4568,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4693,7 +4590,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4717,7 +4613,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "viz_screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4742,7 +4637,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4766,7 +4660,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_gl_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4790,7 +4683,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4951,7 +4843,6 @@
         ],
         "isolate_name": "angle_perftests",
         "name": "angle_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4974,7 +4865,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4997,7 +4887,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5020,7 +4909,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5043,7 +4931,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5070,7 +4957,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5100,7 +4986,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5135,7 +5020,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -5162,7 +5046,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5185,7 +5068,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5209,7 +5091,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "viz_screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5234,7 +5115,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_gl_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5260,7 +5140,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5284,7 +5163,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_gl_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5308,7 +5186,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5559,7 +5436,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5581,7 +5457,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5603,7 +5478,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5625,7 +5499,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5651,7 +5524,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5680,7 +5552,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5714,7 +5585,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -5740,7 +5610,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5762,7 +5631,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5784,7 +5652,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5946,7 +5813,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5969,7 +5835,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -5992,7 +5857,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6015,7 +5879,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6042,7 +5905,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6072,7 +5934,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6107,7 +5968,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -6134,7 +5994,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6157,7 +6016,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6182,7 +6040,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6206,7 +6063,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6377,7 +6233,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6401,7 +6256,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6425,7 +6279,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6449,7 +6302,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6477,7 +6329,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6508,7 +6359,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6544,7 +6394,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -6572,7 +6421,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6596,7 +6444,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6622,7 +6469,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6647,7 +6493,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6827,7 +6672,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6852,7 +6696,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6877,7 +6720,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6902,7 +6744,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6931,7 +6772,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6963,7 +6803,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7000,7 +6839,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -7029,7 +6867,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7054,7 +6891,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7081,7 +6917,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7107,7 +6942,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7331,7 +7165,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7359,7 +7192,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7387,7 +7219,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7415,7 +7246,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7450,7 +7280,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7490,7 +7319,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -7522,7 +7350,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7550,7 +7377,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7581,7 +7407,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7611,7 +7436,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7783,7 +7607,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7805,7 +7628,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7827,7 +7649,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7849,7 +7670,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7875,7 +7695,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7904,7 +7723,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7938,7 +7756,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -7964,7 +7781,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -7986,7 +7802,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8010,7 +7825,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8033,7 +7847,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8196,7 +8009,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8220,7 +8032,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8244,7 +8055,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8268,7 +8078,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8296,7 +8105,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8327,7 +8135,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8363,7 +8170,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -8391,7 +8197,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8415,7 +8220,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8439,7 +8243,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8604,7 +8407,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8628,7 +8430,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8652,7 +8453,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8676,7 +8476,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8704,7 +8503,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8735,7 +8533,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8771,7 +8568,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -8799,7 +8595,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8823,7 +8618,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8847,7 +8641,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9033,7 +8826,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9057,7 +8849,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9081,7 +8872,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9105,7 +8895,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9133,7 +8922,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9164,7 +8952,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9200,7 +8987,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -9228,7 +9014,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9252,7 +9037,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9278,7 +9062,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9303,7 +9086,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9489,7 +9271,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9513,7 +9294,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9537,7 +9317,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9561,7 +9340,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9589,7 +9367,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9620,7 +9397,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9656,7 +9432,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -9684,7 +9459,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9708,7 +9482,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9734,7 +9507,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -9759,7 +9531,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10035,7 +9806,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10059,7 +9829,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10083,7 +9852,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10107,7 +9875,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10135,7 +9902,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10166,7 +9932,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10202,7 +9967,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -10230,7 +9994,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10254,7 +10017,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10280,7 +10042,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10305,7 +10066,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10403,7 +10163,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10428,7 +10187,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10452,7 +10210,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_gl_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10540,7 +10297,6 @@
         ],
         "isolate_name": "angle_perftests",
         "name": "angle_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10567,7 +10323,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10592,7 +10347,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10616,7 +10370,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_gl_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10721,7 +10474,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10745,7 +10497,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10859,7 +10610,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -10885,7 +10635,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11001,7 +10750,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11222,7 +10970,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11247,7 +10994,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11271,7 +11017,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d11_validating_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11295,7 +11040,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11319,7 +11063,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11343,7 +11086,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_gl_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11683,7 +11425,6 @@
         ],
         "isolate_name": "angle_perftests",
         "name": "angle_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11719,7 +11460,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11748,7 +11488,6 @@
         ],
         "isolate_name": "command_buffer_perftests",
         "name": "passthrough_command_buffer_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11777,7 +11516,6 @@
         ],
         "isolate_name": "command_buffer_perftests",
         "name": "validating_command_buffer_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11811,7 +11549,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11844,7 +11581,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d11_validating_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11877,7 +11613,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11910,7 +11645,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -11943,7 +11677,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_gl_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12257,7 +11990,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12280,7 +12012,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12303,7 +12034,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12326,7 +12056,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12353,7 +12082,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12383,7 +12111,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12418,7 +12145,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -12445,7 +12171,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12468,7 +12193,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12492,7 +12216,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "viz_screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12515,7 +12238,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d11_validating_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12539,7 +12261,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12563,7 +12284,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12587,7 +12307,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_gl_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12611,7 +12330,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12895,7 +12613,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12918,7 +12635,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12941,7 +12657,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12964,7 +12679,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -12991,7 +12705,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13021,7 +12734,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13056,7 +12768,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -13083,7 +12794,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13106,7 +12816,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13130,7 +12839,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "viz_screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13155,7 +12863,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13179,7 +12886,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d11_validating_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13203,7 +12909,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_gl_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13227,7 +12932,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13255,7 +12959,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "noop_sleep_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13560,7 +13263,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13583,7 +13285,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13606,7 +13307,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13629,7 +13329,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13656,7 +13355,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13686,7 +13384,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13721,7 +13418,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -13748,7 +13444,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13771,7 +13466,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13795,7 +13489,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "viz_screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13820,7 +13513,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13844,7 +13536,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d11_validating_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13868,7 +13559,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13892,7 +13582,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13916,7 +13605,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_gl_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -13940,7 +13628,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14414,7 +14101,6 @@
         ],
         "isolate_name": "angle_perftests",
         "name": "angle_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14446,7 +14132,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14478,7 +14163,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14510,7 +14194,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14542,7 +14225,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14578,7 +14260,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14617,7 +14298,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14646,7 +14326,6 @@
         ],
         "isolate_name": "command_buffer_perftests",
         "name": "passthrough_command_buffer_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14690,7 +14369,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -14726,7 +14404,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14758,7 +14435,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14787,7 +14463,6 @@
         ],
         "isolate_name": "command_buffer_perftests",
         "name": "validating_command_buffer_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14820,7 +14495,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "viz_screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14854,7 +14528,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_d3d11_validating_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14889,7 +14562,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_gl_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14924,7 +14596,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14957,7 +14628,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d11_validating_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -14990,7 +14660,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15023,7 +14692,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15056,7 +14724,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_gl_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15089,7 +14756,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15340,7 +15006,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d11_validating_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15364,7 +15029,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15647,7 +15311,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15670,7 +15333,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15693,7 +15355,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15716,7 +15377,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15743,7 +15403,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15773,7 +15432,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15808,7 +15466,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -15835,7 +15492,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15858,7 +15514,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15882,7 +15537,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "viz_screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15905,7 +15559,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d11_validating_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15929,7 +15582,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15953,7 +15605,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -15977,7 +15628,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -16280,7 +15930,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -16303,7 +15952,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -16326,7 +15974,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -16349,7 +15996,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -16376,7 +16022,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -16406,7 +16051,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -16441,7 +16085,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -16468,7 +16111,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -16491,7 +16133,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -16515,7 +16156,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "viz_screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -16540,7 +16180,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -16564,7 +16203,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d11_validating_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -16588,7 +16226,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -16612,7 +16249,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -16636,7 +16272,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17083,7 +16718,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17115,7 +16749,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17147,7 +16780,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17179,7 +16811,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17215,7 +16846,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17254,7 +16884,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17298,7 +16927,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -17334,7 +16962,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17366,7 +16993,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17399,7 +17025,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "viz_screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17433,7 +17058,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17466,7 +17090,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d11_validating_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17499,7 +17122,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17532,7 +17154,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17565,7 +17186,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_gl_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17598,7 +17218,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17952,7 +17571,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17975,7 +17593,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -17998,7 +17615,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18021,7 +17637,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18048,7 +17663,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18078,7 +17692,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18113,7 +17726,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -18140,7 +17752,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18163,7 +17774,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18187,7 +17797,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "viz_screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18212,7 +17821,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18236,7 +17844,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d11_validating_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18260,7 +17867,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18284,7 +17890,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_d3d9_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18308,7 +17913,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_gl_passthrough_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -18332,7 +17936,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.gpu.json b/testing/buildbot/chromium.gpu.json
index c7fbadcd..7e441b26 100644
--- a/testing/buildbot/chromium.gpu.json
+++ b/testing/buildbot/chromium.gpu.json
@@ -14,7 +14,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -37,7 +36,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -60,7 +58,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -83,7 +80,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -110,7 +106,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -140,7 +135,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -175,7 +169,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -202,7 +195,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -225,7 +217,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -249,7 +240,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -337,7 +327,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -360,7 +349,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -383,7 +371,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -406,7 +393,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -433,7 +419,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -463,7 +448,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -498,7 +482,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -525,7 +508,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -548,7 +530,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -572,7 +553,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "viz_screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -595,7 +575,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -698,7 +677,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -721,7 +699,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -744,7 +721,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -767,7 +743,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -794,7 +769,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -824,7 +798,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -859,7 +832,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -886,7 +858,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -909,7 +880,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -933,7 +903,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "viz_screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -956,7 +925,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1033,7 +1001,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1055,7 +1022,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1077,7 +1043,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1099,7 +1064,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1125,7 +1089,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1154,7 +1117,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1188,7 +1150,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -1214,7 +1175,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1236,7 +1196,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1258,7 +1217,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1353,7 +1311,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1375,7 +1332,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1397,7 +1353,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1419,7 +1374,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1445,7 +1399,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1474,7 +1427,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1508,7 +1460,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -1534,7 +1485,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1556,7 +1506,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1578,7 +1527,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1660,7 +1608,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1684,7 +1631,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1708,7 +1654,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1732,7 +1677,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1760,7 +1704,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1791,7 +1734,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1827,7 +1769,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -1855,7 +1796,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1879,7 +1819,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1903,7 +1842,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2008,7 +1946,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2032,7 +1969,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2056,7 +1992,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2080,7 +2015,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2108,7 +2042,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2139,7 +2072,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2175,7 +2107,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -2203,7 +2134,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2227,7 +2157,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2251,7 +2180,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2391,7 +2319,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2414,7 +2341,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2437,7 +2363,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2460,7 +2385,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2487,7 +2411,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2517,7 +2440,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2552,7 +2474,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -2579,7 +2500,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2602,7 +2522,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2626,7 +2545,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "viz_screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2649,7 +2567,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2871,7 +2788,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2903,7 +2819,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2935,7 +2850,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2967,7 +2881,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3003,7 +2916,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "info_collection_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3042,7 +2954,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3086,7 +2997,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -3122,7 +3032,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3154,7 +3063,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3187,7 +3095,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "viz_screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3219,7 +3126,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.json b/testing/buildbot/chromium.json
index 3763f70..fcdd1ed 100644
--- a/testing/buildbot/chromium.json
+++ b/testing/buildbot/chromium.json
@@ -50,5 +50,60 @@
         "script": "checkbins.py"
       }
     ]
+  },
+  "android-rel": {
+    "additional_compile_targets": [
+      "all"
+    ]
+  },
+  "linux-rel": {
+    "additional_compile_targets": [
+      "all"
+    ],
+    "scripts": [
+      {
+        "args": [
+          "linux-release-64/sizes"
+        ],
+        "name": "sizes",
+        "script": "sizes.py"
+      }
+    ]
+  },
+  "mac-rel": {
+    "additional_compile_targets": [
+      "all"
+    ],
+    "scripts": [
+      {
+        "args": [
+          "mac-release/sizes"
+        ],
+        "name": "sizes",
+        "script": "sizes.py"
+      }
+    ]
+  },
+  "win-rel": {
+    "additional_compile_targets": [
+      "all"
+    ],
+    "scripts": [
+      {
+        "name": "checkbins",
+        "script": "checkbins.py"
+      }
+    ]
+  },
+  "win32-rel": {
+    "additional_compile_targets": [
+      "all"
+    ],
+    "scripts": [
+      {
+        "name": "checkbins",
+        "script": "checkbins.py"
+      }
+    ]
   }
 }
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 67ade18..4f55a25 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -792,7 +792,6 @@
           "script": "//tools/perf/process_perf_results.py"
         },
         "name": "memory.leak_detection",
-        "only_retry_failed_tests": true,
         "override_compile_targets": [
           "performance_test_suite"
         ],
@@ -1047,8 +1046,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
@@ -1528,7 +1526,6 @@
         ],
         "isolate_name": "chromedriver_py_tests",
         "name": "chromedriver_py_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1536,7 +1533,6 @@
       {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1544,7 +1540,6 @@
       {
         "isolate_name": "devtools_closure_compile",
         "name": "devtools_closure_compile",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1552,7 +1547,6 @@
       {
         "isolate_name": "devtools_eslint",
         "name": "devtools_eslint",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1560,7 +1554,6 @@
       {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1582,7 +1575,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "site_per_process_webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -1597,7 +1589,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1609,7 +1600,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "hard_timeout": 960,
@@ -1622,7 +1612,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -1631,7 +1620,6 @@
       {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1645,7 +1633,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -1660,7 +1647,6 @@
       {
         "isolate_name": "webkit_python_tests",
         "name": "webkit_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1900,8 +1886,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
@@ -2379,7 +2364,6 @@
       {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2387,7 +2371,6 @@
       {
         "isolate_name": "devtools_closure_compile",
         "name": "devtools_closure_compile",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2395,7 +2378,6 @@
       {
         "isolate_name": "devtools_eslint",
         "name": "devtools_eslint",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2403,7 +2385,6 @@
       {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2411,7 +2392,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2423,7 +2403,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "hard_timeout": 960,
@@ -2436,7 +2415,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -2445,7 +2423,6 @@
       {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2462,7 +2439,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -2477,7 +2453,6 @@
       {
         "isolate_name": "webkit_python_tests",
         "name": "webkit_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3074,7 +3049,6 @@
       {
         "isolate_name": "devtools_closure_compile",
         "name": "devtools_closure_compile",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3082,7 +3056,6 @@
       {
         "isolate_name": "devtools_eslint",
         "name": "devtools_eslint",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3090,7 +3063,6 @@
       {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3098,7 +3070,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3109,7 +3080,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -3118,7 +3088,6 @@
       {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3126,7 +3095,6 @@
       {
         "isolate_name": "webkit_python_tests",
         "name": "webkit_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3533,8 +3501,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
@@ -4369,7 +4336,6 @@
         ],
         "isolate_name": "chromedriver_py_tests",
         "name": "chromedriver_py_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4382,7 +4348,6 @@
       {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4395,7 +4360,6 @@
       {
         "isolate_name": "devtools_closure_compile",
         "name": "devtools_closure_compile",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4408,7 +4372,6 @@
       {
         "isolate_name": "devtools_eslint",
         "name": "devtools_eslint",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4421,7 +4384,6 @@
       {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4448,7 +4410,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "site_per_process_webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -4463,7 +4424,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4480,7 +4440,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4498,7 +4457,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4512,7 +4470,6 @@
       {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4531,7 +4488,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -4546,7 +4502,6 @@
       {
         "isolate_name": "webkit_python_tests",
         "name": "webkit_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index bbfeeee..61414b2 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -495,7 +495,6 @@
         ],
         "isolate_name": "chromedriver_py_tests",
         "name": "chromedriver_py_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -503,7 +502,6 @@
       {
         "isolate_name": "components_perftests",
         "name": "components_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -511,7 +509,6 @@
       {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -519,7 +516,6 @@
       {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -527,7 +523,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -538,7 +533,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "hard_timeout": 960,
@@ -551,7 +545,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -560,7 +553,6 @@
       {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -574,7 +566,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -590,7 +581,6 @@
       {
         "isolate_name": "webkit_python_tests",
         "name": "webkit_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1103,7 +1093,6 @@
         ],
         "isolate_name": "chromedriver_py_tests",
         "name": "chromedriver_py_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1111,7 +1100,6 @@
       {
         "isolate_name": "components_perftests",
         "name": "components_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1119,7 +1107,6 @@
       {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1127,7 +1114,6 @@
       {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1135,7 +1121,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1146,7 +1131,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "hard_timeout": 960,
@@ -1159,7 +1143,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -1168,7 +1151,6 @@
       {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1182,7 +1164,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -1198,7 +1179,6 @@
       {
         "isolate_name": "webkit_python_tests",
         "name": "webkit_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2180,7 +2160,6 @@
         ],
         "isolate_name": "chromedriver_py_tests",
         "name": "chromedriver_py_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2194,7 +2173,6 @@
       {
         "isolate_name": "components_perftests",
         "name": "components_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2208,7 +2186,6 @@
       {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2222,7 +2199,6 @@
       {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2236,7 +2212,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2253,7 +2228,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2272,7 +2246,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2287,7 +2260,6 @@
       {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2307,7 +2279,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -2324,7 +2295,6 @@
       {
         "isolate_name": "webkit_python_tests",
         "name": "webkit_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2844,7 +2814,6 @@
         ],
         "isolate_name": "chromedriver_py_tests",
         "name": "chromedriver_py_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2852,7 +2821,6 @@
       {
         "isolate_name": "components_perftests",
         "name": "components_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2860,7 +2828,6 @@
       {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2868,7 +2835,6 @@
       {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2876,7 +2842,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2887,7 +2852,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -2896,7 +2860,6 @@
       {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2911,7 +2874,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -2928,7 +2890,6 @@
       {
         "isolate_name": "webkit_python_tests",
         "name": "webkit_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3444,7 +3405,6 @@
       {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3452,7 +3412,6 @@
       {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3471,7 +3430,6 @@
           "script": "//tools/perf/process_perf_results.py"
         },
         "name": "performance_test_suite",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "hard_timeout": 960,
@@ -3481,7 +3439,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3492,7 +3449,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -3501,7 +3457,6 @@
       {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3518,7 +3473,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -3528,7 +3482,6 @@
       {
         "isolate_name": "webkit_python_tests",
         "name": "webkit_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 268426e2..f8b0cd8 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -3680,8 +3680,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
@@ -4305,7 +4304,7 @@
         "name": "viz_browser_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
-          "shards": 20
+          "shards": 30
         },
         "test": "browser_tests"
       },
@@ -5628,8 +5627,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
diff --git a/testing/buildbot/chromium.swarm.json b/testing/buildbot/chromium.swarm.json
index 59a04d37..b2e0d7a 100644
--- a/testing/buildbot/chromium.swarm.json
+++ b/testing/buildbot/chromium.swarm.json
@@ -696,7 +696,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -717,7 +716,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.webkit.json b/testing/buildbot/chromium.webkit.json
index b2a5531..bb5c3c4 100644
--- a/testing/buildbot/chromium.webkit.json
+++ b/testing/buildbot/chromium.webkit.json
@@ -19,7 +19,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -51,7 +50,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -83,7 +81,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -111,7 +108,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -139,7 +135,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 8a689e9..c70b406 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -651,7 +651,6 @@
         ],
         "isolate_name": "chromedriver_py_tests",
         "name": "chromedriver_py_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -659,7 +658,6 @@
       {
         "isolate_name": "components_perftests",
         "name": "components_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -667,7 +665,6 @@
       {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -675,7 +672,6 @@
       {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -683,7 +679,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -691,7 +686,6 @@
       {
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "hard_timeout": 960,
@@ -704,7 +698,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -713,7 +706,6 @@
       {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -721,7 +713,6 @@
       {
         "isolate_name": "webkit_python_tests",
         "name": "webkit_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -1394,7 +1385,6 @@
       {
         "isolate_name": "mini_installer_tests",
         "name": "mini_installer_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2016,7 +2006,6 @@
         "experiment_percentage": 100,
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2024,7 +2013,6 @@
       {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2044,7 +2032,6 @@
           "script": "//tools/perf/process_perf_results.py"
         },
         "name": "performance_test_suite",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "hard_timeout": 960,
@@ -2054,7 +2041,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2065,7 +2051,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -2074,7 +2059,6 @@
       {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2082,7 +2066,6 @@
       {
         "isolate_name": "webkit_python_tests",
         "name": "webkit_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2736,7 +2719,6 @@
         ],
         "isolate_name": "chromedriver_py_tests",
         "name": "chromedriver_py_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2744,7 +2726,6 @@
       {
         "isolate_name": "components_perftests",
         "name": "components_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2752,7 +2733,6 @@
       {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2760,7 +2740,6 @@
       {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2768,7 +2747,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2776,7 +2754,6 @@
       {
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "hard_timeout": 960,
@@ -2789,7 +2766,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -2798,7 +2774,6 @@
       {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -2812,7 +2787,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -2822,7 +2796,6 @@
       {
         "isolate_name": "webkit_python_tests",
         "name": "webkit_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3501,7 +3474,6 @@
       {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3509,7 +3481,6 @@
       {
         "isolate_name": "metrics_python_tests",
         "name": "metrics_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3528,7 +3499,6 @@
           "script": "//tools/perf/process_perf_results.py"
         },
         "name": "performance_test_suite",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "hard_timeout": 960,
@@ -3538,7 +3508,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3550,7 +3519,6 @@
         "experiment_percentage": 100,
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "hard_timeout": 960,
@@ -3563,7 +3531,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -3572,7 +3539,6 @@
       {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -3592,7 +3558,6 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_tests",
-        "only_retry_failed_tests": true,
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -3607,7 +3572,6 @@
       {
         "isolate_name": "webkit_python_tests",
         "name": "webkit_python_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
diff --git a/testing/buildbot/client.v8.chromium.json b/testing/buildbot/client.v8.chromium.json
index dce3ac84..78e1271 100644
--- a/testing/buildbot/client.v8.chromium.json
+++ b/testing/buildbot/client.v8.chromium.json
@@ -65,8 +65,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
@@ -225,7 +224,6 @@
       {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -233,7 +231,6 @@
       {
         "isolate_name": "devtools_closure_compile",
         "name": "devtools_closure_compile",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -241,7 +238,6 @@
       {
         "isolate_name": "devtools_eslint",
         "name": "devtools_eslint",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -249,7 +245,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -260,7 +255,6 @@
         ],
         "isolate_name": "telemetry_perf_unittests",
         "name": "telemetry_perf_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "hard_timeout": 960,
@@ -273,7 +267,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
@@ -345,8 +338,7 @@
       },
       {
         "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
+          "--site-per-process"
         ],
         "name": "site_per_process_content_browsertests",
         "swarming": {
@@ -506,7 +498,6 @@
       {
         "isolate_name": "content_shell_crash_test",
         "name": "content_shell_crash_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -514,7 +505,6 @@
       {
         "isolate_name": "devtools_closure_compile",
         "name": "devtools_closure_compile",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -522,7 +512,6 @@
       {
         "isolate_name": "devtools_eslint",
         "name": "devtools_eslint",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -530,7 +519,6 @@
       {
         "isolate_name": "telemetry_gpu_unittests",
         "name": "telemetry_gpu_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -541,7 +529,6 @@
         ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 4
diff --git a/testing/buildbot/client.v8.fyi.json b/testing/buildbot/client.v8.fyi.json
index 184a79e..4789212 100644
--- a/testing/buildbot/client.v8.fyi.json
+++ b/testing/buildbot/client.v8.fyi.json
@@ -14,7 +14,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -37,7 +36,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -60,7 +58,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -83,7 +80,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -113,7 +109,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -148,7 +143,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -175,7 +169,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -198,7 +191,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -222,7 +214,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -250,7 +241,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -273,7 +263,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -296,7 +285,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -319,7 +307,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -349,7 +336,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -384,7 +370,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -411,7 +396,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -434,7 +418,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -459,7 +442,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -483,7 +465,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -511,7 +492,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -534,7 +514,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -557,7 +536,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -580,7 +558,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -610,7 +587,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -645,7 +621,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -672,7 +647,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -695,7 +669,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -720,7 +693,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -744,7 +716,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -772,7 +743,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -794,7 +764,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -816,7 +785,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -838,7 +806,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -867,7 +834,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -901,7 +867,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -927,7 +892,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -949,7 +913,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -973,7 +936,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -996,7 +958,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1078,7 +1039,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "context_lost_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1101,7 +1061,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "depth_capture_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1124,7 +1083,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "gpu_process_launch_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1147,7 +1105,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "hardware_accelerated_feature_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1177,7 +1134,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "maps_pixel_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1212,7 +1168,6 @@
         "non_precommit_args": [
           "--upload-refimg-to-cloud-storage"
         ],
-        "only_retry_failed_tests": true,
         "precommit_args": [
           "--download-refimg-from-cloud-storage"
         ],
@@ -1239,7 +1194,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "screenshot_sync_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1262,7 +1216,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "trace_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1287,7 +1240,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl2_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1311,7 +1263,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "webgl_conformance_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index 21fc4793..d21a5271 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -39,7 +39,6 @@
   data = [
     "//testing/buildbot/filters/cast-linux.content_browsertests.filter",
     "//testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter",
-    "//testing/buildbot/filters/site-per-process.content_browsertests.filter",
   ]
 }
 
diff --git a/testing/buildbot/filters/README.md b/testing/buildbot/filters/README.md
index fb79b59e..f8a82b4 100644
--- a/testing/buildbot/filters/README.md
+++ b/testing/buildbot/filters/README.md
@@ -3,9 +3,9 @@
 ## Summary
 
 This directory contains files that list tests that are not yet ready to run in a
-particular mode. For example - the `site-per-process.content_browsertests.filter` file
-lists tests that should be excluded when running `content_browsertests` in
-`--site-per-process` mode.
+particular mode. For example - the `cast-linux.content_browsertests.filter` file
+lists tests that should be excluded when running `content_browsertests` on the
+Cast device or bot (e.g. on 'Cast Linux).
 
 ## File syntax
 
@@ -49,8 +49,7 @@
 
 ```bash
 $ out/dbg/content_browsertests \
-    --site-per-process \
-    --test-launcher-filter-file=testing/buildbot/filters/site-per-process.content_browsertests.filter
+    --test-launcher-filter-file=testing/buildbot/filters/foo.content_browsertests.filter
 ```
 
 When running tests on Android, the test filter file can also be specified using
@@ -58,8 +57,7 @@
 
 ```bash
 $ out/android/bin/run_content_browsertests \
-    --site-per-process \
-    --test-launcher-filter-file=testing/buildbot/filters/site-per-process.content_browsertests.filter
+    --test-launcher-filter-file=testing/buildbot/filters/foo.content_browsertests.filter
 ```
 
 ## Applicability
diff --git a/testing/buildbot/filters/site-per-process.content_browsertests.filter b/testing/buildbot/filters/site-per-process.content_browsertests.filter
deleted file mode 100644
index 4719bc6..0000000
--- a/testing/buildbot/filters/site-per-process.content_browsertests.filter
+++ /dev/null
@@ -1,6 +0,0 @@
-# crbug.com/417518: Get tests working with --site-per-process
--NavigationControllerBrowserTest.ReloadOriginalRequest
-
-# Untriaged.
--LoaderBrowserTest.CookieSameSiteStrictOpenNewNamedWindowTwice
-
diff --git a/testing/buildbot/generate_buildbot_json.py b/testing/buildbot/generate_buildbot_json.py
index 29e698f..29bde5e 100755
--- a/testing/buildbot/generate_buildbot_json.py
+++ b/testing/buildbot/generate_buildbot_json.py
@@ -500,9 +500,6 @@
     self.initialize_args_for_test(result, tester_config)
     result = self.update_and_cleanup_test(result, test_name, tester_name)
     self.add_common_test_properties(result, tester_config)
-
-    # TODO(martiniss): Remove this. https://crbug.com/533481
-    result['only_retry_failed_tests'] = True
     return result
 
   def generate_script_test(self, waterfall, tester_name, tester_config,
@@ -751,6 +748,12 @@
       'WebKit Linux layout_ng Dummy Builder',
       'WebKit Linux root_layer_scrolls Dummy Builder',
       'WebKit Linux slimming_paint_v2 Dummy Builder',
+      #chromium
+      'android-rel',
+      'linux-rel',
+      'mac-rel',
+      'win32-rel',
+      'win-rel',
     ]
 
   def check_input_file_consistency(self):
diff --git a/testing/buildbot/generate_buildbot_json_unittest.py b/testing/buildbot/generate_buildbot_json_unittest.py
index 0e5fc430..8ffc29a3 100755
--- a/testing/buildbot/generate_buildbot_json_unittest.py
+++ b/testing/buildbot/generate_buildbot_json_unittest.py
@@ -804,7 +804,6 @@
       {
         "isolate_name": "foo_test",
         "name": "foo_test",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true
         }
@@ -926,7 +925,6 @@
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "name": "foo_tests",
-        "only_retry_failed_tests": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index a4d57c4..04f381d 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -257,6 +257,8 @@
     'remove_from': [
       'Linux x64',
       'Mac',
+      'linux-rel',
+      'mac-rel',
     ],
   },
   'chrome_public_test_apk': {
@@ -1079,9 +1081,21 @@
     'remove_from': [
       'Win',
       'Win x64',
+      'win32-rel',
+      'win-rel',
     ],
     'modifications': {
       # chromium
+      'mac-rel': {
+        'args': [
+          'mac-release/sizes',
+        ],
+      },
+      'linux-rel': {
+        'args': [
+          'linux-release-64/sizes',
+        ],
+      },
       'Mac': {
         'args': [
           'mac-release/sizes',
@@ -1428,7 +1442,7 @@
         # These are very slow on the ASAN trybot for some reason.
         # crbug.com/794372
         'swarming': {
-          'shards': 20,
+          'shards': 30,
         },
       },
     },
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 554c28d..94e6ec2 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -811,8 +811,7 @@
     },
     'site_per_process_content_browsertests': {
       'args': [
-        '--site-per-process',
-        '--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter'
+        '--site-per-process'
       ],
       'test': 'content_browsertests',
     },
@@ -1938,8 +1937,7 @@
     },
     'site_per_process_content_browsertests': {
       'args': [
-        '--site-per-process',
-        '--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter'
+        '--site-per-process'
       ],
       'test': 'content_browsertests',
     },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index d524263..a82ac762 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -12,6 +12,43 @@
   {
     'name': 'chromium',
     'machines': {
+      'linux-rel': {
+        'additional_compile_targets': [
+          'all',
+        ],
+        'test_suites': {
+          'scripts': 'public_build_scripts',
+        },
+      },
+      'mac-rel': {
+        'additional_compile_targets': [
+          'all',
+        ],
+        'test_suites': {
+          'scripts': 'public_build_scripts',
+        },
+      },
+      'win32-rel': {
+        'additional_compile_targets': [
+          'all',
+        ],
+        'test_suites': {
+          'scripts': 'public_build_scripts',
+        },
+      },
+      'win-rel': {
+        'additional_compile_targets': [
+          'all',
+        ],
+        'test_suites': {
+          'scripts': 'public_build_scripts',
+        },
+      },
+      'android-rel': {
+        'additional_compile_targets': [
+          'all',
+        ],
+      },
       'Linux x64': {
         'additional_compile_targets': [
           'all',
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index a346fb4..21341b4d 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1719,6 +1719,10 @@
 
 # ====== Out of Blink CORS related tests END ======
 
+crbug.com/771118 virtual/service-worker-servicification/external/wpt/service-workers/service-worker/mime-sniffing.https.html [ Failure ]
+crbug.com/771118 virtual/outofblink-cors/external/wpt/service-workers/service-worker/mime-sniffing.https.html [ Failure ]
+crbug.com/771118 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/mime-sniffing.https.html [ Failure ]
+
 crbug.com/492664 [ Linux ] external/wpt/css/css-writing-modes/box-offsets-rel-pos-vlr-005.xht [ Failure ]
 crbug.com/492664 [ Linux ] external/wpt/css/css-writing-modes/box-offsets-rel-pos-vrl-004.xht [ Failure ]
 crbug.com/492664 [ Mac ] external/wpt/css/css-writing-modes/bidi-embed-002.html [ Failure ]
@@ -4868,3 +4872,6 @@
 crbug.com/824539 [ Android ] tables/mozilla_expected_failures/bugs/bug2479-5.html [ Failure ]
 crbug.com/824539 [ Android ] transforms/transformed-caret.html [ Failure ]
 crbug.com/824539 [ Android ] virtual/layout_ng/fast/block/margin-collapse/019.html [ Failure ]
+
+# Sheriff 2018-07-30
+crbug.com/866166 virtual/gpu-rasterization/images/color-profile-image-filter-all.html [ Pass Timeout ]
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-control-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-control-expected.txt
index 47d8cccf..909f48ff 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-control-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-control-expected.txt
@@ -1,55 +1,53 @@
 Verifies viewport correctly shows and hides messages while logging and scrolling.
 
 Logging 100 messages
-activeCountAbove: 6, activeCountBelow: 8
-smallCount: 3, visibleCount: 11, maxActiveCount: 25, minActiveCount: 21
 
 Running: addSmallCount
-Logging 3 messages
+Logging smallCount messages
 Are there smallCount items in DOM? true
 Are there smallCount items visible? true
 
 Running: addMoreThanVisibleCount
-Logging 12 messages
+Logging visibleCount + 1 messages
 Are there visibleCount + 1 items in DOM? true
 Are there visibleCount items visible? true
 
 Running: addMaxActiveCount
-Logging 25 messages
+Logging maxActiveCount messages
 Are there maxActiveCount items in DOM? true
 Are there visibleCount items visible? true
 
 Running: addMoreThanMaxActiveCount
-Logging 28 messages
+Logging maxActiveCount + smallCount messages
 Are there maxActiveCount items in DOM? true
 Are there visibleCount items visible? true
 
 Running: scrollToBottomInPartialActiveWindow
-Logging 15 messages
+Logging visiblePlusHalfExtraRows messages
 Were no items added? true
 Were no items removed? true
 Are there visiblePlusHalfExtraRows items in DOM? true
 
 Running: scrollToBottomInMoreThanActiveWindow
-Logging 26 messages
+Logging maxActiveCount + 1 messages
 Were some items added? true
 Were some items removed? true
 
 Running: shouldNotReconnectExistingElementsToDOM
-Logging 3 messages
-Logging 3 messages
+Logging smallCount messages
+Logging smallCount messages
 Were smallCount * 2 items added? true
 Were 0 items removed? true
 
 Running: logRepeatingMessages
-Logging 11 messages
+Logging visibleCount messages
 Were 1 items added? true
 Were 0 items removed? true
 Are there 1 items in DOM? true
 Are there 1 items visible? true
 
 Running: reorderingMessages
-Logging 3 messages
+Logging smallCount messages
 Swapping messages 0 and 1
 Were no items added? true
 Were no items removed? true
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-control.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-control.js
index a268064..a438ba2d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-control.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-control.js
@@ -28,7 +28,7 @@
   const smallCount = 3;
 
   // Measure visible/active ranges.
-  await logMessages(100);
+  await logMessages(100, false, '100');
   viewport.forceScrollItemToBeFirst(50);
   var {first, last, count} = ConsoleTestRunner.visibleIndices();
   var visibleCount = count;
@@ -38,8 +38,6 @@
   var minActiveCount = 2 * (first - viewport._firstActiveIndex - 1) + visibleCount;
   var activeCountAbove = first - viewport._firstActiveIndex;
   var activeCountBelow = viewport._lastActiveIndex - last;
-  TestRunner.addResult(`activeCountAbove: ${activeCountAbove}, activeCountBelow: ${activeCountBelow}`);
-  TestRunner.addResult(`smallCount: ${smallCount}, visibleCount: ${visibleCount}, maxActiveCount: ${maxActiveCount}, minActiveCount: ${minActiveCount}`);
 
   var wasAddedToDOM = new Set();
   var wasRemovedFromDOM = new Set();
@@ -57,8 +55,8 @@
     wasRemovedFromDOM.clear();
   }
 
-  function logMessages(count, repeating) {
-    TestRunner.addResult('Logging ' + count + ' messages');
+  function logMessages(count, repeating, message) {
+    TestRunner.addResult('Logging ' + message + ' messages');
     return new Promise(resolve => {
       var awaitingMessagesCount = count;
       function messageAdded() {
@@ -125,7 +123,7 @@
   TestRunner.runTestSuite([
     async function addSmallCount(next) {
       reset();
-      await logMessages(smallCount, false);
+      await logMessages(smallCount, false, 'smallCount');
       viewport.forceScrollItemToBeFirst(0);
       assertDOMCount('smallCount', smallCount);
       assertVisibleCount('smallCount', smallCount);
@@ -134,7 +132,7 @@
 
     async function addMoreThanVisibleCount(next) {
       reset();
-      await logMessages(visibleCount + 1, false);
+      await logMessages(visibleCount + 1, false, 'visibleCount + 1');
       viewport.forceScrollItemToBeFirst(0);
       assertDOMCount('visibleCount + 1', visibleCount + 1);
       assertVisibleCount('visibleCount', visibleCount);
@@ -143,7 +141,7 @@
 
     async function addMaxActiveCount(next) {
       reset();
-      await logMessages(maxActiveCount, false);
+      await logMessages(maxActiveCount, false, 'maxActiveCount');
       viewport.forceScrollItemToBeFirst(0);
       assertDOMCount('maxActiveCount', maxActiveCount);
       assertVisibleCount('visibleCount', visibleCount);
@@ -152,7 +150,7 @@
 
     async function addMoreThanMaxActiveCount(next) {
       reset();
-      await logMessages(maxActiveCount + smallCount, false);
+      await logMessages(maxActiveCount + smallCount, false, 'maxActiveCount + smallCount');
       viewport.forceScrollItemToBeFirst(0);
       assertDOMCount('maxActiveCount', maxActiveCount);
       assertVisibleCount('visibleCount', visibleCount);
@@ -163,7 +161,7 @@
       reset();
       // Few enough messages so that they all fit in DOM.
       var visiblePlusHalfExtraRows = visibleCount + Math.floor((minActiveCount - visibleCount) / 2) - 1;
-      await logMessages(visiblePlusHalfExtraRows, false);
+      await logMessages(visiblePlusHalfExtraRows, false, 'visiblePlusHalfExtraRows');
       viewport.forceScrollItemToBeFirst(0);
       resetShowHideCounts();
       // Set scrollTop above the bottom.
@@ -177,7 +175,7 @@
 
     async function scrollToBottomInMoreThanActiveWindow(next) {
       reset();
-      await logMessages(maxActiveCount + 1, false);
+      await logMessages(maxActiveCount + 1, false, 'maxActiveCount + 1');
       viewport.forceScrollItemToBeFirst(0);
       resetShowHideCounts();
       // Set scrollTop above the bottom.
@@ -190,15 +188,15 @@
 
     async function shouldNotReconnectExistingElementsToDOM(next) {
       reset();
-      await logMessages(smallCount, false);
-      await logMessages(smallCount, false);
+      await logMessages(smallCount, false, 'smallCount');
+      await logMessages(smallCount, false, 'smallCount');
       assertCountAddedRemoved('smallCount * 2', smallCount * 2, '0', 0);
       next();
     },
 
     async function logRepeatingMessages(next) {
       reset();
-      await logMessages(visibleCount, true);
+      await logMessages(visibleCount, true, 'visibleCount');
       assertCountAddedRemoved('1', 1, '0', 0);
       assertDOMCount('1', 1);
       assertVisibleCount('1', 1);
@@ -207,7 +205,7 @@
 
     async function reorderingMessages(next) {
       reset();
-      await logMessages(smallCount, false);
+      await logMessages(smallCount, false, 'smallCount');
       resetShowHideCounts();
       TestRunner.addResult('Swapping messages 0 and 1');
       var temp = consoleView._visibleViewMessages[0];
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-indices-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-indices-expected.txt
index 13aa580..8386edae 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-indices-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-indices-expected.txt
@@ -2,36 +2,44 @@
 
 
 Running: testEmptyViewport
-Calculated visible range: -1 to -1, Total: 0
-Actual visible range: -1 to -1, Total: 0
-Active range: -1 to -1, Total: 0
-
+Expected and actual visible ranges match
 
 Running: testFirstLastVisibleIndices
-Logging 100 messages
+Logging 100 Normal messages
 Force item to be first: 0
-Calculated visible range: 0 to 10, Total: 11
-Actual visible range: 0 to 10, Total: 11
-Active range: 0 to 24, Total: 25
-
+Expected and actual visible ranges match
 Force item to be first: 1
-Calculated visible range: 1 to 11, Total: 11
-Actual visible range: 1 to 11, Total: 11
-Active range: 0 to 24, Total: 25
-
+Expected and actual visible ranges match
 Scroll a bit down: 15px
-Calculated visible range: 1 to 12, Total: 12
-Actual visible range: 1 to 12, Total: 12
-Active range: 0 to 24, Total: 25
-
+Expected and actual visible ranges match
 Force item to be last: 50
-Calculated visible range: 40 to 50, Total: 11
-Actual visible range: 40 to 50, Total: 11
-Active range: 35 to 59, Total: 25
-
+Expected and actual visible ranges match
 Force item to be last: 99
-Calculated visible range: 89 to 99, Total: 11
-Actual visible range: 89 to 99, Total: 11
-Active range: 84 to 99, Total: 16
+Expected and actual visible ranges match
 
+Running: testMultilineMessages
+Logging 100 Multiline messages
+Force item to be first: 0
+Expected and actual visible ranges match
+Force item to be first: 1
+Expected and actual visible ranges match
+Scroll a bit down: 15px
+Expected and actual visible ranges match
+Force item to be last: 50
+Expected and actual visible ranges match
+Force item to be last: 99
+Expected and actual visible ranges match
+
+Running: testSlightlyBiggerMessages
+Logging 100 SlightlyBigger messages
+Force item to be first: 0
+Expected and actual visible ranges match
+Force item to be first: 1
+Expected and actual visible ranges match
+Scroll a bit down: 15px
+Expected and actual visible ranges match
+Force item to be last: 50
+Expected and actual visible ranges match
+Force item to be last: 99
+Expected and actual visible ranges match
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-indices.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-indices.js
index 6fac148..2a4d8cc 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-indices.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-indices.js
@@ -7,12 +7,24 @@
     await TestRunner.loadModule('console_test_runner');
     await TestRunner.showPanel('console');
     await TestRunner.evaluateInPagePromise(`
-        function addMessages(count)
+        function addNormalMessages(count)
         {
             for (var i = 0; i < count; ++i)
                 console.log("Message #" + i);
         }
 
+        function addMultilineMessages(count)
+        {
+            for (var i = 0; i < count; ++i)
+                console.log("Message\\n#" + i);
+        }
+
+        function addSlightlyBiggerMessages(count)
+        {
+            for (var i = 0; i < count; ++i)
+              console.log('%cMessage #' + i, 'padding-bottom: 1px');
+        }
+
         //# sourceURL=console-viewport-indices.js
       `);
 
@@ -20,8 +32,8 @@
     var consoleView = Console.ConsoleView.instance();
     var viewport = consoleView._viewport;
 
-    function logMessages(count) {
-      TestRunner.addResult('Logging ' + count + ' messages');
+    function logMessages(count, type) {
+      TestRunner.addResult(`Logging ${count} ${type} messages`);
       return new Promise(resolve => {
         var awaitingMessagesCount = count;
         function messageAdded() {
@@ -33,7 +45,7 @@
           }
         }
         ConsoleTestRunner.addConsoleSniffer(messageAdded, false);
-        TestRunner.evaluateInPage(String.sprintf('addMessages(%d)', count));
+        TestRunner.evaluateInPage(String.sprintf(`add${type}Messages(%d)`, count));
       });
     }
 
@@ -43,15 +55,25 @@
       var calculatedFirst = viewport.firstVisibleIndex();
       var calculatedLast = viewport.lastVisibleIndex();
       var calculatedTotal = calculatedFirst === -1 ? 0 : (calculatedLast - calculatedFirst + 1);
-      TestRunner.addResult(`Calculated visible range: ${calculatedFirst} to ${calculatedLast}, Total: ${calculatedTotal}
-Actual visible range: ${first} to ${last}, Total: ${count}
-Active range: ${viewport._firstActiveIndex} to ${viewport._lastActiveIndex}, Total: ${activeTotal}\n`);
       if (calculatedFirst !== first || calculatedLast !== last) {
         TestRunner.addResult('TEST ENDED IN ERROR: viewport is calculated incorrect visible indices!');
+        TestRunner.addResult(`Calculated visible range: ${calculatedFirst} to ${calculatedLast}, Total: ${calculatedTotal}
+Actual visible range: ${first} to ${last}, Total: ${count}`);
         TestRunner.completeTest();
+      } else {
+        TestRunner.addResult(`Expected and actual visible ranges match`);
       }
     }
 
+    function forceItemAndDump(index, first) {
+      TestRunner.addResult(`Force item to be ${first ? 'first' : 'last'}: ${index}`);
+      if (first)
+        viewport.forceScrollItemToBeFirst(index);
+      else
+        viewport.forceScrollItemToBeLast(index);
+      dumpVisibleIndices();
+    }
+
     TestRunner.runTestSuite([
       async function testEmptyViewport(next) {
         Console.ConsoleView.clearConsole();
@@ -61,7 +83,7 @@
 
       async function testFirstLastVisibleIndices(next) {
         Console.ConsoleView.clearConsole();
-        await logMessages(100, false);
+        await logMessages(100, 'Normal');
 
         forceItemAndDump(0, true);
         forceItemAndDump(1, true);
@@ -75,15 +97,42 @@
         forceItemAndDump(50, false);
         forceItemAndDump(99, false);
         next();
+      },
 
-        function forceItemAndDump(index, first) {
-          TestRunner.addResult(`Force item to be ${first ? 'first' : 'last'}: ${index}`);
-          if (first)
-            viewport.forceScrollItemToBeFirst(index);
-          else
-            viewport.forceScrollItemToBeLast(index);
-          dumpVisibleIndices();
-        }
+      async function testMultilineMessages(next) {
+        Console.ConsoleView.clearConsole();
+        await logMessages(100, 'Multiline');
+
+        forceItemAndDump(0, true);
+        forceItemAndDump(1, true);
+
+        var lessThanOneRowHeight = consoleView.minimumRowHeight() - 1;
+        TestRunner.addResult(`Scroll a bit down: ${lessThanOneRowHeight}px`);
+        viewport.element.scrollTop += lessThanOneRowHeight;
+        viewport.refresh();
+        dumpVisibleIndices();
+
+        forceItemAndDump(50, false);
+        forceItemAndDump(99, false);
+        next();
+      },
+
+      async function testSlightlyBiggerMessages(next) {
+        Console.ConsoleView.clearConsole();
+        await logMessages(100, 'SlightlyBigger');
+
+        forceItemAndDump(0, true);
+        forceItemAndDump(1, true);
+
+        var lessThanOneRowHeight = consoleView.minimumRowHeight() - 1;
+        TestRunner.addResult(`Scroll a bit down: ${lessThanOneRowHeight}px`);
+        viewport.element.scrollTop += lessThanOneRowHeight;
+        viewport.refresh();
+        dumpVisibleIndices();
+
+        forceItemAndDump(50, false);
+        forceItemAndDump(99, false);
+        next();
       }
     ]);
   })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-selection-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-selection-expected.txt
index a7ad4e1..d4493c7 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-selection-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-selection-expected.txt
@@ -5,13 +5,11 @@
 Selected text:<<<EOL
 nsole
 EOL
-first visible message index: 75
 
 Running: testReversedSelectionSingleLineText
 Selected text:<<<EOL
 nsole
 EOL
-first visible message index: 75
 
 Running: testSelectionMultiLineText
 Selected text:<<<EOL
@@ -19,51 +17,39 @@
 console-viewport-selection.js:13 Message #75
 console
 EOL
-first visible message index: 74
 
 Running: testSimpleVisibleSelection
 anchor = {item: 72, offset: 6}, head = {item: 77, offset: 6}
-first visible message index: 72
 
 Running: testHalfScrollSelectionUp
 anchor = {item: 72, offset: 6}, head = {item: 77, offset: 6}
-first visible message index: 75
 
 Running: testHalfScrollSelectionDown
 anchor = {item: 72, offset: 6}, head = {item: 77, offset: 6}
-first visible message index: 65
 
 Running: testScrollSelectionAwayUp
 anchor = {item: 72, offset: 6}, head = {item: 77, offset: 6}
-first visible message index: 0
 
 Running: testScrollSelectionAwayDown
 anchor = {item: 72, offset: 6}, head = {item: 77, offset: 6}
-first visible message index: 140
 
 Running: testShiftClickSelectionOver
 anchor = {item: 72, offset: 6}, head = {item: 10, offset: 0}
-first visible message index: 5
 
 Running: testShiftClickSelectionBelow
 anchor = {item: 72, offset: 6}, head = {item: 140, offset: 0}
-first visible message index: 135
 
 Running: testRemoveSelection
 anchor = null, head = null
-first visible message index: 135
 
 Running: testReversedVisibleSelection
 anchor = {item: 76, offset: 6}, head = {item: 71, offset: 6}
-first visible message index: 71
 
 Running: testShiftClickReversedSelectionOver
 anchor = {item: 76, offset: 6}, head = {item: 10, offset: 0}
-first visible message index: 5
 
 Running: testShiftClickReversedSelectionBelow
 anchor = {item: 76, offset: 6}, head = {item: 140, offset: 0}
-first visible message index: 135
 
 Running: testZeroOffsetSelection
 Selected text: world
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-selection.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-selection.js
index 279eee3d..1d2a7be9 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-selection.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-viewport-selection.js
@@ -31,49 +31,42 @@
       viewportMessagesCount = viewport.lastVisibleIndex() - viewport.firstVisibleIndex() + 1;
       selectMessages(middleMessage, 2, middleMessage, 7);
       dumpSelectionText();
-      dumpViewportRenderedItems();
       next();
     },
 
     function testReversedSelectionSingleLineText(next) {
       selectMessages(middleMessage, 7, middleMessage, 2);
       dumpSelectionText();
-      dumpViewportRenderedItems();
       next();
     },
 
     function testSelectionMultiLineText(next) {
       selectMessages(middleMessage - 1, 4, middleMessage + 1, 7);
       dumpSelectionText();
-      dumpViewportRenderedItems();
       next();
     },
 
     function testSimpleVisibleSelection(next) {
       selectMessages(middleMessage - 3, 6, middleMessage + 2, 6);
       dumpSelectionModel();
-      dumpViewportRenderedItems();
       next();
     },
 
     function testHalfScrollSelectionUp(next) {
       viewport.forceScrollItemToBeFirst(middleMessage);
       dumpSelectionModel();
-      dumpViewportRenderedItems();
       next();
     },
 
     function testHalfScrollSelectionDown(next) {
       viewport.forceScrollItemToBeLast(middleMessage);
       dumpSelectionModel();
-      dumpViewportRenderedItems();
       next();
     },
 
     function testScrollSelectionAwayUp(next) {
       viewport.forceScrollItemToBeFirst(0);
       dumpSelectionModel();
-      dumpViewportRenderedItems();
       next();
     },
 
@@ -81,21 +74,18 @@
       consoleView._immediatelyScrollToBottom();
       viewport.refresh();
       dumpSelectionModel();
-      dumpViewportRenderedItems();
       next();
     },
 
     function testShiftClickSelectionOver(next) {
       emulateShiftClickOnMessage(minimumViewportMessagesCount);
       dumpSelectionModel();
-      dumpViewportRenderedItems();
       next();
     },
 
     function testShiftClickSelectionBelow(next) {
       emulateShiftClickOnMessage(messagesCount - minimumViewportMessagesCount);
       dumpSelectionModel();
-      dumpViewportRenderedItems();
       next();
     },
 
@@ -103,28 +93,24 @@
       var selection = window.getSelection();
       selection.removeAllRanges();
       dumpSelectionModel();
-      dumpViewportRenderedItems();
       next();
     },
 
     function testReversedVisibleSelection(next) {
       selectMessages(middleMessage + 1, 6, middleMessage - 4, 6);
       dumpSelectionModel();
-      dumpViewportRenderedItems();
       next();
     },
 
     function testShiftClickReversedSelectionOver(next) {
       emulateShiftClickOnMessage(minimumViewportMessagesCount);
       dumpSelectionModel();
-      dumpViewportRenderedItems();
       next();
     },
 
     function testShiftClickReversedSelectionBelow(next) {
       emulateShiftClickOnMessage(messagesCount - minimumViewportMessagesCount);
       dumpSelectionModel();
-      dumpViewportRenderedItems();
       next();
     },
 
@@ -210,13 +196,6 @@
     TestRunner.addResult('Selected text:<<<EOL\n' + text + '\nEOL');
   }
 
-  function dumpViewportRenderedItems() {
-    viewport.refresh();
-    var firstVisibleIndex = viewport.firstVisibleIndex();
-    var lastVisibleIndex = viewport.lastVisibleIndex();
-    TestRunner.addResult('first visible message index: ' + firstVisibleIndex);
-  }
-
   function emulateShiftClickOnMessage(messageIndex) {
     viewport.refresh();
     var selection = window.getSelection();
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/access-inspected-object-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/access-inspected-object-expected.txt
index cbaedeb..9207921 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/access-inspected-object-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/access-inspected-object-expected.txt
@@ -8,5 +8,6 @@
             value : null
         }
     }
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/emulation/emulation-oopifs-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/emulation/emulation-oopifs-expected.txt
index 56c8f05..e2cd4da 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/emulation/emulation-oopifs-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/emulation/emulation-oopifs-expected.txt
@@ -6,6 +6,7 @@
     id : <number>
     result : {
     }
+    sessionId : <string>
 }
 screen.width:
 1402
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/iframe-no-src-execution-contexts-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/iframe-no-src-execution-contexts-expected.txt
index 9fd70643..9efadbe 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/iframe-no-src-execution-contexts-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/iframe-no-src-execution-contexts-expected.txt
@@ -12,6 +12,7 @@
             origin : http://devtools.test:8000
         }
     }
+    sessionId : <string>
 }
 {
     method : Runtime.executionContextCreated
@@ -26,5 +27,6 @@
             origin : http://devtools.test:8000
         }
     }
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/mixed-content-execution-contexts-1-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/mixed-content-execution-contexts-1-expected.txt
index 0f8dadd..009a0e19 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/mixed-content-execution-contexts-1-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/mixed-content-execution-contexts-1-expected.txt
@@ -12,6 +12,7 @@
             origin : https://devtools.test:8443
         }
     }
+    sessionId : <string>
 }
 {
     method : Runtime.executionContextCreated
@@ -26,5 +27,6 @@
             origin : https://devtools.test:8443
         }
     }
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/mixed-content-execution-contexts-2-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/mixed-content-execution-contexts-2-expected.txt
index 0b7b72db..0cab96b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/mixed-content-execution-contexts-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/mixed-content-execution-contexts-2-expected.txt
@@ -12,6 +12,7 @@
             origin : https://devtools.test:8443
         }
     }
+    sessionId : <string>
 }
 {
     method : Runtime.executionContextCreated
@@ -26,5 +27,6 @@
             origin : https://devtools.test:8443
         }
     }
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/navigation-blocking-xorigin-iframe.js b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/navigation-blocking-xorigin-iframe.js
index 739ddd96..d1c264d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/navigation-blocking-xorigin-iframe.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/network/navigation-blocking-xorigin-iframe.js
@@ -4,7 +4,7 @@
 
   await session.protocol.Network.clearBrowserCache();
   await session.protocol.Network.setCacheDisabled({cacheDisabled: true});
-  await dp.Target.setAutoAttach({autoAttach: true, waitForDebuggerOnStart: true});
+  await dp.Target.setAutoAttach({autoAttach: true, waitForDebuggerOnStart: true, flatten: true});
 
   let interceptionLog = [];
   function onRequestIntercepted(dp, e) {
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/navigate-204-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/navigate-204-expected.txt
index 7529379..80c99ba 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/navigate-204-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/navigate-204-expected.txt
@@ -6,5 +6,6 @@
         frameId : <string>
         loaderId : <string>
     }
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/page-navigatedWithinDocument-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/page-navigatedWithinDocument-expected.txt
index 41e6e6a6..84531bf 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/page-navigatedWithinDocument-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/page/page-navigatedWithinDocument-expected.txt
@@ -6,6 +6,7 @@
         frameId : <string>
         url : http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html#foo
     }
+    sessionId : <string>
 }
 -- Test Page.navigate() to another anchor URL --
 {
@@ -14,6 +15,7 @@
         frameId : <string>
         url : http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html#bar
     }
+    sessionId : <string>
 }
 -- Test history.pushState() --
 {
@@ -22,6 +24,7 @@
         frameId : <string>
         url : http://127.0.0.1:8000/inspector-protocol/resources/wow.html
     }
+    sessionId : <string>
 }
 -- Test history.replaceState() --
 {
@@ -30,6 +33,7 @@
         frameId : <string>
         url : http://127.0.0.1:8000/replaced.html
     }
+    sessionId : <string>
 }
 -- Test history.back() --
 {
@@ -38,6 +42,7 @@
         frameId : <string>
         url : http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html#bar
     }
+    sessionId : <string>
 }
 -- Test history.forward() --
 {
@@ -46,5 +51,6 @@
         frameId : <string>
         url : http://127.0.0.1:8000/replaced.html
     }
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/inspector-protocol-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/inspector-protocol-test.js
index 7d9fb8a..d6d42b5 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/inspector-protocol-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/inspector-protocol-test.js
@@ -10,6 +10,7 @@
     this._log = log;
     this._completeTest = completeTest;
     this._fetch = fetch;
+    this._browserSession = new TestRunner.Session(this, '');
   }
 
   startDumpingProtocolMessages() {
@@ -26,7 +27,7 @@
     this._log.call(null, item);
   }
 
-  _logObject(object, title, stabilizeNames = ['id', 'nodeId', 'objectId', 'scriptId', 'timestamp', 'backendNodeId', 'parentId', 'frameId', 'loaderId', 'baseURL', 'documentURL', 'styleSheetId', 'executionContextId', 'targetId', 'browserContextId']) {
+  _logObject(object, title, stabilizeNames = ['id', 'nodeId', 'objectId', 'scriptId', 'timestamp', 'backendNodeId', 'parentId', 'frameId', 'loaderId', 'baseURL', 'documentURL', 'styleSheetId', 'executionContextId', 'targetId', 'browserContextId', 'sessionId']) {
     var lines = [];
 
     function dumpValue(value, prefix, prefixWithName) {
@@ -78,7 +79,7 @@
   }
 
   url(relative) {
-    if (relative.startsWith('http://') || relative.startsWith('https://'))
+    if (relative.startsWith('http://') || relative.startsWith('https://') || relative.startsWith('file://'))
       return relative;
     return this._targetBaseURL + relative;
   }
@@ -130,29 +131,43 @@
     return eval(`${source}\n//# sourceURL=${url}`);
   };
 
-  async createPage() {
-    var targetId = (await DevToolsAPI._sendCommandOrDie('Target.createTarget', {url: 'about:blank'})).targetId;
-    await DevToolsAPI._sendCommandOrDie('Target.activateTarget', {targetId});
-    var page = new TestRunner.Page(this, targetId);
-    var dummyURL = DevToolsHost.dummyPageURL;
-    if (!dummyURL) {
-      dummyURL = window.location.href;
-      dummyURL = dummyURL.substring(0, dummyURL.indexOf('inspector-protocol-test.html')) + 'inspector-protocol-page.html';
+  browserP() {
+    return this._browserSession.protocol;
+  }
+
+  async createPage(options) {
+    options = options || {};
+    const browserProtocol = this._browserSession.protocol;
+    const params = {url: 'about:blank'};
+    if (options.width)
+      params.width = options.width;
+    if (options.height)
+      params.height = options.height;
+    if (options.enableBeginFrameControl)
+      params.enableBeginFrameControl = true;
+    if (options.createContext) {
+      const browserContextId = (await browserProtocol.Target.createBrowserContext()).result.browserContextId;
+      options.browserContextId = browserContextId;
     }
-    await page._navigate(dummyURL);
+    const targetId = (await browserProtocol.Target.createTarget(params)).result.targetId;
+    const page = new TestRunner.Page(this, targetId);
+    let url = options.url || DevToolsHost.dummyPageURL;
+    if (!url) {
+      url = window.location.href;
+      url = url.substring(0, url.indexOf('inspector-protocol-test.html')) + 'inspector-protocol-page.html';
+    }
+    await page.navigate(url);
     return page;
   }
 
-  async _start(description, html, url) {
+  async _start(description, options) {
     try {
       if (!description)
         throw new Error('Please provide a description for the test!');
       this.log(description);
-      var page = await this.createPage();
-      if (url)
-        await page.navigate(url);
-      if (html)
-        await page.loadHTML(html);
+      var page = await this.createPage(options);
+      if (options.html)
+        await page.loadHTML(options.html);
       var session = await page.createSession();
       return { page: page, session: session, dp: session.protocol };
     } catch (e) {
@@ -160,16 +175,29 @@
     }
   };
 
-  startBlank(description) {
-    return this._start(description, null, null);
+  startBlank(description, options) {
+    return this._start(description, options || {});
   }
 
-  startHTML(html, description) {
-    return this._start(description, html, null);
+  startHTML(html, description, options) {
+    options = options || {};
+    options.html = html;
+    return this._start(description, options);
   }
 
-  startURL(url, description) {
-    return this._start(description, null, url);
+  startURL(url, description, options) {
+    options = options || {};
+    options.url = url;
+    return this._start(description, options);
+  }
+
+  startWithFrameControl(description, options) {
+    options = options || {};
+    options.width = options.width || 800;
+    options.height = options.height || 600;
+    options.createContext = true;
+    options.enableBeginFrameControl = true;
+    return this._start(description, options);
   }
 
   async logStackTrace(debuggers, stackTrace, debuggerId) {
@@ -210,10 +238,9 @@
   }
 
   async createSession() {
-    var sessionId = (await DevToolsAPI._sendCommandOrDie('Target.attachToTarget', {targetId: this._targetId})).sessionId;
-    var session = new TestRunner.Session(this._testRunner, sessionId);
-    DevToolsAPI._sessions.set(sessionId, session);
-    return session;
+    let dp = this._testRunner._browserSession.protocol;
+    const sessionId = (await dp.Target.attachToTarget({targetId: this._targetId, flatten: true})).result.sessionId;
+    return new TestRunner.Session(this._testRunner, sessionId);
   }
 
   navigate(url) {
@@ -239,63 +266,27 @@
     this._testRunner = testRunner;
     this._sessionId = sessionId;
     this._requestId = 0;
-    this._dispatchTable = new Map();
     this._eventHandlers = new Map();
     this.protocol = this._setupProtocol();
-    this._childSessions = null;
-    this._parentSession = null;
+    this._parentSessionId = null;
+    DevToolsAPI._sessions.set(sessionId, this);
   }
 
   async disconnect() {
-    await DevToolsAPI._sendCommandOrDie('Target.detachFromTarget', {sessionId: this._sessionId});
-    if (this._parentSession)
-      this._parentSession._childSessions.delete(this._sessionId);
-    else
-      DevToolsAPI._sessions.delete(this._sessionId);
+    await DevToolsAPI._sendCommandOrDie(this._parentSessionId, 'Target.detachFromTarget', {sessionId: this._sessionId});
   }
 
   createChild(sessionId) {
-    if (!this._childSessions) {
-      this._childSessions = new Map();
-      this.protocol.Target.onReceivedMessageFromTarget(event => this._dispatchMessageFromTarget(event));
-    }
-    let session = new TestRunner.Session(this._testRunner, sessionId);
-    this._childSessions.set(sessionId, session);
-    session._parentSession = this;
+    const session = new TestRunner.Session(this._testRunner, sessionId);
+    session._parentSessionId = this._sessionId;
     return session;
   }
 
-  async createTargetInNewContext(width, height, url, enableBeginFrameControl) {
-    const browserContextId = (await this.protocol.Target.createBrowserContext())
-        .result.browserContextId;
-    const targetId = (await this.protocol.Target.createTarget(
-        {url, browserContextId, width, height, enableBeginFrameControl}))
-        .result.targetId;
-    const sessionId = (await this.protocol.Target.attachToTarget({targetId}))
-        .result.sessionId;
-    return this.createChild(sessionId);
-  }
-
-  _dispatchMessageFromTarget(event) {
-    var session = this._childSessions.get(event.params.sessionId);
-    if (session)
-      session._dispatchMessage(JSON.parse(event.params.message));
-  }
-
-  sendRawCommand(requestId, message) {
-    if (this._parentSession)
-      this._parentSession.sendCommand('Target.sendMessageToTarget', {sessionId: this._sessionId, message: message});
-    else
-      DevToolsAPI._sendCommandOrDie('Target.sendMessageToTarget', {sessionId: this._sessionId, message: message});
-    return new Promise(f => this._dispatchTable.set(requestId, f));
-  }
-
   sendCommand(method, params) {
     var requestId = ++this._requestId;
-    var messageObject = {'id': requestId, 'method': method, 'params': params};
     if (this._testRunner._dumpInspectorProtocolMessages)
-      this._testRunner.log(`frontend => backend: ${JSON.stringify(messageObject)}`);
-    return this.sendRawCommand(requestId, JSON.stringify(messageObject));
+      this._testRunner.log(`frontend => backend: ${JSON.stringify({method, params, sessionId: this._sessionId})}`);
+    return DevToolsAPI._sendCommand(this._sessionId, method, params);
   }
 
   async evaluate(code, ...args) {
@@ -340,17 +331,9 @@
   _dispatchMessage(message) {
     if (this._testRunner._dumpInspectorProtocolMessages)
       this._testRunner.log(`backend => frontend: ${JSON.stringify(message)}`);
-    if (typeof message.id === 'number') {
-      var handler = this._dispatchTable.get(message.id);
-      if (handler) {
-        this._dispatchTable.delete(message.id);
-        handler(message);
-      }
-    } else {
-      var eventName = message.method;
-      for (var handler of (this._eventHandlers.get(eventName) || []))
-        handler(message);
-    }
+    var eventName = message.method;
+    for (var handler of (this._eventHandlers.get(eventName) || []))
+      handler(message);
   }
 
   _setupProtocol() {
@@ -505,32 +488,31 @@
       if (handler) {
         DevToolsAPI._dispatchTable.delete(messageId);
         handler(messageObject);
+      } else {
+        DevToolsAPI._die(`Unexpected result id ${messageId}`);
       }
     } else {
-      var eventName = messageObject.method;
-      if (eventName === 'Target.receivedMessageFromTarget') {
-        var sessionId = messageObject.params.sessionId;
-        var message = messageObject.params.message;
-        var session = DevToolsAPI._sessions.get(sessionId);
-        if (session)
-          session._dispatchMessage(JSON.parse(message));
-      }
+      var session = DevToolsAPI._sessions.get(messageObject.sessionId);
+      if (session)
+        session._dispatchMessage(messageObject);
     }
   } catch(e) {
     DevToolsAPI._die(`Exception when dispatching message\n${JSON.stringify(messageObject)}`, e);
   }
 };
 
-DevToolsAPI._sendCommand = function(method, params) {
+DevToolsAPI._sendCommand = function(sessionId, method, params) {
   var requestId = ++DevToolsAPI._requestId;
   var messageObject = {'id': requestId, 'method': method, 'params': params};
+  if (sessionId)
+    messageObject.sessionId = sessionId;
   var embedderMessage = {'id': ++DevToolsAPI._embedderMessageId, 'method': 'dispatchProtocolMessage', 'params': [JSON.stringify(messageObject)]};
   DevToolsHost.sendMessageToEmbedder(JSON.stringify(embedderMessage));
   return new Promise(f => DevToolsAPI._dispatchTable.set(requestId, f));
 };
 
-DevToolsAPI._sendCommandOrDie = function(method, params) {
-  return DevToolsAPI._sendCommand(method, params).then(message => {
+DevToolsAPI._sendCommandOrDie = function(sessionId, method, params) {
+  return DevToolsAPI._sendCommand(sessionId, method, params).then(message => {
     if (message.error)
       DevToolsAPI._die('Error communicating with harness', new Error(JSON.stringify(message.error)));
     return message.result;
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/runtime/runtime-evaluate-silent-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/runtime/runtime-evaluate-silent-expected.txt
index 7ced510..653eca4 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/runtime/runtime-evaluate-silent-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/runtime/runtime-evaluate-silent-expected.txt
@@ -10,6 +10,7 @@
             value : false
         }
     }
+    sessionId : <string>
 }
 UseCounter should be unsilenced when unmuted
 {
@@ -20,5 +21,6 @@
             value : true
         }
     }
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/target/target-expose-devtools-protocol.js b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/target/target-expose-devtools-protocol.js
index 816c707..1cd557cc 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/target/target-expose-devtools-protocol.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/target/target-expose-devtools-protocol.js
@@ -1,7 +1,7 @@
 (async function(testRunner) {
   // 1. Create a page, connect to it and use browser connection to grant it a remote debugging capability.
   const {page, session, dp} = await testRunner.startBlank('Verify that exposing devtools protocol yields a functional protocol.');
-  await DevToolsAPI._sendCommandOrDie('Target.exposeDevToolsProtocol', {targetId: page._targetId, bindingName: 'cdp'});
+  await testRunner.browserP().Target.exposeDevToolsProtocol({targetId: page._targetId, bindingName: 'cdp'});
 
   // 2. To avoid implementing a protocol client in test, use target domain to validate protocol binding.
   await dp.Target.setDiscoverTargets({discover: true});
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/target/wait-for-debugger.js b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/target/wait-for-debugger.js
index bfc0bfe..db72be1e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/target/wait-for-debugger.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/target/wait-for-debugger.js
@@ -2,7 +2,7 @@
   var {page, session, dp} = await testRunner.startBlank(
       `Tests that waitForDebuggerOnStart works with out-of-process iframes.`);
 
-  await dp.Target.setAutoAttach({autoAttach: true, waitForDebuggerOnStart: true});
+  await dp.Target.setAutoAttach({autoAttach: true, waitForDebuggerOnStart: true, flatten: true});
 
   await dp.Page.enable();
   dp.Network.enable();
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/console/console-dom-mutation-violations-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/console/console-dom-mutation-violations-expected.txt
index 119cf79b..8434c51 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/console/console-dom-mutation-violations-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/console/console-dom-mutation-violations-expected.txt
@@ -21,5 +21,6 @@
             timestamp : <number>
         }
     }
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/console/console-memory-setter-in-strict-mode-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/console/console-memory-setter-in-strict-mode-expected.txt
index 3984939..cc7ae8a5 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/console/console-memory-setter-in-strict-mode-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/console/console-memory-setter-in-strict-mode-expected.txt
@@ -6,5 +6,6 @@
             type : undefined
         }
     }
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames-expected.txt
index 2ab63df..3a9ad7c4 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames-expected.txt
@@ -144,5 +144,6 @@
         ]
         parentId : <number>
     }
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes-expected.txt
index 4f27c26..54a39d9f 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes-expected.txt
@@ -292,5 +292,6 @@
             xmlVersion : 
         }
     }
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setOuterHTML-detached-document-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setOuterHTML-detached-document-expected.txt
index 65397911..b97ff83 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setOuterHTML-detached-document-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setOuterHTML-detached-document-expected.txt
@@ -3,5 +3,6 @@
     id : <number>
     result : {
     }
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setOuterHTML-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setOuterHTML-expected.txt
index bc037ccb..2610ff3 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setOuterHTML-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-setOuterHTML-expected.txt
@@ -4,5 +4,6 @@
     result : {
         outerHTML : <body><div>Привет мир 1</div>     <div>Привет мир 2</div>   </body>
     }
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchTouchEvent-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchTouchEvent-expected.txt
index 2ad2a30d..976ac48 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchTouchEvent-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/input/dispatchTouchEvent-expected.txt
@@ -301,6 +301,7 @@
         message : Must send a TouchStart first to start a new touch.
     }
     id : <number>
+    sessionId : <string>
 }
 
 
@@ -318,6 +319,7 @@
         message : TouchStart and TouchMove must have at least one touch point.
     }
     id : <number>
+    sessionId : <string>
 }
 
 
@@ -360,6 +362,7 @@
         message : TouchEnd and TouchCancel must not have any touch points.
     }
     id : <number>
+    sessionId : <string>
 }
 
 
@@ -379,6 +382,7 @@
         message : TouchEnd and TouchCancel must not have any touch points.
     }
     id : <number>
+    sessionId : <string>
 }
 
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/json-parse-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/json-parse-expected.txt
deleted file mode 100644
index 5d527c01..0000000
--- a/third_party/WebKit/LayoutTests/inspector-protocol/json-parse-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Tests that backend correctly handles unicode in messages
-{
-    id : <number>
-    result : {
-        result : {
-            type : string
-            value : Привет мир
-        }
-    }
-}
-
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/json-parse.js b/third_party/WebKit/LayoutTests/inspector-protocol/json-parse.js
deleted file mode 100644
index f6d26bbc..0000000
--- a/third_party/WebKit/LayoutTests/inspector-protocol/json-parse.js
+++ /dev/null
@@ -1,13 +0,0 @@
-(async function(testRunner) {
-  var {page, session, dp} = await testRunner.startBlank('Tests that backend correctly handles unicode in messages');
-
-  var requestId = 100500;
-  var command = {
-    'method': 'Runtime.evaluate',
-    'params': {expression: '\'!!!\''},
-    'id': requestId
-  };
-  var message = JSON.stringify(command).replace('!!!', '\\u041F\\u0440\\u0438\\u0432\\u0435\\u0442 \\u043C\\u0438\\u0440');
-  testRunner.log(await session.sendRawCommand(requestId, message));
-  testRunner.completeTest();
-})
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/pageNavigateToFragment-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/page/pageNavigateToFragment-expected.txt
index 90e7b564..51070b2 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/pageNavigateToFragment-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/pageNavigateToFragment-expected.txt
@@ -5,6 +5,7 @@
         frameId : <string>
         loaderId : <string>
     }
+    sessionId : <string>
 }
 {
     id : <number>
@@ -12,5 +13,6 @@
         frameId : <string>
         loaderId : <string>
     }
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/terminate-execution-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/page/terminate-execution-expected.txt
index 155491ea..d9e1603 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/page/terminate-execution-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/terminate-execution-expected.txt
@@ -3,6 +3,7 @@
     id : <number>
     result : {
     }
+    sessionId : <string>
 }
 {
     error : {
@@ -10,5 +11,6 @@
         message : Execution was terminated
     }
     id : <number>
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-log-handle-navigate-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-log-handle-navigate-expected.txt
index 7b3e6eb..10bfb57 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-log-handle-navigate-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-console-log-handle-navigate-expected.txt
@@ -6,6 +6,7 @@
         message : Cannot find context with specified id
     }
     id : <number>
+    sessionId : <string>
 }
 Got new context: true
 {
@@ -14,6 +15,7 @@
         message : Cannot find context with specified id
     }
     id : <number>
+    sessionId : <string>
 }
 Got new context: true
 {
@@ -22,5 +24,6 @@
         message : Cannot find context with specified id
     }
     id : <number>
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-evaluate-return-by-value-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-evaluate-return-by-value-expected.txt
index 4a0b044..d896cdd 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-evaluate-return-by-value-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-evaluate-return-by-value-expected.txt
@@ -7,6 +7,7 @@
         message : Object couldn't be returned by value
     }
     id : <number>
+    sessionId : <string>
 }
 
 Running test: testObjectWithChain
@@ -16,5 +17,6 @@
         message : Object reference chain is too long
     }
     id : <number>
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-evaluate-with-context-id-equal-zero-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-evaluate-with-context-id-equal-zero-expected.txt
index f3f69e0..ee5e034 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-evaluate-with-context-id-equal-zero-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-evaluate-with-context-id-equal-zero-expected.txt
@@ -5,5 +5,6 @@
         message : Cannot find context with specified id
     }
     id : <number>
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-evaluate-without-enabling-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-evaluate-without-enabling-expected.txt
index c624a3f..e745a30 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-evaluate-without-enabling-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-evaluate-without-enabling-expected.txt
@@ -5,5 +5,6 @@
         message : Cannot find context with specified id
     }
     id : <number>
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-install-binding-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-install-binding-expected.txt
index 33ffbf5..7aa62e3 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-install-binding-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-install-binding-expected.txt
@@ -4,6 +4,7 @@
     id : <number>
     result : {
     }
+    sessionId : <string>
 }
 Add script to replace console.debug with binding on load..
 Add iframe with console.debug call..
@@ -14,6 +15,7 @@
         name : send
         payload : payload
     }
+    sessionId : <string>
 }
 Navigate to page with console.debug..
 {
@@ -23,5 +25,6 @@
         name : send
         payload : payload
     }
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-shouldnt-crash-after-inspected-context-destroyed-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-shouldnt-crash-after-inspected-context-destroyed-expected.txt
index 16f83b8..70b5a3c 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-shouldnt-crash-after-inspected-context-destroyed-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-shouldnt-crash-after-inspected-context-destroyed-expected.txt
@@ -6,5 +6,6 @@
             type : undefined
         }
     }
+    sessionId : <string>
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/sessions/log-entry-added-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/sessions/log-entry-added-expected.txt
index 8ad4ccd4..49336920 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/sessions/log-entry-added-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/sessions/log-entry-added-expected.txt
@@ -24,6 +24,7 @@
             timestamp : <number>
         }
     }
+    sessionId : <string>
 }
 Enabling logging in session2
 Triggering violation
@@ -50,6 +51,7 @@
             timestamp : <number>
         }
     }
+    sessionId : <string>
 }
 From session2:
 {
@@ -74,6 +76,7 @@
             timestamp : <number>
         }
     }
+    sessionId : <string>
 }
 Disabling logging in session1
 Triggering violation
@@ -100,6 +103,7 @@
             timestamp : <number>
         }
     }
+    sessionId : <string>
 }
 Disabling logging in session2
 Triggering violation
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/sessions/tracing-start-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/sessions/tracing-start-expected.txt
index 29cd75a..422f2fb 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/sessions/tracing-start-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/sessions/tracing-start-expected.txt
@@ -4,6 +4,7 @@
     id : <number>
     result : {
     }
+    sessionId : <string>
 }
 Starting tracing in session2
 {
@@ -12,12 +13,14 @@
         message : Tracing is already started
     }
     id : <number>
+    sessionId : <string>
 }
 Stopping tracing in session1
 {
     id : <number>
     result : {
     }
+    sessionId : <string>
 }
 Stopping tracing in session2
 {
@@ -26,6 +29,7 @@
         message : Tracing is not started
     }
     id : <number>
+    sessionId : <string>
 }
 session1: dataCollected=true tracingComplete=true
 session2: dataCollected=false tracingComplete=false
diff --git a/third_party/blink/public/platform/web_layer_tree_view.h b/third_party/blink/public/platform/web_layer_tree_view.h
index 46838bbf2..a4ed392a 100644
--- a/third_party/blink/public/platform/web_layer_tree_view.h
+++ b/third_party/blink/public/platform/web_layer_tree_view.h
@@ -145,6 +145,9 @@
   // dirty.
   virtual void SetNeedsBeginFrame() {}
 
+  // Relays the end of a fling animation.
+  virtual void DidStopFlinging() {}
+
   // Run layout and paint of all pending document changes asynchronously.
   virtual void LayoutAndPaintAsync(base::OnceClosure callback) {}
 
diff --git a/third_party/blink/renderer/core/events/wheel_event.cc b/third_party/blink/renderer/core/events/wheel_event.cc
index c26e75a..3b1ce775 100644
--- a/third_party/blink/renderer/core/events/wheel_event.cc
+++ b/third_party/blink/renderer/core/events/wheel_event.cc
@@ -117,9 +117,9 @@
 }
 
 void WheelEvent::preventDefault() {
-  UIEventWithKeyState::preventDefault();
+  MouseEvent::preventDefault();
 
-  if (HandlingPassive() == PassiveMode::kNotPassiveDefault &&
+  if (HandlingPassive() == PassiveMode::kNotPassiveDefault && currentTarget() &&
       currentTarget()->IsTopLevelNode()) {
     if (ExecutionContext* context = currentTarget()->GetExecutionContext()) {
       UseCounter::Count(
diff --git a/third_party/blink/renderer/core/exported/web_associated_url_loader_impl_test.cc b/third_party/blink/renderer/core/exported/web_associated_url_loader_impl_test.cc
index 699f85f..8162e306 100644
--- a/third_party/blink/renderer/core/exported/web_associated_url_loader_impl_test.cc
+++ b/third_party/blink/renderer/core/exported/web_associated_url_loader_impl_test.cc
@@ -520,7 +520,7 @@
 
   ServeRequests();
   // We should get a notification about access control check failure.
-  EXPECT_FALSE(will_follow_redirect_);
+  EXPECT_TRUE(will_follow_redirect_);
   EXPECT_FALSE(did_receive_response_);
   EXPECT_FALSE(did_receive_data_);
   EXPECT_TRUE(did_fail_);
@@ -568,8 +568,7 @@
   EXPECT_TRUE(expected_loader_);
   expected_loader_->LoadAsynchronously(request, this);
   ServeRequests();
-  // We should not receive a notification for the redirect.
-  EXPECT_FALSE(will_follow_redirect_);
+  EXPECT_TRUE(will_follow_redirect_);
   EXPECT_TRUE(did_receive_response_);
   EXPECT_TRUE(did_receive_data_);
   EXPECT_TRUE(did_finish_loading_);
diff --git a/third_party/blink/renderer/core/fetch/fetch_manager.cc b/third_party/blink/renderer/core/fetch/fetch_manager.cc
index 2962b4c..a8f81a3 100644
--- a/third_party/blink/renderer/core/fetch/fetch_manager.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_manager.cc
@@ -179,7 +179,7 @@
   ~Loader() override;
   virtual void Trace(blink::Visitor*);
 
-  void DidReceiveRedirectTo(const KURL&) override;
+  bool WillFollowRedirect(const KURL&, const ResourceResponse&) override;
   void DidReceiveResponse(unsigned long,
                           const ResourceResponse&,
                           std::unique_ptr<WebDataConsumerHandle>) override;
@@ -376,8 +376,10 @@
   visitor->Trace(execution_context_);
 }
 
-void FetchManager::Loader::DidReceiveRedirectTo(const KURL& url) {
+bool FetchManager::Loader::WillFollowRedirect(const KURL& url,
+                                              const ResourceResponse&) {
   url_list_.push_back(url);
+  return true;
 }
 
 void FetchManager::Loader::DidReceiveResponse(
diff --git a/third_party/blink/renderer/core/html/parser/html_parser_idioms.cc b/third_party/blink/renderer/core/html/parser/html_parser_idioms.cc
index 21df2ee..d63469d 100644
--- a/third_party/blink/renderer/core/html/parser/html_parser_idioms.cc
+++ b/third_party/blink/renderer/core/html/parser/html_parser_idioms.cc
@@ -377,7 +377,7 @@
 
   for (const auto& html_attribute : attributes) {
     const String& attribute_name = html_attribute.first;
-    const String& attribute_value = AtomicString(html_attribute.second);
+    const AtomicString& attribute_value = AtomicString(html_attribute.second);
 
     if (ThreadSafeMatch(attribute_name, http_equivAttr)) {
       if (DeprecatedEqualIgnoringCase(attribute_value, "content-type"))
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
index 331e67d8..237448d 100644
--- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl
+++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -5932,6 +5932,8 @@
       # Whether to pause new targets when attaching to them. Use `Runtime.runIfWaitingForDebugger`
       # to run paused targets.
       boolean waitForDebuggerOnStart
+      # Enables "flat" access to the session via specifying sessionId attribute in the commands.
+      experimental optional boolean flatten
 
   # Controls whether to discover available targets and notify via
   # `targetCreated/targetInfoChanged/targetDestroyed` events.
diff --git a/third_party/blink/renderer/core/inspector/inspector_worker_agent.cc b/third_party/blink/renderer/core/inspector/inspector_worker_agent.cc
index 56fde78..9cb95fcb 100644
--- a/third_party/blink/renderer/core/inspector/inspector_worker_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_worker_agent.cc
@@ -79,7 +79,8 @@
 }
 
 Response InspectorWorkerAgent::setAutoAttach(bool auto_attach,
-                                             bool wait_for_debugger_on_start) {
+                                             bool wait_for_debugger_on_start,
+                                             Maybe<bool> flatten) {
   wait_for_debugger_on_start_.Set(wait_for_debugger_on_start);
 
   if (auto_attach == auto_attach_.Get())
diff --git a/third_party/blink/renderer/core/inspector/inspector_worker_agent.h b/third_party/blink/renderer/core/inspector/inspector_worker_agent.h
index b482a7a..6f2a733 100644
--- a/third_party/blink/renderer/core/inspector/inspector_worker_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_worker_agent.h
@@ -63,7 +63,8 @@
 
   // Called from Dispatcher
   protocol::Response setAutoAttach(bool auto_attach,
-                                   bool wait_for_debugger_on_start) override;
+                                   bool wait_for_debugger_on_start,
+                                   protocol::Maybe<bool> flatten) override;
   protocol::Response sendMessageToTarget(
       const String& message,
       protocol::Maybe<String> session_id,
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc b/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
index 8b355a9f..05f71c3 100644
--- a/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
+++ b/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
@@ -16,16 +16,9 @@
 namespace {
 
 bool IsOccluded(const Element& element, const IntersectionGeometry& geometry) {
-  HitTestResult hits(
+  HitTestResult result(
       element.GetLayoutObject()->HitTestForOcclusion(geometry.TargetRect()));
-  const HitTestResult::NodeSet& hit_nodes = hits.ListBasedTestResult();
-  for (const auto& node : hit_nodes) {
-    if (!node->contains(&element) &&
-        node->GetLayoutObject()->HasNonZeroEffectiveOpacity()) {
-      return true;
-    }
-  }
-  return false;
+  return result.InnerNode() && result.InnerNode() != &element;
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc b/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc
index c867a3d..02b513f 100644
--- a/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc
+++ b/third_party/blink/renderer/core/intersection_observer/intersection_observer_test.cc
@@ -354,6 +354,16 @@
   EXPECT_EQ(observer_delegate->EntryCount(), 2);
   EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting());
   EXPECT_FALSE(observer_delegate->LastEntry()->isVisible());
+
+  // Zero-opacity objects should not count as occluding.
+  occluder->SetInlineStyleProperty(CSSPropertyOpacity, "0");
+  Compositor().BeginFrame();
+  test::RunPendingTasks();
+  ASSERT_FALSE(Compositor().NeedsBeginFrame());
+  EXPECT_EQ(observer_delegate->CallCount(), 3);
+  EXPECT_EQ(observer_delegate->EntryCount(), 3);
+  EXPECT_TRUE(observer_delegate->LastEntry()->isIntersecting());
+  EXPECT_TRUE(observer_delegate->LastEntry()->isVisible());
 }
 
 TEST_F(IntersectionObserverV2Test, BasicOpacity) {
diff --git a/third_party/blink/renderer/core/layout/hit_test_request.h b/third_party/blink/renderer/core/layout/hit_test_request.h
index e7626ce..0c3e6e9 100644
--- a/third_party/blink/renderer/core/layout/hit_test_request.h
+++ b/third_party/blink/renderer/core/layout/hit_test_request.h
@@ -52,6 +52,7 @@
     // testing after a hit has been found.
     kPenetratingList = 1 << 12,
     kAvoidCache = 1 << 13,
+    kIgnoreZeroOpacityObjects = 1 << 14,
   };
 
   typedef unsigned HitTestRequestType;
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 9fa10d6..7ce1cd5 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -1701,9 +1701,9 @@
   LocalFrame* frame = GetDocument().GetFrame();
   DCHECK(!frame->View()->NeedsLayout());
   HitTestRequest::HitTestRequestType hit_type =
-      HitTestRequest::kListBased | HitTestRequest::kPenetratingList |
       HitTestRequest::kIgnorePointerEventsNone | HitTestRequest::kReadOnly |
-      HitTestRequest::kIgnoreClipping;
+      HitTestRequest::kIgnoreClipping |
+      HitTestRequest::kIgnoreZeroOpacityObjects;
   HitTestLocation location(hit_rect);
   return frame->GetEventHandler().HitTestResultAtLocation(location, hit_type,
                                                           this, true);
diff --git a/third_party/blink/renderer/core/layout/layout_view.cc b/third_party/blink/renderer/core/layout/layout_view.cc
index 52975440..df7732d 100644
--- a/third_party/blink/renderer/core/layout/layout_view.cc
+++ b/third_party/blink/renderer/core/layout/layout_view.cc
@@ -137,8 +137,6 @@
   TRACE_EVENT_BEGIN0("blink,devtools.timeline", "HitTest");
   hit_test_count_++;
 
-  DCHECK(!location.IsRectBasedTest() || result.GetHitTestRequest().ListBased());
-
   uint64_t dom_tree_version = GetDocument().DomTreeVersion();
   HitTestResult cache_result = result;
   bool hit_layer = false;
diff --git a/third_party/blink/renderer/core/loader/threadable_loader.cc b/third_party/blink/renderer/core/loader/threadable_loader.cc
index 20f364f..a3c9c51 100644
--- a/third_party/blink/renderer/core/loader/threadable_loader.cc
+++ b/third_party/blink/renderer/core/loader/threadable_loader.cc
@@ -671,16 +671,10 @@
       return false;
     }
 
-    if (out_of_blink_cors_) {
-      client_->DidReceiveRedirectTo(new_url);
-      client_->WillFollowRedirect(new_url, redirect_response);
-      return true;
-    }
-
     // Allow same origin requests to continue after allowing clients to audit
     // the redirect.
-    if (IsAllowedRedirect(new_request.GetFetchRequestMode(), new_url)) {
-      client_->DidReceiveRedirectTo(new_url);
+    if (out_of_blink_cors_ ||
+        IsAllowedRedirect(new_request.GetFetchRequestMode(), new_url)) {
       return client_->WillFollowRedirect(new_url, redirect_response);
     }
 
@@ -721,7 +715,7 @@
       }
     }
 
-    client_->DidReceiveRedirectTo(new_url);
+    client_->WillFollowRedirect(new_url, redirect_response);
 
     // FIXME: consider combining this with CORS redirect handling performed by
     // CrossOriginAccessControl::handleRedirect().
diff --git a/third_party/blink/renderer/core/loader/threadable_loader_client.h b/third_party/blink/renderer/core/loader/threadable_loader_client.h
index a5404ed7..760c66c 100644
--- a/third_party/blink/renderer/core/loader/threadable_loader_client.h
+++ b/third_party/blink/renderer/core/loader/threadable_loader_client.h
@@ -50,8 +50,6 @@
  public:
   virtual void DidSendData(unsigned long long /*bytesSent*/,
                            unsigned long long /*totalBytesToBeSent*/) {}
-  // TODO(japhet?): Merge these redirect callbacks.
-  virtual void DidReceiveRedirectTo(const KURL&) {}
   virtual bool WillFollowRedirect(const KURL& new_url,
                                   const ResourceResponse&) {
     return true;
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 4d93fdf..2603238 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -2001,6 +2001,12 @@
   if (!IsSelfPaintingLayer() && !HasSelfPaintingLayerDescendant())
     return nullptr;
 
+  if ((result.GetHitTestRequest().GetType() &
+       HitTestRequest::kIgnoreZeroOpacityObjects) &&
+      !layout_object.HasNonZeroEffectiveOpacity()) {
+    return nullptr;
+  }
+
   ShouldRespectOverflowClipType clip_behavior = kRespectOverflowClip;
   if (result.GetHitTestRequest().IgnoreClipping())
     clip_behavior = kIgnoreOverflowClip;
@@ -2127,8 +2133,8 @@
     candidate_layer = hit_layer;
   }
 
-  // Collect the fragments. This will compute the clip rectangles for each layer
-  // fragment.
+  // Collect the fragments. This will compute the clip rectangles for each
+  // layer fragment.
   base::Optional<PaintLayerFragments> layer_fragments;
   LayoutPoint offset;
   if (recursion_data.intersects_location) {
@@ -2208,7 +2214,7 @@
                                     inside_fragment_background_rect) &&
         IsHitCandidate(this, false, z_offset_for_contents_ptr,
                        unflattened_transform_state.get())) {
-      if (recursion_data.original_location.IsRectBasedTest())
+      if (result.GetHitTestRequest().ListBased())
         result.Append(temp_result);
       else
         result = temp_result;
@@ -2331,7 +2337,7 @@
   if (!GetLayoutObject().HitTestAllPhases(result, hit_test_location,
                                           fragment_offset, hit_test_filter)) {
     // It's wrong to set innerNode, but then claim that you didn't hit anything,
-    // unless it is a rect-based test.
+    // unless it is a list-based test.
     DCHECK(!result.InnerNode() || (result.GetHitTestRequest().ListBased() &&
                                    result.ListBasedTestResult().size()));
     return false;
@@ -2432,8 +2438,6 @@
 
     // If it is a list-based test, we can safely append the temporary result
     // since it might had hit nodes but not necesserily had hitLayer set.
-    DCHECK(!recursion_data.original_location.IsRectBasedTest() ||
-           result.GetHitTestRequest().ListBased());
     if (result.GetHitTestRequest().ListBased())
       result.Append(temp_result);
 
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js b/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js
index d380af9..71393cc 100644
--- a/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js
+++ b/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js
@@ -583,7 +583,7 @@
     if (!this._currentGroup.messagesHidden()) {
       const originatingMessage = viewMessage.consoleMessage().originatingMessage();
       if (lastMessage && originatingMessage && lastMessage.consoleMessage() === originatingMessage)
-        lastMessage.toMessageElement().classList.add('console-adjacent-user-command-result');
+        viewMessage.toMessageElement().classList.add('console-adjacent-user-command-result');
 
       this._visibleViewMessages.push(viewMessage);
       this._searchMessage(this._visibleViewMessages.length - 1);
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js b/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js
index ebf57f65..de0d78f 100644
--- a/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js
+++ b/third_party/blink/renderer/devtools/front_end/console/ConsoleViewMessage.js
@@ -93,7 +93,7 @@
    */
   willHide() {
     this._isVisible = false;
-    this._cachedHeight = this.contentElement().offsetHeight;
+    this._cachedHeight = this.element().offsetHeight;
   }
 
   /**
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsoleViewport.js b/third_party/blink/renderer/devtools/front_end/console/ConsoleViewport.js
index 023ecc6..571ac47 100644
--- a/third_party/blink/renderer/devtools/front_end/console/ConsoleViewport.js
+++ b/third_party/blink/renderer/devtools/front_end/console/ConsoleViewport.js
@@ -166,13 +166,22 @@
   }
 
   _rebuildCumulativeHeightsIfNeeded() {
+    let totalCachedHeight = 0;
+    let totalMeasuredHeight = 0;
     // Check whether current items in DOM have changed heights. Tolerate 1-pixel
     // error due to double-to-integer rounding errors.
     for (let i = 0; i < this._renderedItems.length; ++i) {
       const cachedItemHeight = this._cachedItemHeight(this._firstActiveIndex + i);
-      if (Math.abs(cachedItemHeight - this._renderedItems[i].element().offsetHeight) > 1) {
+      const measuredHeight = this._renderedItems[i].element().offsetHeight;
+      if (Math.abs(cachedItemHeight - measuredHeight) > 1) {
         this._rebuildCumulativeHeights();
-        break;
+        return;
+      }
+      totalMeasuredHeight += measuredHeight;
+      totalCachedHeight += cachedItemHeight;
+      if (Math.abs(totalCachedHeight - totalMeasuredHeight) > 1) {
+        this._rebuildCumulativeHeights();
+        return;
       }
     }
   }
@@ -534,6 +543,9 @@
     const lastVisibleIndex = this.lastVisibleIndex();
     if (index > firstVisibleIndex && index < lastVisibleIndex)
       return;
+    // If the prompt is visible, then the last item must be fully on screen.
+    if (index === lastVisibleIndex && this._cumulativeHeights[index] <= this.element.scrollTop + this._visibleHeight())
+      return;
     if (makeLast)
       this.forceScrollItemToBeLast(index);
     else if (index <= firstVisibleIndex)
@@ -553,6 +565,8 @@
     if (this.element.isScrolledToBottom())
       this.setStickToBottom(true);
     this.refresh();
+    // After refresh, the item is in DOM, but may not be visible (items above were larger than expected).
+    this.renderedElementAt(index).scrollIntoView(true /* alignTop */);
   }
 
   /**
@@ -566,6 +580,8 @@
     if (this.element.isScrolledToBottom())
       this.setStickToBottom(true);
     this.refresh();
+    // After refresh, the item is in DOM, but may not be visible (items above were larger than expected).
+    this.renderedElementAt(index).scrollIntoView(false /* alignTop */);
   }
 
   /**
diff --git a/third_party/blink/renderer/devtools/front_end/console/consoleView.css b/third_party/blink/renderer/devtools/front_end/console/consoleView.css
index 2e7e2792..a6b71fb 100644
--- a/third_party/blink/renderer/devtools/front_end/console/consoleView.css
+++ b/third_party/blink/renderer/devtools/front_end/console/consoleView.css
@@ -30,6 +30,9 @@
 .console-view {
     background-color: white;
     overflow: hidden;
+    --message-border-color: rgb(240, 240, 240);
+    --warning-border-color: hsl(50, 100%, 88%);
+    --error-border-color: hsl(0, 100%, 92%);
 }
 
 .console-toolbar-container {
@@ -67,7 +70,6 @@
 
 #console-messages {
     flex: 1 1;
-    padding: 2px 0;
     overflow-y: auto;
     word-wrap: break-word;
     -webkit-user-select: text;
@@ -87,7 +89,7 @@
     position: relative;
     padding: 3px 22px 1px 0;
     margin-left: 24px;
-    min-height: 18px;  /* Sync with ConsoleViewMessage.js */
+    min-height: 17px;  /* Sync with ConsoleViewMessage.js */
     flex: auto;
     display: flex;
 }
@@ -180,23 +182,38 @@
 
 .console-message-wrapper {
     display: flex;
-    border-bottom: 1px solid rgb(240, 240, 240);
+    border-top: 1px solid var(--message-border-color);
+    border-bottom: 1px solid transparent;
 }
 
-.console-message-wrapper.console-adjacent-user-command-result {
-    border-bottom: none;
+.console-message-wrapper:first-of-type {
+    border-top-color: transparent;
 }
 
-.console-message-wrapper.console-error-level {
-    border-top: 1px solid hsl(0, 100%, 92%);
-    border-bottom: 1px solid hsl(0, 100%, 92%);
-    margin-top: -1px;
+.console-message-wrapper.console-adjacent-user-command-result:not(.console-error-level):not(.console-warning-level) {
+    border-top: none;
 }
 
-.console-message-wrapper.console-warning-level {
-    border-top: 1px solid hsl(50, 100%, 88%);
-    border-bottom: 1px solid hsl(50, 100%, 88%);
-    margin-top: -1px;
+.console-message-wrapper.console-error-level,
+.console-message-wrapper.console-error-level + .console-message-wrapper:not(.console-warning-level) {
+    border-top-color: var(--error-border-color);
+}
+
+.console-message-wrapper.console-warning-level,
+.console-message-wrapper.console-warning-level + .console-message-wrapper:not(.console-error-level) {
+    border-top-color: var(--warning-border-color);
+}
+
+.console-message-wrapper:last-of-type {
+    border-bottom-color: var(--message-border-color);
+}
+
+.console-message-wrapper.console-error-level:last-of-type {
+    border-bottom-color: var(--error-border-color);
+}
+
+.console-message-wrapper.console-warning-level:last-of-type {
+    border-bottom-color: var(--warning-border-color);
 }
 
 .console-message-wrapper .nesting-level-marker {
@@ -332,6 +349,10 @@
     clear: both;
 }
 
+.console-message .source-code {
+    line-height: 1.2;
+}
+
 .console-message-anchor {
     float: right;
     text-align: right;
diff --git a/third_party/blink/renderer/devtools/front_end/console_test_runner/ConsoleTestRunner.js b/third_party/blink/renderer/devtools/front_end/console_test_runner/ConsoleTestRunner.js
index e72a511f..dc28c73c 100644
--- a/third_party/blink/renderer/devtools/front_end/console_test_runner/ConsoleTestRunner.js
+++ b/third_party/blink/renderer/devtools/front_end/console_test_runner/ConsoleTestRunner.js
@@ -611,14 +611,12 @@
 };
 
 /**
- * Returns actual visible indices. Messages in the margin are treated as NOT visible.
  * @return {!{first: number, last: number, count: number}}
  */
 ConsoleTestRunner.visibleIndices = function() {
   const consoleView = Console.ConsoleView.instance();
   const viewport = consoleView._viewport;
   const viewportRect = viewport.element.getBoundingClientRect();
-  const viewportPadding = parseFloat(window.getComputedStyle(viewport.element).paddingTop);
   let first = -1;
   let last = -1;
   let count = 0;
@@ -628,8 +626,7 @@
     if (!item._element || !item._element.isConnected)
       continue;
     const itemRect = item._element.getBoundingClientRect();
-    const isVisible = (itemRect.bottom > viewportRect.top + viewportPadding + 1) &&
-        (itemRect.top <= viewportRect.bottom - viewportPadding - 1);
+    const isVisible = (itemRect.bottom > viewportRect.top + 1) && (itemRect.top <= viewportRect.bottom - 1);
     if (isVisible) {
       first = first === -1 ? i : first;
       last = i;
diff --git a/third_party/blink/renderer/modules/xr/xr_device.idl b/third_party/blink/renderer/modules/xr/xr_device.idl
index 30e102b..f8da225 100644
--- a/third_party/blink/renderer/modules/xr/xr_device.idl
+++ b/third_party/blink/renderer/modules/xr/xr_device.idl
@@ -7,6 +7,6 @@
     SecureContext,
     OriginTrialEnabled=WebXR
 ] interface XRDevice {
-  [CallWith=ScriptState, MeasureAs=XRSupportsSession] Promise supportsSession([PermissiveDictionaryConversion] optional XRSessionCreationOptions options);
-  [CallWith=ScriptState, MeasureAs=XRRequestSession] Promise requestSession([PermissiveDictionaryConversion] optional XRSessionCreationOptions options);
+  [CallWith=ScriptState, MeasureAs=XRSupportsSession] Promise<void> supportsSession([PermissiveDictionaryConversion] optional XRSessionCreationOptions options);
+  [CallWith=ScriptState, MeasureAs=XRRequestSession] Promise<XRSession> requestSession([PermissiveDictionaryConversion] optional XRSessionCreationOptions options);
 };
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
index 7d8fccd..6549d0f 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -84,7 +84,9 @@
   if (!host)
     return;
   for (auto child : root_layer_->children()) {
-    host->UnregisterElement(child->element_id(), cc::ElementListType::ACTIVE);
+    auto element_id = child->element_id();
+    if (element_id)
+      host->UnregisterElement(element_id, cc::ElementListType::ACTIVE);
   }
   root_layer_->RemoveAllChildren();
   if (extra_data_for_testing_enabled_) {
diff --git a/third_party/closure_compiler/README.chromium b/third_party/closure_compiler/README.chromium
index 8b2d6c5..d0274ffc 100644
--- a/third_party/closure_compiler/README.chromium
+++ b/third_party/closure_compiler/README.chromium
@@ -1,8 +1,8 @@
 Name: Closure compiler
 Short Name: closure-compiler
 URL: http://github.com/google/closure-compiler
-Version: v20150729-236-gad656a1
-Date: 2015/08/26 08:46
+Version: v20180725-137c24759
+Date: 2018/07/27 19:34
 Revision: 137c2475944651f45433965afa9f1cddf7d1966b
 License: Apache 2.0
 License File: LICENSE
diff --git a/third_party/closure_compiler/externs/settings_private.js b/third_party/closure_compiler/externs/settings_private.js
index a95a2ff1..fb13fc7 100644
--- a/third_party/closure_compiler/externs/settings_private.js
+++ b/third_party/closure_compiler/externs/settings_private.js
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -63,11 +63,11 @@
 chrome.settingsPrivate.PrefObject;
 
 /**
- * Sets a settings value.
+ * Sets a pref value.
  * @param {string} name The name of the pref.
  * @param {*} value The new value of the pref.
- * @param {string} pageId The user metrics identifier or null.
- * @param {function(boolean):void} callback The callback for whether the pref
+ * @param {string=} pageId An optional user metrics identifier.
+ * @param {function(boolean):void=} callback The callback for whether the pref
  *     was set or not.
  */
 chrome.settingsPrivate.setPref = function(name, value, pageId, callback) {};
diff --git a/third_party/closure_compiler/roll_closure_compiler b/third_party/closure_compiler/roll_closure_compiler
index d34e162..1341a36 100755
--- a/third_party/closure_compiler/roll_closure_compiler
+++ b/third_party/closure_compiler/roll_closure_compiler
@@ -38,7 +38,9 @@
 
 cd closure-compiler
 
-new_head=$(git rev-parse HEAD)
+new_head="$(git rev-parse HEAD)"
+new_version="$(git log HEAD -n1 --date=format:%Y%m%d --pretty=format:v%cd-%h)"
+new_date="$(date --utc '+%Y/%m/%d %H:%M')"
 
 if [[ "${new_head}" == "${old_head}" ]]; then
   echo "No closure-compiler changes since last roll. Nothing to do."
@@ -147,7 +149,7 @@
 echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
 echo
 
-sed -i "s/^Revision: ${old_head}$/Revision: ${new_head}/" "${README}"
+sed -i "s/^Revision: ${old_head}$/Revision: ${new_head}/; s,^Date: .*,Date: ${new_date},; s,^Version: .*,Version: ${new_version}," "${README}"
 
 echo "git commit -a -m 'Roll closure compiler"
 echo
diff --git a/tools/clang/scripts/package.py b/tools/clang/scripts/package.py
index 5abba31..ead68d3 100755
--- a/tools/clang/scripts/package.py
+++ b/tools/clang/scripts/package.py
@@ -275,6 +275,7 @@
   elif sys.platform == 'win32':
     want.extend(['lib/clang/*/lib/windows/clang_rt.asan*.dll',
                  'lib/clang/*/lib/windows/clang_rt.asan*.lib',
+                 'lib/clang/*/lib/windows/clang_rt.profile*.lib',
                  'lib/clang/*/lib/windows/clang_rt.ubsan*.lib',
                  ])
 
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 67806b3..32e2c2b 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -29,6 +29,11 @@
       'Mac': 'release_bot_mac_strip',
       'Win': 'release_bot_x86_minimal_symbols_enable_archive_compression',
       'Win x64': 'release_bot_minimal_symbols_enable_archive_compression',
+      'android-rel': 'android_without_codecs_release_bot_minimal_symbols',
+      'linux-rel': 'release_bot',
+      'mac-rel': 'release_bot_mac_strip',
+      'win32-rel': 'release_bot_x86_minimal_symbols_enable_archive_compression',
+      'win-rel': 'release_bot_minimal_symbols_enable_archive_compression',
     },
 
     'chromium.android': {
@@ -555,7 +560,7 @@
     },
 
     'tryserver.chromium.chromiumos': {
-      'chromeos-amd64-generic-rel': 'cros_chrome_sdk_dcheck_always_on',
+      'chromeos-amd64-generic-rel': 'cros_chrome_sdk',
       'chromeos-daisy-rel': 'cros_chrome_sdk',
       'linux-chromeos-rel': 'chromeos_with_codecs_release_trybot',
       'linux-chromeos-compile-dbg': 'chromeos_with_codecs_debug_bot',
@@ -1169,10 +1174,6 @@
       'cros_chrome_sdk',
     ],
 
-    'cros_chrome_sdk_dcheck_always_on': [
-      'cros_chrome_sdk', 'dcheck_always_on',
-    ],
-
     'cros_chrome_sdk_headless_ozone': [
       'cros_chrome_sdk', 'ozone_platform_headless',
     ],
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index a90de18..f0c392bc 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -25507,6 +25507,21 @@
   <int value="2" label="SubframeBlocked"/>
 </enum>
 
+<enum name="IOSGetCookiesForURLCallCookieStoreType">
+  <int value="0" label="WKHTTPSystemCookieStore"/>
+  <int value="1" label="NSHTTPSystemCookieStore"/>
+  <int value="2" label="CookieMonster"/>
+</enum>
+
+<enum name="IOSGetCookiesForURLCallResult">
+  <int value="0" label="Cookies found on WKHTTPSystemCookieStore"/>
+  <int value="1" label="No Cookies on WKHTTPSystemCookieStore"/>
+  <int value="2" label="Cookies found on NSHTTPSystemCookieStore"/>
+  <int value="3" label="No Cookies on NSHTTPSystemCookieStore"/>
+  <int value="4" label="Cookies found on CookieMonster"/>
+  <int value="5" label="No Cookies on CookieMonster"/>
+</enum>
+
 <enum name="IOSHandoffOrigin">
   <int value="0" label="Unknown Origin"/>
   <int value="1" label="Chrome on iOS"/>
@@ -40394,6 +40409,9 @@
 </enum>
 
 <enum name="QuotaOriginTypes">
+  <obsolete>
+    Removed from code July 2018.
+  </obsolete>
   <int value="0" label="Other"/>
   <int value="1" label="None"/>
   <int value="2" label="google.com durable"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 43401ed..93b9768 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -595,6 +595,15 @@
   </summary>
 </histogram>
 
+<histogram name="AnchorElementMetrics.Clicked.AreaRank" units="rank">
+  <owner>chelu@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    The rank of the clicked anchor element in terms of area. This histogram is
+    recorded when the anchor element is clicked.
+  </summary>
+</histogram>
+
 <histogram name="AnchorElementMetrics.Clicked.ClickIntervals" units="ms">
   <owner>chelu@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
@@ -655,6 +664,118 @@
   </summary>
 </histogram>
 
+<histogram name="AnchorElementMetrics.Clicked.NavigationScore" units="score">
+  <owner>chelu@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    The calculated navigation score of the target link (href) of an anchor
+    element. The score is retrieved from the site engagement service. This
+    histogram is recorded when the anchor element is clicked and the score has
+    already been calculated when the document is loaded.
+  </summary>
+</histogram>
+
+<histogram name="AnchorElementMetrics.Clicked.NavigationScoreRank" units="rank">
+  <owner>chelu@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    The rank of the navigation score of the target link (href) of an anchor
+    element. This histogram is recorded when the anchor element is clicked and
+    the score has already been calculated when the document is loaded.
+  </summary>
+</histogram>
+
+<histogram name="AnchorElementMetrics.Clicked.RatioContainsImage_ContainsImage"
+    units="%">
+  <owner>chelu@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    The ratio times 100 between the number of anchor elements that contains
+    images and the total number of anchor elements. This histogram is recorded
+    when the anchor element is clicked and it contains images.
+  </summary>
+</histogram>
+
+<histogram name="AnchorElementMetrics.Clicked.RatioContainsImage_NoImage"
+    units="%">
+  <owner>chelu@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    The ratio times 100 between the number of anchor elements that contains
+    images and the total number of anchor elements. This histogram is recorded
+    when the anchor element is clicked and it does not contain images.
+  </summary>
+</histogram>
+
+<histogram name="AnchorElementMetrics.Clicked.RatioInIframe_InIframe" units="%">
+  <owner>chelu@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    The ratio times 100 between the number of anchor elements that is inside an
+    iframe and the total number of anchor elements. This histogram is recorded
+    when the anchor element is clicked and it is inside an iframe.
+  </summary>
+</histogram>
+
+<histogram name="AnchorElementMetrics.Clicked.RatioInIframe_NotInIframe"
+    units="%">
+  <owner>chelu@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    The ratio times 100 between the number of anchor elements that is inside an
+    iframe and the total number of anchor elements. This histogram is recorded
+    when the anchor element is clicked and it is not inside an iframe.
+  </summary>
+</histogram>
+
+<histogram name="AnchorElementMetrics.Clicked.RatioSameHost_DiffHost" units="%">
+  <owner>chelu@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    The ratio times 100 between the number of anchor elements whose href have
+    the same host as the document and the total number of anchor elements. This
+    histogram is recorded when the anchor element is clicked and href of the
+    anchor element has a different host than the document.
+  </summary>
+</histogram>
+
+<histogram name="AnchorElementMetrics.Clicked.RatioSameHost_SameHost" units="%">
+  <owner>chelu@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    The ratio times 100 between the number of anchor elements whose href have
+    the same host as the document and the total number of anchor elements. This
+    histogram is recorded when the anchor element is clicked and href of the
+    anchor element has the same host as the document.
+  </summary>
+</histogram>
+
+<histogram
+    name="AnchorElementMetrics.Clicked.RatioUrlIncremented_NotIncremented"
+    units="%">
+  <owner>chelu@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    The ratio times 100 between the number of anchor elements whose href is
+    incremented by one from the url of the document and the total number of
+    anchor elements. This histogram is recorded when the anchor element is
+    clicked and its href is not incremented by one from the url of the document.
+  </summary>
+</histogram>
+
+<histogram
+    name="AnchorElementMetrics.Clicked.RatioUrlIncremented_UrlIncremented"
+    units="%">
+  <owner>chelu@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    The ratio times 100 between the number of anchor elements whose href is
+    incremented by one from the url of the document and the total number of
+    anchor elements. This histogram is recorded when the anchor element is
+    clicked and its href is incremented by one from the url of the document.
+  </summary>
+</histogram>
+
 <histogram name="AnchorElementMetrics.ContainsImage" enum="Boolean">
   <owner>chelu@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
@@ -663,6 +784,15 @@
   </summary>
 </histogram>
 
+<histogram name="AnchorElementMetrics.DocumentEngagementScore" units="score">
+  <owner>chelu@chromium.org</owner>
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    The site engagement score of the document URL. The score is retrieved from
+    the site engagement service.
+  </summary>
+</histogram>
+
 <histogram name="AnchorElementMetrics.IsInIFrame" enum="Boolean">
   <owner>chelu@chromium.org</owner>
   <owner>tbansal@chromium.org</owner>
@@ -770,6 +900,16 @@
   </summary>
 </histogram>
 
+<histogram name="AnchorElementMetrics.Visible.NumberOfAnchorElementsAfterMerge"
+    units="count">
+  <owner>chelu@chromium.org</owner>
+  <summary>
+    The number of anchor element metrics sent to the browser process on a page
+    load. Anchor elements having the same href are merged and counted as 1. This
+    histogram is recorded when the webpage is loaded.
+  </summary>
+</histogram>
+
 <histogram name="Android.Activity.ChromeTabbedActivity.StopReason"
     enum="AndroidActivityStopReason">
   <owner>dfalcantara@chromium.org</owner>
@@ -37005,6 +37145,31 @@
   </summary>
 </histogram>
 
+<histogram name="IOS.Cookies.GetCookiesForURLCallResult"
+    enum="IOSGetCookiesForURLCallResult">
+  <owner>mrefaat@chromium.org</owner>
+  <summary>
+    Recorded to indicate whether the GetCookiesForURL call found cookies or not
+    when called on a specific system cookie store implementation. Most of the
+    cookies fetching on iOS Chromium is done by the WKWebView and doesn't
+    involve calling GetCookiesForURL. The method is only called when a request
+    is made by the UrlRequestFetcher for cases that are not handled by WKWebView
+    (eg. Downloads, Auto Suggestions and NTP tiles).
+  </summary>
+</histogram>
+
+<histogram name="IOS.Cookies.GetCookiesForURLCallStoreType"
+    enum="IOSGetCookiesForURLCallCookieStoreType">
+  <owner>mrefaat@chromium.org</owner>
+  <summary>
+    The system cookie store type used when GetCookiesForURL method is called.
+    Most of the cookies fetching on iOS Chromium is done by the WKWebView and
+    doesn't involve calling GetCookiesForURL. The method is only called when a
+    request is made by the UrlRequestFetcher for cases that are not handled by
+    WKWebView (eg. Downloads, Auto Suggestions and NTP tiles).
+  </summary>
+</histogram>
+
 <histogram name="IOS.DragAndDrop.DragContent" enum="DragContent">
   <owner>jif@chromium.org</owner>
   <summary>
@@ -79312,6 +79477,9 @@
 </histogram>
 
 <histogram name="Quota.LRUOriginTypes" enum="QuotaOriginTypes">
+  <obsolete>
+    Removed July 2018
+  </obsolete>
   <owner>dgrogan@chromium.org</owner>
   <summary>
     Types of origins that are initially selected for eviction via LRU. Some of
@@ -115760,6 +115928,7 @@
   <suffix name="Clicked" label="Clicked by the user, on click"/>
   <suffix name="Visible" label="Intersects with the viewport, on page load"/>
   <affected-histogram name="AnchorElementMetrics.ContainsImage"/>
+  <affected-histogram name="AnchorElementMetrics.DocumentEngagementScore"/>
   <affected-histogram name="AnchorElementMetrics.IsInIFrame"/>
   <affected-histogram name="AnchorElementMetrics.IsSameHost"/>
   <affected-histogram name="AnchorElementMetrics.IsUrlIncrementedByOne"/>
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index f9e13b9..91894b2 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -154,7 +154,6 @@
 crbug.com/829499 [ Android_One ] rendering.mobile/css_animations_many_keyframes [ Skip ]
 crbug.com/829499 [ Android_One ] rendering.mobile/web_animations_many_keyframes [ Skip ]
 crbug.com/840964 [ Nexus_5X ] rendering.mobile/web_animations_many_keyframes [ Skip ]
-crbug.com/750833 [ Android_Webview ] rendering.mobile/flickr_scroll [ Skip ]
 crbug.com/653993 [ Android_Webview ] rendering.mobile/maps_perf_test [ Skip ]
 [ All ] rendering.mobile/core_scroll_header_panel [ Skip ] # Polymer test, needs to be modernized.
 [ All ] rendering.mobile/paper_button [ Skip ] # Polymer test, needs to be modernized.
diff --git a/tools/perf/page_sets/data/rendering_desktop.json b/tools/perf/page_sets/data/rendering_desktop.json
index ae6bfc4..485e842 100644
--- a/tools/perf/page_sets/data/rendering_desktop.json
+++ b/tools/perf/page_sets/data/rendering_desktop.json
@@ -207,25 +207,91 @@
         "many_planets_deep": {
             "DEFAULT": "tough_webgl_cases_006.wprgo"
         },
-	"blogspot_pinch": {
+        "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"
         },
-        "weather_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
+        "twitter_pinch_2018": {
+            "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "booking_pinch": {
+        "weather_pinch": {
             "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
         },
         "yahoo_games_pinch": {
@@ -234,32 +300,20 @@
         "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"
         },
-        "amazon_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
-        "cnn_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
-        "ebay_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"
         },
-        "gmail_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
-        "google_search_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
-        "google_calendar_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
-        "google_image_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
+        "youtube_pinch_2018": {
+            "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
         "cats_unscaled": {
             "DEFAULT": "tough_image_decode_cases_000.wprgo"
@@ -267,7 +321,7 @@
         "cats_viewport_width": {
             "DEFAULT": "tough_image_decode_cases_000.wprgo"
         },
-	"js_full_screen_invalidation": {
+        "js_full_screen_invalidation": {
             "DEFAULT": "tough_compositor_cases_001.wprgo"
         },
         "new_tilings": {
diff --git a/tools/perf/page_sets/data/rendering_mobile.json b/tools/perf/page_sets/data/rendering_mobile.json
index 73ae6ad1..52ba1e3 100644
--- a/tools/perf/page_sets/data/rendering_mobile.json
+++ b/tools/perf/page_sets/data/rendering_mobile.json
@@ -491,35 +491,23 @@
         },
         "smash_cat": {
             "DEFAULT": "tough_canvas_cases_001.wprgo"
-	},
-	"microsoft_performance": {
-            "DEFAULT": "tough_animation_cases_000.wprgo"
         },
-        "ebay_scroll": {
-            "DEFAULT": "simple_mobile_sites_002.wprgo"
+        "microsoft_performance": {
+            "DEFAULT": "tough_animation_cases_000.wprgo"
         },
         "ebay_scroll_2018": {
             "DEFAULT": "simple_mobile_sites_003.wprgo"
         },
-        "flickr_scroll": {
-            "DEFAULT": "simple_mobile_sites_002.wprgo"
-        },
         "flickr_scroll_2018": {
             "DEFAULT": "simple_mobile_sites_003.wprgo"
         },
-        "nyc_gov_scroll": {
-            "DEFAULT": "simple_mobile_sites_002.wprgo"
-        },
         "nyc_gov_scroll_2018": {
             "DEFAULT": "simple_mobile_sites_003.wprgo"
         },
-        "nytimes_scroll": {
-            "DEFAULT": "simple_mobile_sites_002.wprgo"
-        },
         "nytimes_scroll_2018": {
             "DEFAULT": "simple_mobile_sites_003.wprgo"
         },
-	"aquarium_20k": {
+        "aquarium_20k": {
             "DEFAULT": "tough_webgl_cases_006.wprgo"
         },
         "animometer_webgl": {
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 671e8e4..e326ad1 100644
--- a/tools/perf/page_sets/data/tough_pinch_zoom_cases.json
+++ b/tools/perf/page_sets/data/tough_pinch_zoom_cases.json
@@ -1,24 +1,90 @@
 {
     "archives": {
+        "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"
         },
-        "weather_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
+        "twitter_pinch_2018": {
+            "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         },
-        "booking_pinch": {
+        "weather_pinch": {
             "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
         },
         "yahoo_games_pinch": {
@@ -27,32 +93,20 @@
         "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"
         },
-        "amazon_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
-        "cnn_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
-        "ebay_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"
         },
-        "gmail_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
-        "google_search_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
-        "google_calendar_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
-        },
-        "google_image_pinch": {
-            "DEFAULT": "tough_pinch_zoom_cases_000.wprgo"
+        "youtube_pinch_2018": {
+            "DEFAULT": "tough_pinch_zoom_cases_001.wprgo"
         }
     },
     "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.",
diff --git a/tools/perf/page_sets/data/tough_pinch_zoom_cases_001.wprgo.sha1 b/tools/perf/page_sets/data/tough_pinch_zoom_cases_001.wprgo.sha1
new file mode 100644
index 0000000..f523acf
--- /dev/null
+++ b/tools/perf/page_sets/data/tough_pinch_zoom_cases_001.wprgo.sha1
@@ -0,0 +1 @@
+f343b7d0516f9fa2890a445be57842e12177dd69
\ No newline at end of file
diff --git a/tools/perf/page_sets/rendering/simple_mobile_sites.py b/tools/perf/page_sets/rendering/simple_mobile_sites.py
index 89091ca5..74b78a5 100644
--- a/tools/perf/page_sets/rendering/simple_mobile_sites.py
+++ b/tools/perf/page_sets/rendering/simple_mobile_sites.py
@@ -36,44 +36,24 @@
       action_runner.ScrollPage(direction='down', speed_in_pixels_per_second=300)
 
 
-class SimpleEbayPage(SimplePage):
-  BASE_NAME = 'ebay_scroll'
-  URL = 'http://www.ebay.co.uk/'
-
-
 class SimpleEbay2018Page(SimplePage):
   BASE_NAME = 'ebay_scroll'
   YEAR = '2018'
   URL = 'http://www.ebay.co.uk/'
 
 
-class SimpleFlickrPage(SimplePage):
-  BASE_NAME = 'flickr_scroll'
-  URL = 'https://www.flickr.com/'
-
-
 class SimpleFlickr2018Page(SimplePage):
   BASE_NAME = 'flickr_scroll'
   YEAR = '2018'
   URL = 'https://www.flickr.com/photos/flickr/albums/72157639858715274'
 
 
-class SimpleNYCGovPage(SimplePage):
-  BASE_NAME = 'nyc_gov_scroll'
-  URL = 'http://www.nyc.gov'
-
-
 class SimpleNYCGov2018Page(SimplePage):
   BASE_NAME = 'nyc_gov_scroll'
   YEAR = '2018'
   URL = 'http://www.nyc.gov'
 
 
-class SimpleNYTimesPage(SimplePage):
-  BASE_NAME = 'nytimes_scroll'
-  URL = 'http://m.nytimes.com/'
-
-
 class SimpleNYTimes2018Page(SimplePage):
   BASE_NAME = 'nytimes_scroll'
   YEAR = '2018'
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 3d53ac0..8dda6230 100644
--- a/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py
+++ b/tools/perf/page_sets/rendering/tough_pinch_zoom_cases.py
@@ -7,6 +7,8 @@
 from page_sets.rendering import rendering_story
 from page_sets.rendering import story_tags
 from page_sets.system_health import platforms
+from page_sets.login_helpers import linkedin_login
+from page_sets.login_helpers import google_login
 
 
 class ToughPinchZoomPage(rendering_story.RenderingStory):
@@ -61,6 +63,19 @@
     action_runner.WaitForElement(text='Next')
 
 
+class GoogleSearchPinchZoom2018Page(ToughPinchZoomPage):
+
+  """ Why: top google property; a google tab is often open. """
+
+  BASE_NAME = 'google_search_pinch'
+  YEAR = '2018'
+  URL = 'https://www.google.com/#hl=en&q=barack+obama'
+
+  def RunNavigateSteps(self, action_runner):
+    super(GoogleSearchPinchZoom2018Page, self).RunNavigateSteps(action_runner)
+    action_runner.WaitForElement(text='Next')
+
+
 class GmailPinchZoomPage(ToughPinchZoomPage):
 
   """ Why: productivity, top google properties """
@@ -75,6 +90,22 @@
         'document.getElementById("gb") !== null')
 
 
+class GmailPinchZoom2018Page(ToughPinchZoomPage):
+
+  """ Why: productivity, top google properties """
+
+  BASE_NAME = 'gmail_pinch'
+  YEAR = '2018'
+  URL = 'https://mail.google.com/mail/'
+
+  def RunNavigateSteps(self, action_runner):
+    google_login.NewLoginGoogleAccount(action_runner, 'googletest')
+    super(GmailPinchZoom2018Page, self).RunNavigateSteps(action_runner)
+    action_runner.WaitForJavaScriptCondition(
+        'window.gmonkey !== undefined &&'
+        'document.getElementById("gb") !== null')
+
+
 class GoogleCalendarPinchZoomPage(ToughPinchZoomPage):
 
   """ Why: productivity, top google properties """
@@ -87,6 +118,21 @@
     action_runner.Wait(2)
 
 
+class GoogleCalendarPinchZoom2018Page(ToughPinchZoomPage):
+
+  """ Why: productivity, top google properties """
+
+  BASE_NAME = 'google_calendar_pinch'
+  YEAR = '2018'
+  URL = 'https://www.google.com/calendar/'
+
+  def RunNavigateSteps(self, action_runner):
+    google_login.NewLoginGoogleAccount(action_runner, 'googletest')
+    super(GoogleCalendarPinchZoom2018Page, self).RunNavigateSteps(
+      action_runner)
+    action_runner.WaitForElement('span[class~="sm8sCf"]')
+
+
 class GoogleImagePinchZoomPage(ToughPinchZoomPage):
 
   """ Why: tough image case; top google properties """
@@ -95,6 +141,15 @@
   URL = 'https://www.google.com/search?q=cats&tbm=isch'
 
 
+class GoogleImagePinchZoom2018Page(ToughPinchZoomPage):
+
+  """ Why: tough image case; top google properties """
+
+  BASE_NAME = 'google_image_pinch'
+  YEAR = '2018'
+  URL = 'https://www.google.com/search?q=cats&tbm=isch'
+
+
 class YoutubePinchZoomPage(ToughPinchZoomPage):
 
   """ Why: #3 (Alexa global) """
@@ -107,6 +162,19 @@
     action_runner.Wait(2)
 
 
+class YoutubePinchZoom2018Page(ToughPinchZoomPage):
+
+  """ Why: #3 (Alexa global) """
+
+  BASE_NAME = 'youtube_pinch'
+  YEAR = '2018'
+  URL = 'http://www.youtube.com'
+
+  def RunNavigateSteps(self, action_runner):
+    super(YoutubePinchZoom2018Page, self).RunNavigateSteps(action_runner)
+    action_runner.WaitForElement(selector='#buttons')
+
+
 class BlogSpotPinchZoomPage(ToughPinchZoomPage):
 
   """
@@ -122,6 +190,22 @@
     action_runner.WaitForElement(text='accessibility')
 
 
+class BlogSpotPinchZoom2018Page(ToughPinchZoomPage):
+
+  """
+  Why: #11 (Alexa global), google property; some blogger layouts have infinite
+  scroll but more interesting
+  """
+
+  BASE_NAME = 'blogspot_pinch'
+  YEAR = '2018'
+  URL = 'http://googlewebmastercentral.blogspot.com/'
+
+  def RunNavigateSteps(self, action_runner):
+    super(BlogSpotPinchZoom2018Page, self).RunNavigateSteps(action_runner)
+    action_runner.WaitForElement('div[class="searchBox"]')
+
+
 class FacebookPinchZoomPage(ToughPinchZoomPage):
 
   """ Why: top social,Public profile """
@@ -134,6 +218,19 @@
     action_runner.WaitForElement(text='About')
 
 
+class FacebookPinchZoom2018Page(ToughPinchZoomPage):
+
+  """ Why: top social,Public profile """
+
+  BASE_NAME = 'facebook_pinch'
+  YEAR = '2018'
+  URL = 'http://www.facebook.com/barackobama'
+
+  def RunNavigateSteps(self, action_runner):
+    super(FacebookPinchZoom2018Page, self).RunNavigateSteps(action_runner)
+    action_runner.WaitForElement(text='Videos')
+
+
 class LinkedinPinchZoomPage(ToughPinchZoomPage):
 
   """ Why: #12 (Alexa global),Public profile """
@@ -142,6 +239,19 @@
   URL = 'http://www.linkedin.com/in/linustorvalds'
 
 
+class LinkedinPinchZoom2018Page(ToughPinchZoomPage):
+
+  """ Why: #12 (Alexa global),Public profile """
+
+  BASE_NAME = 'linkedin_pinch'
+  YEAR = '2018'
+  URL = 'http://www.linkedin.com/in/linustorvalds'
+
+  def RunNavigateSteps(self, action_runner):
+    linkedin_login.LoginDesktopAccount(action_runner, 'linkedin')
+    super(LinkedinPinchZoom2018Page, self).RunNavigateSteps(action_runner)
+
+
 class TwitterPinchZoomPage(ToughPinchZoomPage):
 
   """ Why: #8 (Alexa global),Picked an interesting page """
@@ -154,6 +264,19 @@
     action_runner.Wait(2)
 
 
+class TwitterPinchZoom2018Page(ToughPinchZoomPage):
+
+  """ Why: #8 (Alexa global),Picked an interesting page """
+
+  BASE_NAME = 'twitter_pinch'
+  YEAR = '2018'
+  URL = 'https://twitter.com/katyperry'
+
+  def RunNavigateSteps(self, action_runner):
+    super(TwitterPinchZoom2018Page, self).RunNavigateSteps(action_runner)
+    action_runner.WaitForElement(selector='.ProfileNav')
+
+
 class ESPNPinchZoomPage(ToughPinchZoomPage):
 
   """ Why: #1 sports """
@@ -162,6 +285,15 @@
   URL = 'http://espn.go.com/nba'
 
 
+class ESPNPinchZoom2018Page(ToughPinchZoomPage):
+
+  """ Why: #1 sports """
+
+  BASE_NAME = 'espn_pinch'
+  YEAR = '2018'
+  URL = 'http://espn.go.com/nba'
+
+
 class WeatherDotComPinchZoomPage(ToughPinchZoomPage):
 
   """ Why: #7 (Alexa news); #27 total time spent,Picked interesting page """
@@ -170,6 +302,13 @@
   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'
+  YEAR = '2018'
+  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) """
@@ -182,6 +321,13 @@
     action_runner.Wait(2)
 
 
+class TwitchPinchZoom2018Page(ToughPinchZoomPage):
+  """ Why: #1 games according to Alexa  """
+  BASE_NAME = 'twitch_pinch'
+  YEAR = '2018'
+  URL = 'https://www.twitch.tv'
+
+
 class YahooNewsPinchZoomPage(ToughPinchZoomPage):
 
   """ Why: #1 news worldwide (Alexa global) """
@@ -190,6 +336,15 @@
   URL = 'http://news.yahoo.com'
 
 
+class YahooNewsPinchZoom2018Page(ToughPinchZoomPage):
+
+  """ Why: #1 news worldwide (Alexa global) """
+
+  BASE_NAME = 'yahoo_news_pinch'
+  YEAR = '2018'
+  URL = 'http://news.yahoo.com'
+
+
 class CnnPinchZoomPage(ToughPinchZoomPage):
 
   """ Why: #2 news worldwide """
@@ -198,6 +353,15 @@
   URL = 'http://www.cnn.com'
 
 
+class CnnPinchZoom2018Page(ToughPinchZoomPage):
+
+  """ Why: #2 news worldwide """
+
+  BASE_NAME = 'cnn_pinch'
+  YEAR = '2018'
+  URL = 'http://www.cnn.com'
+
+
 class AmazonPinchZoomPage(ToughPinchZoomPage):
 
   """
@@ -209,6 +373,18 @@
   URL = 'http://www.amazon.com'
 
 
+class AmazonPinchZoom2018Page(ToughPinchZoomPage):
+
+  """
+  Why: #1 world commerce website by visits; #3 commerce in the US by
+  time spent
+  """
+
+  BASE_NAME = 'amazon_pinch'
+  YEAR = '2018'
+  URL = 'http://www.amazon.com'
+
+
 class EBayPinchZoomPage(ToughPinchZoomPage):
 
   """  Why: #1 commerce website by time spent by users in US"""
@@ -217,6 +393,15 @@
   URL = 'http://www.ebay.com'
 
 
+class EBayPinchZoom2018Page(ToughPinchZoomPage):
+
+  """  Why: #1 commerce website by time spent by users in US"""
+
+  BASE_NAME = 'ebay_pinch'
+  YEAR = '2018'
+  URL = 'http://www.ebay.com'
+
+
 class BookingPinchZoomPage(ToughPinchZoomPage):
 
   """ Why: #1 Alexa recreation"""
@@ -225,6 +410,15 @@
   URL = 'http://booking.com'
 
 
+class BookingPinchZoom2018Page(ToughPinchZoomPage):
+
+  """ Why: #1 Alexa recreation"""
+
+  BASE_NAME = 'booking_pinch'
+  YEAR = '2018'
+  URL = 'http://booking.com'
+
+
 class YahooSportsPinchZoomPage(ToughPinchZoomPage):
 
   """ Why: #1 Alexa sports"""
@@ -232,6 +426,14 @@
   URL = 'http://sports.yahoo.com/'
 
 
+class YahooSportsPinchZoom2018Page(ToughPinchZoomPage):
+
+  """ Why: #1 Alexa sports"""
+  BASE_NAME = 'yahoo_sports_pinch'
+  YEAR = '2018'
+  URL = 'http://sports.yahoo.com/'
+
+
 # TODO(crbug.com/760553):remove this class after
 # smoothness.tough_pinch_zoom_cases benchmark is completely
 # replaced by rendering benchmarks
@@ -283,6 +485,43 @@
     self.AddStory(BookingPinchZoomPage(
         page_set=self))
 
+    self.AddStory(GoogleSearchPinchZoom2018Page(
+        page_set=self))
+    self.AddStory(GmailPinchZoom2018Page(
+        page_set=self))
+    self.AddStory(GoogleCalendarPinchZoom2018Page(
+        page_set=self))
+    self.AddStory(GoogleImagePinchZoom2018Page(
+        page_set=self))
+    self.AddStory(YoutubePinchZoom2018Page(
+        page_set=self))
+    self.AddStory(BlogSpotPinchZoom2018Page(
+        page_set=self))
+    self.AddStory(FacebookPinchZoom2018Page(
+        page_set=self))
+    self.AddStory(LinkedinPinchZoom2018Page(
+        page_set=self))
+    self.AddStory(TwitterPinchZoom2018Page(
+        page_set=self))
+    self.AddStory(ESPNPinchZoom2018Page(
+        page_set=self))
+    self.AddStory(TwitchPinchZoom2018Page(
+        page_set=self))
+    self.AddStory(YahooNewsPinchZoom2018Page(
+        page_set=self))
+    self.AddStory(CnnPinchZoom2018Page(
+        page_set=self))
+    self.AddStory(AmazonPinchZoom2018Page(
+        page_set=self))
+    self.AddStory(EBayPinchZoom2018Page(
+        page_set=self))
+    self.AddStory(AccuWeatherPinchZoom2018Page(
+        page_set=self))
+    self.AddStory(YahooSportsPinchZoom2018Page(
+        page_set=self))
+    self.AddStory(BookingPinchZoom2018Page(
+        page_set=self))
+
 
 class AndroidToughPinchZoomCasesPageSet(ToughPinchZoomCasesPageSet):
 
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc
index 09f770c..f7b742e 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -1313,22 +1313,62 @@
 
 void AXPlatformNodeAuraLinux::GetAtkState(AtkStateSet* atk_state_set) {
   AXNodeData data = GetData();
+  if (data.HasState(ax::mojom::State::kCollapsed))
+    atk_state_set_add_state(atk_state_set, ATK_STATE_EXPANDABLE);
   if (data.HasState(ax::mojom::State::kDefault))
     atk_state_set_add_state(atk_state_set, ATK_STATE_DEFAULT);
   if (data.HasState(ax::mojom::State::kEditable))
     atk_state_set_add_state(atk_state_set, ATK_STATE_EDITABLE);
-  if (data.HasState(ax::mojom::State::kExpanded))
+  if (data.HasState(ax::mojom::State::kExpanded)) {
+    atk_state_set_add_state(atk_state_set, ATK_STATE_EXPANDABLE);
     atk_state_set_add_state(atk_state_set, ATK_STATE_EXPANDED);
+  }
   if (data.HasState(ax::mojom::State::kFocusable))
     atk_state_set_add_state(atk_state_set, ATK_STATE_FOCUSABLE);
+  if (data.HasState(ax::mojom::State::kHorizontal))
+    atk_state_set_add_state(atk_state_set, ATK_STATE_HORIZONTAL);
+  if (!data.HasState(ax::mojom::State::kInvisible)) {
+    atk_state_set_add_state(atk_state_set, ATK_STATE_VISIBLE);
+    if (!delegate_->IsOffscreen())
+      atk_state_set_add_state(atk_state_set, ATK_STATE_SHOWING);
+  }
+  if (data.HasState(ax::mojom::State::kMultiselectable))
+    atk_state_set_add_state(atk_state_set, ATK_STATE_MULTISELECTABLE);
+  if (data.HasState(ax::mojom::State::kRequired))
+    atk_state_set_add_state(atk_state_set, ATK_STATE_REQUIRED);
+  if (data.HasState(ax::mojom::State::kVertical))
+    atk_state_set_add_state(atk_state_set, ATK_STATE_VERTICAL);
+  if (data.HasState(ax::mojom::State::kVisited))
+    atk_state_set_add_state(atk_state_set, ATK_STATE_VISITED);
+  if (data.HasIntAttribute(ax::mojom::IntAttribute::kInvalidState) &&
+      data.GetIntAttribute(ax::mojom::IntAttribute::kInvalidState) !=
+          static_cast<int32_t>(ax::mojom::InvalidState::kFalse))
+    atk_state_set_add_state(atk_state_set, ATK_STATE_INVALID_ENTRY);
 #if defined(ATK_216)
+  if (data.HasIntAttribute(ax::mojom::IntAttribute::kCheckedState))
+    atk_state_set_add_state(atk_state_set, ATK_STATE_CHECKABLE);
   if (data.HasIntAttribute(ax::mojom::IntAttribute::kHasPopup))
     atk_state_set_add_state(atk_state_set, ATK_STATE_HAS_POPUP);
 #endif
-  if (data.GetBoolAttribute(ax::mojom::BoolAttribute::kSelected))
-    atk_state_set_add_state(atk_state_set, ATK_STATE_SELECTED);
-  if (data.HasBoolAttribute(ax::mojom::BoolAttribute::kSelected))
+  if (data.GetBoolAttribute(ax::mojom::BoolAttribute::kBusy))
+    atk_state_set_add_state(atk_state_set, ATK_STATE_BUSY);
+  if (data.GetBoolAttribute(ax::mojom::BoolAttribute::kModal))
+    atk_state_set_add_state(atk_state_set, ATK_STATE_MODAL);
+  if (data.GetBoolAttribute(ax::mojom::BoolAttribute::kSelected)) {
     atk_state_set_add_state(atk_state_set, ATK_STATE_SELECTABLE);
+    atk_state_set_add_state(atk_state_set, ATK_STATE_SELECTED);
+  }
+  if (IsPlainTextField() || IsRichTextField()) {
+    atk_state_set_add_state(atk_state_set, ATK_STATE_SELECTABLE_TEXT);
+    if (data.HasState(ax::mojom::State::kMultiline))
+      atk_state_set_add_state(atk_state_set, ATK_STATE_MULTI_LINE);
+    else
+      atk_state_set_add_state(atk_state_set, ATK_STATE_SINGLE_LINE);
+  }
+
+  if (!GetStringAttribute(ax::mojom::StringAttribute::kAutoComplete).empty() ||
+      IsFocusedInputWithSuggestions())
+    atk_state_set_add_state(atk_state_set, ATK_STATE_SUPPORTS_AUTOCOMPLETION);
 
   // Checked state
   const auto checked_state = GetData().GetCheckedState();
@@ -1349,6 +1389,7 @@
   switch (GetData().GetRestriction()) {
     case ax::mojom::Restriction::kNone:
       atk_state_set_add_state(atk_state_set, ATK_STATE_ENABLED);
+      atk_state_set_add_state(atk_state_set, ATK_STATE_SENSITIVE);
       break;
     case ax::mojom::Restriction::kReadOnly:
 #if defined(ATK_216)
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
index 612e070d..3a94cf3 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
@@ -76,6 +76,9 @@
 //
 // AtkObject tests
 //
+#if defined(ATK_CHECK_VERSION) && ATK_CHECK_VERSION(2, 16, 0)
+#define ATK_216
+#endif
 
 TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectDetachedObject) {
   AXNodeData root;
@@ -201,9 +204,6 @@
 TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectState) {
   AXNodeData root;
   root.id = 1;
-  root.AddState(ax::mojom::State::kDefault);
-  root.AddState(ax::mojom::State::kExpanded);
-
   Init(root);
 
   AtkObject* root_obj(GetRootAtkObject());
@@ -212,9 +212,107 @@
 
   AtkStateSet* state_set = atk_object_ref_state_set(root_obj);
   ASSERT_TRUE(ATK_IS_STATE_SET(state_set));
-  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_DEFAULT));
-  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_EXPANDED));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_ENABLED));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_SENSITIVE));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_SHOWING));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_VISIBLE));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_BUSY));
+#if defined(ATK_216)
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_CHECKABLE));
+#endif
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_CHECKED));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_DEFAULT));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_EDITABLE));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_EXPANDABLE));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_EXPANDED));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_FOCUSABLE));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_FOCUSED));
+#if defined(ATK_216)
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_HAS_POPUP));
+#endif
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_HORIZONTAL));
+  ASSERT_FALSE(
+      atk_state_set_contains_state(state_set, ATK_STATE_INVALID_ENTRY));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_MODAL));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_MULTI_LINE));
+  ASSERT_FALSE(
+      atk_state_set_contains_state(state_set, ATK_STATE_MULTISELECTABLE));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_REQUIRED));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_SELECTABLE));
+  ASSERT_FALSE(
+      atk_state_set_contains_state(state_set, ATK_STATE_SELECTABLE_TEXT));
   ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_SELECTED));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_SINGLE_LINE));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set,
+                                            ATK_STATE_SUPPORTS_AUTOCOMPLETION));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_VERTICAL));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_VISITED));
+  g_object_unref(state_set);
+
+  root = AXNodeData();
+  root.AddState(ax::mojom::State::kDefault);
+  root.AddState(ax::mojom::State::kEditable);
+  root.AddState(ax::mojom::State::kExpanded);
+  root.AddState(ax::mojom::State::kFocusable);
+  root.AddState(ax::mojom::State::kMultiselectable);
+  root.AddState(ax::mojom::State::kRequired);
+  root.AddState(ax::mojom::State::kVertical);
+  root.AddBoolAttribute(ax::mojom::BoolAttribute::kBusy, true);
+  root.SetInvalidState(ax::mojom::InvalidState::kTrue);
+  root.AddStringAttribute(ax::mojom::StringAttribute::kAutoComplete, "foo");
+  GetRootNode()->SetData(root);
+
+  state_set = atk_object_ref_state_set(root_obj);
+  ASSERT_TRUE(ATK_IS_STATE_SET(state_set));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_BUSY));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_DEFAULT));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_EDITABLE));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_EXPANDABLE));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_EXPANDED));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_FOCUSABLE));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_INVALID_ENTRY));
+  ASSERT_TRUE(
+      atk_state_set_contains_state(state_set, ATK_STATE_MULTISELECTABLE));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_REQUIRED));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set,
+                                           ATK_STATE_SUPPORTS_AUTOCOMPLETION));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_VERTICAL));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_FOCUSED));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_HORIZONTAL));
+  g_object_unref(state_set);
+
+  root = AXNodeData();
+  root.AddState(ax::mojom::State::kCollapsed);
+  root.AddState(ax::mojom::State::kHorizontal);
+  root.AddState(ax::mojom::State::kVisited);
+  root.AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, true);
+  root.SetHasPopup(ax::mojom::HasPopup::kTrue);
+  GetRootNode()->SetData(root);
+
+  state_set = atk_object_ref_state_set(root_obj);
+  ASSERT_TRUE(ATK_IS_STATE_SET(state_set));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_EXPANDABLE));
+#if defined(ATK_216)
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_HAS_POPUP));
+#endif
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_HORIZONTAL));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_SELECTABLE));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_SELECTED));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_VISITED));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_EXPANDED));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_VERTICAL));
+  g_object_unref(state_set);
+
+  root = AXNodeData();
+  root.AddState(ax::mojom::State::kInvisible);
+  root.AddBoolAttribute(ax::mojom::BoolAttribute::kModal, true);
+  GetRootNode()->SetData(root);
+
+  state_set = atk_object_ref_state_set(root_obj);
+  ASSERT_TRUE(ATK_IS_STATE_SET(state_set));
+  ASSERT_TRUE(atk_state_set_contains_state(state_set, ATK_STATE_MODAL));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_SHOWING));
+  ASSERT_FALSE(atk_state_set_contains_state(state_set, ATK_STATE_VISIBLE));
   g_object_unref(state_set);
 
   g_object_unref(root_obj);
diff --git a/ui/chromeos/events/event_rewriter_chromeos.cc b/ui/chromeos/events/event_rewriter_chromeos.cc
index e2d287b2..05639df 100644
--- a/ui/chromeos/events/event_rewriter_chromeos.cc
+++ b/ui/chromeos/events/event_rewriter_chromeos.cc
@@ -110,8 +110,9 @@
 const ModifierRemapping* kModifierRemappingNeoMod3 = &kModifierRemappings[1];
 
 // Gets a remapped key for |pref_name| key. For example, to find out which
-// key Search is currently remapped to, call the function with
-// prefs::kLanguageRemapSearchKeyTo.
+// key Ctrl is currently remapped to, call the function with
+// prefs::kLanguageRemapControlKeyTo.
+// Note: For the Search key, call GetSearchRemappedKey().
 const ModifierRemapping* GetRemappedKey(
     const std::string& pref_name,
     EventRewriterChromeOS::Delegate* delegate) {
@@ -122,13 +123,40 @@
   if (!delegate->GetKeyboardRemappedPrefValue(pref_name, &value))
     return nullptr;
 
-  for (size_t i = 0; i < arraysize(kModifierRemappings); ++i) {
-    if (value == static_cast<int>(kModifierRemappings[i].remap_to))
-      return &kModifierRemappings[i];
+  for (auto& remapping : kModifierRemappings) {
+    if (value == static_cast<int>(remapping.remap_to))
+      return &remapping;
   }
+
   return nullptr;
 }
 
+// Gets a remapped key for the Search key based on the |keyboard_type| of the
+// last event. Internal Search key, Command key on external Apple keyboards, and
+// Meta key (either Search or Windows) on external non-Apple keyboards can all
+// be remapped separately.
+const ModifierRemapping* GetSearchRemappedKey(
+    EventRewriterChromeOS::Delegate* delegate,
+    EventRewriterChromeOS::DeviceType keyboard_type) {
+  std::string pref_name;
+  switch (keyboard_type) {
+    case EventRewriterChromeOS::kDeviceAppleKeyboard:
+      pref_name = prefs::kLanguageRemapExternalCommandKeyTo;
+      break;
+
+    case EventRewriterChromeOS::kDeviceExternalNonAppleKeyboard:
+      pref_name = prefs::kLanguageRemapExternalMetaKeyTo;
+      break;
+
+    default:
+      // Use the preference for internal Search key remapping.
+      pref_name = prefs::kLanguageRemapSearchKeyTo;
+      break;
+  }
+
+  return GetRemappedKey(pref_name, delegate);
+}
+
 bool HasDiamondKey() {
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
       ::chromeos::switches::kHasChromeOSDiamondKey);
@@ -144,36 +172,6 @@
   return manager->IsISOLevel5ShiftUsedByCurrentInputMethod();
 }
 
-EventRewriterChromeOS::DeviceType GetDeviceType(const std::string& device_name,
-                                                int vendor_id,
-                                                int product_id) {
-  if (vendor_id == kHotrodRemoteVendorId &&
-      product_id == kHotrodRemoteProductId) {
-    return EventRewriterChromeOS::kDeviceHotrodRemote;
-  }
-
-  if (base::LowerCaseEqualsASCII(device_name, "virtual core keyboard"))
-    return EventRewriterChromeOS::kDeviceVirtualCoreKeyboard;
-
-  std::vector<std::string> tokens = base::SplitString(
-      device_name, " .", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-
-  // If the |device_name| contains the two words, "apple" and "keyboard", treat
-  // it as an Apple keyboard.
-  bool found_apple = false;
-  bool found_keyboard = false;
-  for (size_t i = 0; i < tokens.size(); ++i) {
-    if (!found_apple && base::LowerCaseEqualsASCII(tokens[i], "apple"))
-      found_apple = true;
-    if (!found_keyboard && base::LowerCaseEqualsASCII(tokens[i], "keyboard"))
-      found_keyboard = true;
-    if (found_apple && found_keyboard)
-      return EventRewriterChromeOS::kDeviceAppleKeyboard;
-  }
-
-  return EventRewriterChromeOS::kDeviceUnknown;
-}
-
 struct KeyboardRemapping {
   // MatchKeyboardRemapping() succeeds if the tested has all of the specified
   // flags (and possibly other flags), and either the key_code matches or the
@@ -273,15 +271,56 @@
 
 EventRewriterChromeOS::~EventRewriterChromeOS() {}
 
+// static
+EventRewriterChromeOS::DeviceType EventRewriterChromeOS::GetDeviceType(
+    const ui::InputDevice& keyboard_device) {
+  if (keyboard_device.vendor_id == kHotrodRemoteVendorId &&
+      keyboard_device.product_id == kHotrodRemoteProductId) {
+    return EventRewriterChromeOS::kDeviceHotrodRemote;
+  }
+
+  if (base::LowerCaseEqualsASCII(keyboard_device.name,
+                                 "virtual core keyboard")) {
+    return EventRewriterChromeOS::kDeviceVirtualCoreKeyboard;
+  }
+
+  const std::vector<std::string> tokens =
+      base::SplitString(keyboard_device.name, " .", base::KEEP_WHITESPACE,
+                        base::SPLIT_WANT_NONEMPTY);
+
+  // If the |device_name| contains the two words, "apple" and "keyboard", treat
+  // it as an Apple keyboard.
+  bool found_apple = false;
+  bool found_keyboard = false;
+  for (size_t i = 0; i < tokens.size(); ++i) {
+    if (!found_apple && base::LowerCaseEqualsASCII(tokens[i], "apple"))
+      found_apple = true;
+    if (!found_keyboard && base::LowerCaseEqualsASCII(tokens[i], "keyboard"))
+      found_keyboard = true;
+    if (found_apple && found_keyboard)
+      return EventRewriterChromeOS::kDeviceAppleKeyboard;
+  }
+
+  if (!found_apple && found_keyboard &&
+      keyboard_device.type == INPUT_DEVICE_EXTERNAL) {
+    return EventRewriterChromeOS::kDeviceExternalNonAppleKeyboard;
+  }
+
+  return EventRewriterChromeOS::kDeviceUnknown;
+}
+
 void EventRewriterChromeOS::KeyboardDeviceAddedForTesting(
     int device_id,
     const std::string& device_name,
-    KeyboardTopRowLayout layout) {
+    KeyboardTopRowLayout layout,
+    InputDeviceType device_type) {
   // Tests must avoid XI2 reserved device IDs.
   DCHECK((device_id < 0) || (device_id > 1));
-  KeyboardDeviceAddedInternal(
-      device_id,
-      GetDeviceType(device_name, kUnknownVendorId, kUnknownProductId), layout);
+  InputDevice keyboard_device(device_id, device_type, device_name);
+  keyboard_device.vendor_id = kUnknownVendorId;
+  keyboard_device.product_id = kUnknownProductId;
+  KeyboardDeviceAddedInternal(device_id, GetDeviceType(keyboard_device),
+                              layout);
 }
 
 void EventRewriterChromeOS::RewriteMouseButtonEventForTesting(
@@ -398,27 +437,26 @@
   last_keyboard_device_id_ = device_id;
 }
 
-bool EventRewriterChromeOS::IsAppleKeyboard() const {
-  return IsLastKeyboardOfType(kDeviceAppleKeyboard);
-}
-
 bool EventRewriterChromeOS::IsHotrodRemote() const {
   return IsLastKeyboardOfType(kDeviceHotrodRemote);
 }
 
 bool EventRewriterChromeOS::IsLastKeyboardOfType(DeviceType device_type) const {
-  if (last_keyboard_device_id_ == ui::ED_UNKNOWN_DEVICE)
-    return false;
+  return GetLastKeyboardType() == device_type;
+}
 
-  // Check which device generated |event|.
+EventRewriterChromeOS::DeviceType EventRewriterChromeOS::GetLastKeyboardType()
+    const {
+  if (last_keyboard_device_id_ == ui::ED_UNKNOWN_DEVICE)
+    return kDeviceUnknown;
+
   const auto iter = device_id_to_info_.find(last_keyboard_device_id_);
   if (iter == device_id_to_info_.end()) {
     LOG(ERROR) << "Device ID " << last_keyboard_device_id_ << " is unknown.";
-    return false;
+    return kDeviceUnknown;
   }
 
-  const DeviceType type = iter->second.type;
-  return type == device_type;
+  return iter->second.type;
 }
 
 int EventRewriterChromeOS::GetRemappedModifierMasks(const ui::Event& event,
@@ -432,11 +470,7 @@
       continue;
     switch (kModifierRemappings[i].flag) {
       case ui::EF_COMMAND_DOWN:
-        // Rewrite Command key presses on an Apple keyboard to Control.
-        if (IsAppleKeyboard()) {
-          DCHECK_EQ(ui::EF_CONTROL_DOWN, kModifierRemappingCtrl->flag);
-          remapped_key = kModifierRemappingCtrl;
-        }
+        remapped_key = GetSearchRemappedKey(delegate_, GetLastKeyboardType());
         break;
       case ui::EF_MOD3_DOWN:
         // If EF_MOD3_DOWN is used by the current input method, leave it alone;
@@ -684,8 +718,7 @@
               GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo, delegate_);
         } else {
           characteristic_flag = ui::EF_ALTGR_DOWN;
-          remapped_key =
-              GetRemappedKey(prefs::kLanguageRemapSearchKeyTo, delegate_);
+          remapped_key = GetSearchRemappedKey(delegate_, GetLastKeyboardType());
         }
       }
       if (remapped_key && remapped_key->result.key_code == ui::VKEY_CAPITAL)
@@ -734,14 +767,7 @@
     case ui::DomCode::META_LEFT:
     case ui::DomCode::META_RIGHT:
       characteristic_flag = ui::EF_COMMAND_DOWN;
-      // Rewrite Command-L/R key presses on an Apple keyboard to Control.
-      if (IsAppleKeyboard()) {
-        DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->result.key_code);
-        remapped_key = kModifierRemappingCtrl;
-      } else {
-        remapped_key =
-            GetRemappedKey(prefs::kLanguageRemapSearchKeyTo, delegate_);
-      }
+      remapped_key = GetSearchRemappedKey(delegate_, GetLastKeyboardType());
       // Default behavior is Super key, hence don't remap the event if the pref
       // is unavailable.
       break;
@@ -1173,8 +1199,7 @@
       ui::InputDeviceManager::GetInstance()->GetKeyboardDevices();
   for (const auto& keyboard : keyboard_devices) {
     if (keyboard.id == device_id) {
-      const DeviceType type =
-          GetDeviceType(keyboard.name, keyboard.vendor_id, keyboard.product_id);
+      const DeviceType type = GetDeviceType(keyboard);
       if (type == kDeviceAppleKeyboard) {
         VLOG(1) << "Apple keyboard '" << keyboard.name << "' connected: "
                 << "id=" << device_id;
diff --git a/ui/chromeos/events/event_rewriter_chromeos.h b/ui/chromeos/events/event_rewriter_chromeos.h
index ee570e6..8d51f34 100644
--- a/ui/chromeos/events/event_rewriter_chromeos.h
+++ b/ui/chromeos/events/event_rewriter_chromeos.h
@@ -12,6 +12,7 @@
 
 #include "base/files/file_path.h"
 #include "base/macros.h"
+#include "ui/events/devices/input_device.h"
 #include "ui/events/event.h"
 #include "ui/events/event_rewriter.h"
 #include "ui/events/keycodes/dom/dom_key.h"
@@ -41,6 +42,7 @@
   enum DeviceType {
     kDeviceUnknown = 0,
     kDeviceAppleKeyboard,
+    kDeviceExternalNonAppleKeyboard,
     kDeviceHotrodRemote,
     kDeviceVirtualCoreKeyboard,  // X-server generated events.
   };
@@ -106,11 +108,14 @@
                         ui::EventRewriter* sticky_keys_controller);
   ~EventRewriterChromeOS() override;
 
+  static DeviceType GetDeviceType(const ui::InputDevice& keyboard_device);
+
   // Calls KeyboardDeviceAddedInternal.
   void KeyboardDeviceAddedForTesting(
       int device_id,
       const std::string& device_name,
-      KeyboardTopRowLayout layout = kKbdTopRowLayoutDefault);
+      KeyboardTopRowLayout layout = kKbdTopRowLayoutDefault,
+      InputDeviceType device_type = INPUT_DEVICE_UNKNOWN);
 
   // Calls RewriteMouseEvent().
   void RewriteMouseButtonEventForTesting(
@@ -164,12 +169,12 @@
                                    DeviceType type,
                                    KeyboardTopRowLayout layout);
 
-  // Returns true if |last_keyboard_device_id_| is Apple's.
-  bool IsAppleKeyboard() const;
   // Returns true if |last_keyboard_device_id_| is Hotrod remote.
   bool IsHotrodRemote() const;
   // Returns true if |last_keyboard_device_id_| is of given |device_type|.
   bool IsLastKeyboardOfType(DeviceType device_type) const;
+  // Returns the device type of |last_keyboard_device_id_|.
+  DeviceType GetLastKeyboardType() const;
 
   // Given modifier flags |original_flags|, returns the remapped modifiers
   // according to user preferences and/or event properties.
diff --git a/ui/chromeos/events/pref_names.cc b/ui/chromeos/events/pref_names.cc
index f3b5307..765c0eb 100644
--- a/ui/chromeos/events/pref_names.cc
+++ b/ui/chromeos/events/pref_names.cc
@@ -27,5 +27,9 @@
     "settings.language.remap_backspace_key_to";
 const char kLanguageRemapDiamondKeyTo[] =
     "settings.language.remap_diamond_key_to";
+const char kLanguageRemapExternalCommandKeyTo[] =
+    "settings.language.remap_external_command_key_to";
+const char kLanguageRemapExternalMetaKeyTo[] =
+    "settings.language.remap_external_meta_key_to";
 
 }  // namespace prefs
diff --git a/ui/chromeos/events/pref_names.h b/ui/chromeos/events/pref_names.h
index d597176..f75aa2a 100644
--- a/ui/chromeos/events/pref_names.h
+++ b/ui/chromeos/events/pref_names.h
@@ -17,6 +17,8 @@
 extern const char kLanguageRemapEscapeKeyTo[];
 extern const char kLanguageRemapBackspaceKeyTo[];
 extern const char kLanguageRemapDiamondKeyTo[];
+extern const char kLanguageRemapExternalCommandKeyTo[];
+extern const char kLanguageRemapExternalMetaKeyTo[];
 
 }  // namespace prefs
 
diff --git a/ui/gl/gl_surface_presentation_helper.cc b/ui/gl/gl_surface_presentation_helper.cc
index 5a6ce42..064dca9f 100644
--- a/ui/gl/gl_surface_presentation_helper.cc
+++ b/ui/gl/gl_surface_presentation_helper.cc
@@ -5,6 +5,7 @@
 #include "ui/gl/gl_surface_presentation_helper.h"
 
 #include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
 #include "ui/gfx/vsync_provider.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_fence.h"
@@ -118,6 +119,12 @@
   gpu_timing_client_ = context->CreateGPUTimingClient();
   if (!gpu_timing_client_->IsAvailable())
     gpu_timing_client_ = nullptr;
+
+// https://crbug.com/854298 : disable GLFence on Android as they seem to cause
+// issues on some devices.
+#if !defined(OS_ANDROID)
+  gl_fence_supported_ = GLFence::IsSupported();
+#endif
 }
 
 void GLSurfacePresentationHelper::PreSwapBuffers(
@@ -127,7 +134,7 @@
     timer = gpu_timing_client_->CreateGPUTimer(false /* prefer_elapsed_time */);
     timer->QueryTimeStamp();
     pending_frames_.push_back(Frame(std::move(timer), callback));
-  } else if (GLFence::IsSupported()) {
+  } else if (gl_fence_supported_) {
     auto fence = GLFence::Create();
     pending_frames_.push_back(Frame(std::move(fence), callback));
   } else {
@@ -170,7 +177,7 @@
   bool need_update_vsync = false;
   bool disjoint_occurred =
       gpu_timing_client_ && gpu_timing_client_->CheckAndResetTimerErrors();
-  if (disjoint_occurred || (!gpu_timing_client_ && !GLFence::IsSupported())) {
+  if (disjoint_occurred || (!gpu_timing_client_ && !gl_fence_supported_)) {
     // If GPUTimer and GLFence are not avaliable or disjoint occurred, we will
     // compute the next VSync's timestamp and use it to run presentation
     // callback.
diff --git a/ui/gl/gl_surface_presentation_helper.h b/ui/gl/gl_surface_presentation_helper.h
index d4020f10..32c09b7 100644
--- a/ui/gl/gl_surface_presentation_helper.h
+++ b/ui/gl/gl_surface_presentation_helper.h
@@ -96,6 +96,7 @@
   base::TimeTicks vsync_timebase_;
   base::TimeDelta vsync_interval_;
   bool check_pending_frame_scheduled_ = false;
+  bool gl_fence_supported_ = false;
 
   base::WeakPtrFactory<GLSurfacePresentationHelper> weak_ptr_factory_;
 
diff --git a/ui/views/win/pen_event_processor.cc b/ui/views/win/pen_event_processor.cc
index b5e7093..b820c51 100644
--- a/ui/views/win/pen_event_processor.cc
+++ b/ui/views/win/pen_event_processor.cc
@@ -45,12 +45,12 @@
   // have to check if previously the pointer type is an eraser.
   if (pointer_pen_info.penFlags & PEN_FLAG_ERASER) {
     input_type = ui::EventPointerType::POINTER_TYPE_ERASER;
-    DCHECK(eraser_pointer_id_ == -1 || eraser_pointer_id_ == mapped_pointer_id);
+    DCHECK(!eraser_pointer_id_ || *eraser_pointer_id_ == mapped_pointer_id);
     eraser_pointer_id_ = mapped_pointer_id;
-  } else if (eraser_pointer_id_ == mapped_pointer_id &&
+  } else if (eraser_pointer_id_ && *eraser_pointer_id_ == mapped_pointer_id &&
              message == WM_POINTERUP) {
     input_type = ui::EventPointerType::POINTER_TYPE_ERASER;
-    eraser_pointer_id_ = -1;
+    eraser_pointer_id_.reset();
   }
 
   // convert pressure into a float [0, 1]. The range of the pressure is
diff --git a/ui/views/win/pen_event_processor.h b/ui/views/win/pen_event_processor.h
index 87d949c..ab10799c 100644
--- a/ui/views/win/pen_event_processor.h
+++ b/ui/views/win/pen_event_processor.h
@@ -9,6 +9,7 @@
 
 #include <memory>
 
+#include "base/optional.h"
 #include "ui/events/event.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/sequential_id_generator.h"
@@ -54,7 +55,7 @@
   bool send_touch_for_pen_ = false;
   bool sent_mouse_down_ = false;
   bool sent_touch_start_ = false;
-  int eraser_pointer_id_ = -1;
+  base::Optional<unsigned int> eraser_pointer_id_;
 
   DISALLOW_COPY_AND_ASSIGN(PenEventProcessor);
 };
diff --git a/webrunner/service/common.h b/webrunner/service/common.h
index 351fbf2..3e4eeb7 100644
--- a/webrunner/service/common.h
+++ b/webrunner/service/common.h
@@ -7,6 +7,8 @@
 
 #include <zircon/processargs.h>
 
+#include "webrunner/common/webrunner_export.h"
+
 namespace base {
 class FilePath;
 }
@@ -29,7 +31,7 @@
 // Returns data directory that should be used by this context process. Should
 // not be called in ContextProvider. Empty path is returned if the context
 // doesn't have storage dir.
-base::FilePath GetWebContextDataDir();
+WEBRUNNER_EXPORT base::FilePath GetWebContextDataDir();
 
 }  // namespace webrunner