diff --git a/AUTHORS b/AUTHORS
index 72262c45..7da923c 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -989,6 +989,7 @@
 Zhaoze Zhou <zhaoze.zhou@partner.samsung.com>
 Zheda Chen <zheda.chen@intel.com>
 Zheng Chuang <zhengchuangscu@gmail.com>
+Zhengkun Li <zhengkli@amazon.com>
 Zhenyu Liang <zhenyu.liang@intel.com>
 Zhenyu Shan <zhenyu.shan@intel.com>
 Zhifei Fang <facetothefate@gmail.com>
diff --git a/DEPS b/DEPS
index c7adc49..f5cf945d 100644
--- a/DEPS
+++ b/DEPS
@@ -133,11 +133,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '44c8131b779b1a21bae524733663014d3614a5ed',
+  'skia_revision': 'f4438d56e989745868ad2fc289894a1553d68ab6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '72287902200674b17fbc4557a6a9fb6c67f0542c',
+  'v8_revision': '3f6dd8f7b0462a669f3ed1c52519d19625a42d42',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -145,11 +145,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '094c40dce6015add9e9524364a4e9b0523b7c31e',
+  'angle_revision': '2fb6563bf50375dffcc92aab6c7865da4c555df7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'af973b67141eb2f8abf7e5bcf109f829fae0abbc',
+  'swiftshader_revision': 'a2749f39f47dd61b6f18972f6471993c6b5c1928',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -196,7 +196,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': '1a088f27008b608cfd9363cc70fbac3f44568f0e',
+  'catapult_revision': 'f8e231582d6aa491266c06cfaa7b81cd15aa3dfa',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -248,7 +248,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '6df8a917a4496f1a46e8ae21ffa3d00075380e47',
+  'spv_tools_revision': 'e545522146af37cc84f6b16e51ebbed96edd334c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -270,25 +270,26 @@
   # and whatever else without interference from each other.
   'quiche_revision': '348de99ee1f13e6747da3695387a2c78610f5f62',
   # Three lines of non-changing comments so that
-  # the commit queue can handle CLs rolling clang format
-  # and whatever else without interference from each other.
-  'clang_format_revision': '96636aa0e9f047f17447f2d45a094d0b59ed7917',
-  # Three lines of non-changing comments so that
-  # the commit queue can handle CLs rolling libc++
-  # and whatever else without interference from each other.
-  'libcxx_revision': 'a50f5035629b7621e92acef968403f71b7d48553',
-  # Three lines of non-changing comments so that
-  # the commit queue can handle CLs rolling libc++abi
-  # and whatever else without interference from each other.
-  'libcxxabi_revision': '0d529660e32d77d9111912d73f2c74fc5fa2a858',
-  # Three lines of non-changing comments so that
-  # the commit queue can handle CLs rolling libunwind
-  # and whatever else without interference from each other.
-  'libunwind_revision': '69d9b84cca8354117b9fe9705a4430d789ee599b',
-  # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ios_webkit
   # and whatever else without interference from each other.
   'ios_webkit_revision': '59e9de61b7b36507836fa8b098e8839d7d995b13',
+
+  #
+  # TODO(crbug.com/941824): These revisions need to be kept in sync
+  # between //DEPS and //buildtools/DEPS, so if you're updating one,
+  # update the other. There is a presubmit check that checks that
+  # you've done so; if you are adding new tools to //buildtools and
+  # hence new revisions to this list, make sure you update the
+  # _CheckBuildtoolsRevsAreInSync in PRESUBMIT.py to include the additional
+  # revisions.
+  #
+  # Also, if you change these, make sure you update the svn_revisions in
+  # //buildtools/deps_revisions.gni.
+  #
+  'clang_format_revision': '96636aa0e9f047f17447f2d45a094d0b59ed7917',
+  'libcxx_revision': 'a50f5035629b7621e92acef968403f71b7d48553',
+  'libcxxabi_revision': '0d529660e32d77d9111912d73f2c74fc5fa2a858',
+  'libunwind_revision': '69d9b84cca8354117b9fe9705a4430d789ee599b',
 }
 
 # Only these hosts are allowed for dependencies in this DEPS file.
@@ -408,7 +409,7 @@
   },
 
     'src/ios/third_party/edo/src': {
-      'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git' + '@' + '4ec31ccbe1e03279619915b00ddf30af5422106e',
+      'url': Var('chromium_git') + '/external/github.com/google/eDistantObject.git' + '@' + '0146bd6e1f057160bb80e596c644414e05267e9e',
       'condition': 'checkout_ios',
   },
 
@@ -760,7 +761,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '7a62eb7d2b04fa3418bfd1ab4dbc40be74818e64',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '69d4958ee9b3375a35c8e2f88173187a5b89594b',
       'condition': 'checkout_linux',
   },
 
@@ -785,7 +786,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '40c19421b4ba13579d1d8cbfecc7cb610eca3269',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '1c2fa0fdda124fad7f41d30d19efb901df7e4408',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1018,7 +1019,7 @@
   },
 
   'src/third_party/libvpx/source/libvpx':
-    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '8256c8b297c8b7c7ee4de24edff82ed67d6ef207',
+    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '1533bd84f12e5b24b5c2e41d1729942c7aa218ad',
 
   'src/third_party/libwebm/source':
     Var('chromium_git') + '/webm/libwebm.git' + '@' + '51ca718c3adf0ddedacd7df25fe45f67dc5a9ce1',
@@ -1127,7 +1128,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '29885798ac66d92369e98bc90a51ee2d2e497ec4',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '8320e6d2b742e5ecde2c60ca535a1d3c8f4c0bdb',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1339,7 +1340,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@eae9be8ac5e0e8fbaae7c5af4a5db0fc0f6d2be8',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@b58fe2ab9436b6e35ef3527b8fbf4e7f81c4c98a',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 0508eda..12de957 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -3027,6 +3027,46 @@
   return all_problems
 
 
+def _CheckBuildtoolsRevisionsAreInSync(input_api, output_api):
+  # TODO(crbug.com/941824): We need to make sure the entries in
+  # //buildtools/DEPS are kept in sync with the entries in //DEPS
+  # so that users of //buildtools in other projects get the same tooling
+  # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
+  # support to gclient, we can eliminate the duplication and delete
+  # this presubmit check.
+
+  # Update this regexp if new revisions are added to the files.
+  rev_regexp = input_api.re.compile(
+      "'(clang_format|libcxx|libcxxabi|libunwind)_revision':")
+
+  # If a user is changing one revision, they need to change the same
+  # line in both files. This means that any given change should contain
+  # exactly the same list of changed lines that match the regexps. The
+  # replace(' ', '') call allows us to ignore whitespace changes to the
+  # lines. The 'long_text' parameter to the error will contain the
+  # list of changed lines in both files, which should make it easy enough
+  # to spot the error without going overboard in this implementation.
+  revs_changes = {
+      'DEPS': {},
+      'buildtools/DEPS': {},
+  }
+  long_text = ''
+
+  for f in input_api.AffectedFiles(
+      file_filter=lambda f: f.LocalPath() in ('DEPS', 'buildtools/DEPS')):
+    for line_num, line in f.ChangedContents():
+      if rev_regexp.search(line):
+        revs_changes[f.LocalPath()][line.replace(' ', '')] = line
+        long_text += '%s:%d: %s\n' % (f.LocalPath(), line_num, line)
+
+  if set(revs_changes['DEPS']) != set(revs_changes['buildtools/DEPS']):
+    return [output_api.PresubmitError(
+        'Change buildtools revisions in sync in both //DEPS and '
+        '//buildtools/DEPS.', long_text=long_text + '\n')]
+  else:
+    return []
+
+
 def _AndroidSpecificOnUploadChecks(input_api, output_api):
   """Groups upload checks that target android code."""
   results = []
@@ -3111,6 +3151,7 @@
     input_api.canned_checks.CheckVPythonSpec(input_api, output_api)))
   results.extend(_CheckTranslationScreenshots(input_api, output_api))
   results.extend(_CheckCorrectProductNameInMessages(input_api, output_api))
+  results.extend(_CheckBuildtoolsRevisionsAreInSync(input_api, output_api))
 
   for f in input_api.AffectedFiles():
     path, name = input_api.os_path.split(f.LocalPath())
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py
index e3c16f6..34456b1 100755
--- a/PRESUBMIT_test.py
+++ b/PRESUBMIT_test.py
@@ -2232,5 +2232,49 @@
                                                    MockOutputApi())
     self.assertEqual(0, len(results))
 
+
+class BuildtoolsRevisionsAreInSyncTest(unittest.TestCase):
+  # TODO(crbug.com/941824): We need to make sure the entries in
+  # //buildtools/DEPS are kept in sync with the entries in //DEPS
+  # so that users of //buildtools in other projects get the same tooling
+  # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
+  # support to gclient, we can eliminate the duplication and delete
+  # these tests for the corresponding presubmit check.
+
+  def _check(self, files):
+    mock_input_api = MockInputApi()
+    mock_input_api.files = []
+    for fname, contents in files.items():
+      mock_input_api.files.append(MockFile(fname, contents.splitlines()))
+    return PRESUBMIT._CheckBuildtoolsRevisionsAreInSync(mock_input_api,
+                                                        MockOutputApi())
+
+  def testOneFileChangedButNotTheOther(self):
+    results = self._check({
+        "DEPS": "'libunwind_revision': 'onerev'",
+    })
+    self.assertNotEqual(results, [])
+
+  def testNeitherFileChanged(self):
+    results = self._check({
+        "OWNERS": "foobar@example.com",
+    })
+    self.assertEqual(results, [])
+
+  def testBothFilesChangedAndMatch(self):
+    results = self._check({
+        "DEPS": "'libunwind_revision': 'onerev'",
+        "buildtools/DEPS": "'libunwind_revision': 'onerev'",
+    })
+    self.assertEqual(results, [])
+
+  def testBothFilesWereChangedAndDontMatch(self):
+    results = self._check({
+        "DEPS": "'libunwind_revision': 'onerev'",
+        "buildtools/DEPS": "'libunwind_revision': 'anotherrev'",
+    })
+    self.assertNotEqual(results, [])
+
+
 if __name__ == '__main__':
   unittest.main()
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 8983f5f..156e205c 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -19,6 +19,7 @@
 #include "android_webview/browser/aw_contents_io_thread_client.h"
 #include "android_webview/browser/aw_cookie_access_policy.h"
 #include "android_webview/browser/aw_devtools_manager_delegate.h"
+#include "android_webview/browser/aw_feature_list.h"
 #include "android_webview/browser/aw_feature_list_creator.h"
 #include "android_webview/browser/aw_http_auth_handler.h"
 #include "android_webview/browser/aw_proxying_url_loader_factory.h"
@@ -984,6 +985,13 @@
   return android_webview::GetUserAgent();
 }
 
+content::ContentBrowserClient::WideColorGamutHeuristic
+AwContentBrowserClient::GetWideColorGamutHeuristic() const {
+  if (base::FeatureList::IsEnabled(features::kWebViewWideColorGamutSupport))
+    return WideColorGamutHeuristic::kUseWindow;
+  return WideColorGamutHeuristic::kNone;
+}
+
 content::SpeechRecognitionManagerDelegate*
 AwContentBrowserClient::CreateSpeechRecognitionManagerDelegate() {
   return new AwSpeechRecognitionManagerDelegate();
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index c2afa81a..1b50460 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -229,6 +229,8 @@
       bool* bypass_redirect_checks) override;
   std::string GetProduct() const override;
   std::string GetUserAgent() const override;
+  ContentBrowserClient::WideColorGamutHeuristic GetWideColorGamutHeuristic()
+      const override;
 
   AwFeatureListCreator* aw_feature_list_creator() {
     return aw_feature_list_creator_;
diff --git a/android_webview/browser/aw_feature_list.cc b/android_webview/browser/aw_feature_list.cc
index 2c02de3..f05c8f60 100644
--- a/android_webview/browser/aw_feature_list.cc
+++ b/android_webview/browser/aw_feature_list.cc
@@ -25,7 +25,6 @@
 const base::Feature* kFeaturesExposedToJava[] = {
     &features::kWebViewConnectionlessSafeBrowsing,
     &features::kWebViewPageStartedOnCommit,
-    &features::kWebViewWideColorGamutSupport,
 };
 
 const base::Feature* FindFeatureExposedToJava(const std::string& feature_name) {
diff --git a/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java b/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java
index fd51311c..d8547ede 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java
@@ -36,7 +36,6 @@
 import org.chromium.content_public.browser.ChildProcessCreationParams;
 import org.chromium.content_public.browser.ChildProcessLauncherHelper;
 import org.chromium.policy.CombinedPolicyProvider;
-import org.chromium.ui.base.WindowAndroid;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -147,10 +146,6 @@
                 } catch (ProcessInitException e) {
                     throw new RuntimeException("Cannot initialize WebView", e);
                 }
-
-                if (AwFeatureList.isEnabled(AwFeatureList.WEBVIEW_WIDE_COLOR_GAMUT_SUPPORT)) {
-                    WindowAndroid.enableWideColorGamut();
-                }
             });
         }
     }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwFeatureList.java b/android_webview/java/src/org/chromium/android_webview/AwFeatureList.java
index eff10b2..829c7a8 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwFeatureList.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwFeatureList.java
@@ -67,7 +67,6 @@
     public static final String WEBVIEW_CONNECTIONLESS_SAFE_BROWSING =
             "WebViewConnectionlessSafeBrowsing";
     public static final String WEBVIEW_PAGE_STARTED_ON_COMMIT = "WebViewPageStartedOnCommit";
-    public static final String WEBVIEW_WIDE_COLOR_GAMUT_SUPPORT = "WebViewWideColorGamutSupport";
 
     private static native boolean nativeIsEnabled(String featureName);
 }
diff --git a/android_webview/tools/run_cts.py b/android_webview/tools/run_cts.py
index 5e99f5c..13774de 100755
--- a/android_webview/tools/run_cts.py
+++ b/android_webview/tools/run_cts.py
@@ -320,6 +320,21 @@
     device.Uninstall(package)
 
 
+def ForwardArgsToTestRunner(known_args):
+  """Convert any args that should be forwarded to test_runner.py"""
+  forwarded_args = []
+  if known_args.devices:
+    # test_runner.py parses --device as nargs instead of append args
+    forwarded_args.extend(['--device'] + known_args.devices)
+  if known_args.blacklist_file:
+    forwarded_args.extend(['--blacklist-file', known_args.blacklist_file])
+
+  if known_args.verbose:
+    forwarded_args.extend(['-' + 'v' * known_args.verbose])
+  #TODO: Pass quiet to test runner when it becomes supported
+  return forwarded_args
+
+
 def main():
   parser = argparse.ArgumentParser()
   parser.add_argument(
@@ -373,13 +388,13 @@
   logging_common.InitializeLogging(args)
   devil_chromium.Initialize()
 
+  test_runner_args.extend(ForwardArgsToTestRunner(args))
+
   devices = script_common.GetDevices(args.devices, args.blacklist_file)
   device = devices[0]
   if len(devices) > 1:
-    logging.warning('Only single device supported, using 1st of %d devices: %s',
-                    len(devices), device.serial)
-  test_runner_args.extend(['-d', device.serial])
-
+    logging.warning('Detection of arch and cts-release will use 1st of %d '
+                    'devices: %s', len(devices), device.serial)
   arch = args.arch or DetermineArch(device)
   cts_release = args.cts_release or DetermineCtsRelease(device)
 
diff --git a/ash/DEPS b/ash/DEPS
index 35ba450..7b40fb2 100644
--- a/ash/DEPS
+++ b/ash/DEPS
@@ -61,12 +61,10 @@
   "+chromeos/constants",
   "+chromeos/dbus/dbus_thread_manager.h",
   "+chromeos/dbus/fake_power_manager_client.h",
-  "+chromeos/dbus/fake_session_manager_client.h",
   "+chromeos/dbus/hammerd",
   "+chromeos/dbus/power_manager",
   "+chromeos/dbus/power_manager_client.h",
   "+chromeos/dbus/power_policy_controller.h",
-  "+chromeos/dbus/session_manager_client.h",
   "+chromeos/dbus/shill_device_client.h",
   "+chromeos/dbus/system_clock",
   # TODO(jamescook): Eliminate this. http://crbug.com/644355
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index 3cc430544..5d04d414 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -28,7 +28,6 @@
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/session/session_controller.h"
-#include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "ash/voice_interaction/voice_interaction_controller.h"
 #include "ash/wallpaper/wallpaper_controller.h"
@@ -535,16 +534,6 @@
   return model_->state_fullscreen();
 }
 
-void AppListControllerImpl::OnWindowDragStarted() {
-  in_window_dragging_ = true;
-  UpdateHomeLauncherVisibility();
-}
-
-void AppListControllerImpl::OnWindowDragEnded() {
-  in_window_dragging_ = false;
-  UpdateHomeLauncherVisibility();
-}
-
 void AppListControllerImpl::FlushForTesting() {
   bindings_.FlushForTesting();
 }
@@ -617,7 +606,7 @@
   }
 
   // Show the app list if the tablet mode starts.
-  ShowHomeLauncher();
+  Shell::Get()->home_screen_controller()->Show();
   UpdateLauncherContainer();
 }
 
@@ -643,16 +632,6 @@
     app_list_view->OnScreenKeyboardShown(is_visible);
 }
 
-void AppListControllerImpl::OnWallpaperPreviewStarted() {
-  in_wallpaper_preview_ = true;
-  UpdateHomeLauncherVisibility();
-}
-
-void AppListControllerImpl::OnWallpaperPreviewEnded() {
-  in_wallpaper_preview_ = false;
-  UpdateHomeLauncherVisibility();
-}
-
 void AppListControllerImpl::OnVoiceInteractionSettingsEnabled(bool enabled) {
   UpdateAssistantVisibility();
 }
@@ -678,7 +657,7 @@
     return;
 
   if (should_be_shown)
-    ShowHomeLauncher();
+    Shell::Get()->home_screen_controller()->Show();
 }
 
 void AppListControllerImpl::OnWindowUntracked(aura::Window* untracked_window) {
@@ -732,6 +711,16 @@
                          : AssistantExitPoint::kLauncherClose);
 }
 
+void AppListControllerImpl::ShowHomeScreen() {
+  DCHECK(IsTabletMode());
+
+  Show(GetDisplayIdToShowAppListOn(), app_list::kTabletMode, base::TimeTicks());
+}
+
+aura::Window* AppListControllerImpl::GetHomeScreenWindow() {
+  return presenter_.GetWindow();
+}
+
 void AppListControllerImpl::UpdateYPositionAndOpacityForHomeLauncher(
     int y_position_in_screen,
     float opacity,
@@ -1157,17 +1146,6 @@
   return model_->FindFolderItem(folder_id);
 }
 
-void AppListControllerImpl::UpdateHomeLauncherVisibility() {
-  if (!IsTabletMode() || !presenter_.GetWindow())
-    return;
-
-  const bool in_overview = Shell::Get()->overview_controller()->IsSelecting();
-  if (in_wallpaper_preview_ || in_overview || in_window_dragging_)
-    presenter_.GetWindow()->Hide();
-  else
-    presenter_.GetWindow()->Show();
-}
-
 void AppListControllerImpl::UpdateAssistantVisibility() {
   GetSearchModel()->search_box()->SetShowAssistantButton(
       IsAssistantAllowedAndEnabled());
@@ -1185,17 +1163,6 @@
       .id();
 }
 
-void AppListControllerImpl::ShowHomeLauncher() {
-  DCHECK(IsTabletMode());
-
-  if (!Shell::Get()->session_controller()->IsActiveUserSessionStarted())
-    return;
-
-  Show(GetDisplayIdToShowAppListOn(), app_list::kTabletMode, base::TimeTicks());
-  UpdateHomeLauncherVisibility();
-  Shelf::ForWindow(presenter_.GetWindow())->MaybeUpdateShelfBackground();
-}
-
 void AppListControllerImpl::ResetHomeLauncherIfShown() {
   if (!IsTabletMode() || !presenter_.IsVisible())
     return;
diff --git a/ash/app_list/app_list_controller_impl.h b/ash/app_list/app_list_controller_impl.h
index 26176cb..4395afc2 100644
--- a/ash/app_list/app_list_controller_impl.h
+++ b/ash/app_list/app_list_controller_impl.h
@@ -151,12 +151,6 @@
                                  base::TimeTicks event_time_stamp);
   app_list::AppListViewState GetAppListViewState();
 
-  // Called when a window starts/ends dragging. If we're in tablet mode and home
-  // launcher is enabled, we should hide the home launcher during dragging a
-  // window and reshow it when the drag ends.
-  void OnWindowDragStarted();
-  void OnWindowDragEnded();
-
   // app_list::AppListViewDelegate:
   app_list::AppListModel* GetModel() override;
   app_list::SearchModel* GetSearchModel() override;
@@ -231,8 +225,6 @@
 
   // WallpaperControllerObserver:
   void OnWallpaperColorsChanged() override;
-  void OnWallpaperPreviewStarted() override;
-  void OnWallpaperPreviewEnded() override;
 
   // mojom::VoiceInteractionObserver:
   void OnVoiceInteractionSettingsEnabled(bool enabled) override;
@@ -256,6 +248,8 @@
   void OnHomeLauncherAnimationComplete(bool shown, int64_t display_id) override;
 
   // HomeScreenDelegate:
+  void ShowHomeScreen() override;
+  aura::Window* GetHomeScreenWindow() override;
   void UpdateYPositionAndOpacityForHomeLauncher(
       int y_position_in_screen,
       float opacity,
@@ -294,10 +288,6 @@
       AppListItemMetadataPtr metadata);
   app_list::AppListFolderItem* FindFolderItem(const std::string& folder_id);
 
-  // Update the visibility of the home launcher based on e.g. if the device is
-  // in overview mode.
-  void UpdateHomeLauncherVisibility();
-
   // Update the visibility of Assistant functionality.
   void UpdateAssistantVisibility();
 
@@ -306,15 +296,12 @@
 
   int64_t GetDisplayIdToShowAppListOn();
 
-  // Shows the home launcher in tablet mode.
-  void ShowHomeLauncher();
-
   void ResetHomeLauncherIfShown();
 
   // Updates which container the launcher window should be in.
   void UpdateLauncherContainer();
 
-// Returns the length of the most recent query.
+  // Returns the length of the most recent query.
   int GetLastQueryLength();
 
   base::string16 last_raw_query_;
@@ -339,13 +326,6 @@
   // overview mode exit animations are finished.
   bool use_slide_to_exit_overview_ = false;
 
-  // Whether the wallpaper is being previewed. The home launcher (if enabled)
-  // should be hidden during wallpaper preview.
-  bool in_wallpaper_preview_ = false;
-
-  // Whether we're currently in a window dragging process.
-  bool in_window_dragging_ = false;
-
   base::ObserverList<AppListControllerObserver> observers_;
 
   DISALLOW_COPY_AND_ASSIGN(AppListControllerImpl);
diff --git a/ash/app_list/views/assistant/assistant_main_stage.cc b/ash/app_list/views/assistant/assistant_main_stage.cc
index 561f3bc..345f8bb 100644
--- a/ash/app_list/views/assistant/assistant_main_stage.cc
+++ b/ash/app_list/views/assistant/assistant_main_stage.cc
@@ -143,10 +143,6 @@
   layer()->SetFillsBoundsOpaquely(false);
   layer()->SetMasksToBounds(true);
 
-  // TODO(wutao): finalize the padding.
-  constexpr int kTopPaddingDip = 3;
-  SetBorder(views::CreateEmptyBorder(gfx::Insets(kTopPaddingDip, 0, 0, 0)));
-
   // Separators: the progress indicator and the horizontal separator will be the
   // separator when querying and showing the results, respectively. The height
   // of the horizontal separator is set to be the same as the progress indicator
diff --git a/ash/app_list/views/assistant/assistant_main_view.cc b/ash/app_list/views/assistant/assistant_main_view.cc
index e479f41..d68d097d 100644
--- a/ash/app_list/views/assistant/assistant_main_view.cc
+++ b/ash/app_list/views/assistant/assistant_main_view.cc
@@ -10,17 +10,12 @@
 #include "ash/app_list/views/assistant/dialog_plate.h"
 #include "ash/assistant/ui/assistant_ui_constants.h"
 #include "ash/assistant/ui/assistant_view_delegate.h"
+#include "ash/public/cpp/app_list/app_list_features.h"
 #include "ui/chromeos/search_box/search_box_constants.h"
 #include "ui/views/layout/box_layout.h"
 
 namespace app_list {
 
-namespace {
-
-constexpr int kBottomPaddingDip = 8;
-
-}  // namespace
-
 AssistantMainView::AssistantMainView(ash::AssistantViewDelegate* delegate)
     : delegate_(delegate) {
   InitLayout();
@@ -83,7 +78,6 @@
           views::BoxLayout::Orientation::kVertical));
   layout->set_cross_axis_alignment(
       views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
-  SetBorder(views::CreateEmptyBorder(gfx::Insets(0, 0, kBottomPaddingDip, 0)));
 
   // Dialog plate.
   dialog_plate_ = new DialogPlate(delegate_);
diff --git a/ash/app_list/views/assistant/dialog_plate.cc b/ash/app_list/views/assistant/dialog_plate.cc
index 2fea69f..bd3f651e 100644
--- a/ash/app_list/views/assistant/dialog_plate.cc
+++ b/ash/app_list/views/assistant/dialog_plate.cc
@@ -33,11 +33,10 @@
 namespace {
 
 // Appearance.
-// TODO(wutao): need to be finalized.
 constexpr int kDialogPaddingDip = 16;
 constexpr int kIconSizeDip = 24;
 constexpr int kButtonSizeDip = 32;
-constexpr int kPreferredHeightDip = 48;
+constexpr int kPreferredHeightDip = 56;
 
 // Animation.
 constexpr base::TimeDelta kAnimationFadeInDelay =
diff --git a/ash/app_list/views/search_box_view.cc b/ash/app_list/views/search_box_view.cc
index 1fca956a..733477f 100644
--- a/ash/app_list/views/search_box_view.cc
+++ b/ash/app_list/views/search_box_view.cc
@@ -176,11 +176,9 @@
 void SearchBoxView::UpdateSearchIcon() {
   const gfx::VectorIcon& google_icon =
       is_search_box_active() ? kGoogleColorIcon : kGoogleBlackIcon;
-  const gfx::VectorIcon& icon =
-      search_model_->search_engine_is_google() &&
-              !app_list_features::IsEmbeddedAssistantUIEnabled()
-          ? google_icon
-          : kSearchEngineNotGoogleIcon;
+  const gfx::VectorIcon& icon = search_model_->search_engine_is_google()
+                                    ? google_icon
+                                    : kSearchEngineNotGoogleIcon;
   SetSearchIconImage(gfx::CreateVectorIcon(icon, search_box::kSearchIconSize,
                                            search_box_color()));
 }
diff --git a/ash/app_list/views/search_result_tile_item_view.cc b/ash/app_list/views/search_result_tile_item_view.cc
index ffad6f52..306d08d 100644
--- a/ash/app_list/views/search_result_tile_item_view.cc
+++ b/ash/app_list/views/search_result_tile_item_view.cc
@@ -97,7 +97,6 @@
   AddChildView(icon_);
 
   if (is_play_store_app_search_enabled_ ||
-      app_list_features::IsAppShortcutSearchEnabled() ||
       is_app_reinstall_recommendation_enabled_) {
     badge_ = new views::ImageView;
     badge_->set_can_process_events_within_subtree(false);
diff --git a/ash/assistant/ui/main_stage/assistant_opt_in_view.cc b/ash/assistant/ui/main_stage/assistant_opt_in_view.cc
index 1f19769..4740793 100644
--- a/ash/assistant/ui/main_stage/assistant_opt_in_view.cc
+++ b/ash/assistant/ui/main_stage/assistant_opt_in_view.cc
@@ -9,6 +9,7 @@
 
 #include "ash/assistant/ui/assistant_ui_constants.h"
 #include "ash/assistant/ui/assistant_view_delegate.h"
+#include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/canvas.h"
@@ -123,7 +124,9 @@
           views::BoxLayout::Orientation::kHorizontal));
 
   layout_manager->set_cross_axis_alignment(
-      views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_END);
+      app_list_features::IsEmbeddedAssistantUIEnabled()
+          ? views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_CENTER
+          : views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_END);
 
   layout_manager->set_main_axis_alignment(
       views::BoxLayout::MainAxisAlignment::MAIN_AXIS_ALIGNMENT_CENTER);
diff --git a/ash/assistant/ui/main_stage/suggestion_container_view.cc b/ash/assistant/ui/main_stage/suggestion_container_view.cc
index 5d54828..d57dcc63 100644
--- a/ash/assistant/ui/main_stage/suggestion_container_view.cc
+++ b/ash/assistant/ui/main_stage/suggestion_container_view.cc
@@ -12,6 +12,7 @@
 #include "ash/assistant/ui/assistant_ui_constants.h"
 #include "ash/assistant/ui/assistant_view_delegate.h"
 #include "ash/assistant/util/assistant_util.h"
+#include "ash/public/cpp/app_list/app_list_features.h"
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/views/layout/box_layout.h"
@@ -72,7 +73,9 @@
           gfx::Insets(0, kPaddingDip), kSpacingDip));
 
   layout_manager_->set_cross_axis_alignment(
-      views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_END);
+      app_list_features::IsEmbeddedAssistantUIEnabled()
+          ? views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_CENTER
+          : views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_END);
 
   // We center align when showing conversation starters.
   layout_manager_->set_main_axis_alignment(
diff --git a/ash/assistant/ui/main_stage/ui_element_container_view.cc b/ash/assistant/ui/main_stage/ui_element_container_view.cc
index 0dbb0037..7aeab3cb 100644
--- a/ash/assistant/ui/main_stage/ui_element_container_view.cc
+++ b/ash/assistant/ui/main_stage/ui_element_container_view.cc
@@ -13,6 +13,7 @@
 #include "ash/assistant/ui/main_stage/assistant_card_element_view.h"
 #include "ash/assistant/ui/main_stage/assistant_text_element_view.h"
 #include "ash/assistant/util/animation_util.h"
+#include "ash/public/cpp/app_list/app_list_features.h"
 #include "base/callback.h"
 #include "base/time/time.h"
 #include "ui/aura/window.h"
@@ -27,14 +28,17 @@
 namespace {
 
 // Appearance.
-constexpr int kFirstCardMarginTopDip = 40;
-constexpr int kPaddingBottomDip = 24;
+constexpr int kEmbeddedUiFirstCardMarginTopDip = 8;
+constexpr int kEmbeddedUiPaddingBottomDip = 8;
+constexpr int kMainUiFirstCardMarginTopDip = 40;
+constexpr int kMainUiPaddingBottomDip = 24;
 
 // Card element animation.
 constexpr float kCardElementAnimationFadeOutOpacity = 0.26f;
 
 // Text element animation.
-constexpr float kTextElementAnimationFadeOutOpacity = 0.f;
+constexpr float kEmbeddedUiTextElementAnimationFadeOutOpacity = 0.26f;
+constexpr float kMainUiTextElementAnimationFadeOutOpacity = 0.f;
 
 // UI element animation.
 constexpr base::TimeDelta kUiElementAnimationFadeInDelay =
@@ -43,6 +47,27 @@
     base::TimeDelta::FromMilliseconds(250);
 constexpr base::TimeDelta kUiElementAnimationFadeOutDuration =
     base::TimeDelta::FromMilliseconds(167);
+
+// Helpers ---------------------------------------------------------------------
+
+int GetFirstCardMarginTopDip() {
+  return app_list_features::IsEmbeddedAssistantUIEnabled()
+             ? kEmbeddedUiFirstCardMarginTopDip
+             : kMainUiFirstCardMarginTopDip;
+}
+
+int GetPaddingBottomDip() {
+  return app_list_features::IsEmbeddedAssistantUIEnabled()
+             ? kEmbeddedUiPaddingBottomDip
+             : kMainUiPaddingBottomDip;
+}
+
+float GetTextElementAnimationFadeOutOpacity() {
+  return app_list_features::IsEmbeddedAssistantUIEnabled()
+             ? kEmbeddedUiTextElementAnimationFadeOutOpacity
+             : kMainUiTextElementAnimationFadeOutOpacity;
+}
+
 }  // namespace
 
 // UiElementContainerView ------------------------------------------------------
@@ -106,7 +131,7 @@
 void UiElementContainerView::InitLayout() {
   content_view()->SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kVertical,
-      gfx::Insets(0, kUiElementHorizontalMarginDip, kPaddingBottomDip,
+      gfx::Insets(0, kUiElementHorizontalMarginDip, GetPaddingBottomDip(),
                   kUiElementHorizontalMarginDip),
       kSpacingDip));
 }
@@ -229,12 +254,12 @@
   if (is_first_card_) {
     is_first_card_ = false;
 
-    // The first card requires a top margin of |kFirstCardMarginTopDip|, but
+    // The first card requires a top margin of |GetFirstCardMarginTopDip()|, but
     // we need to account for child spacing because the first card is not
     // necessarily the first UI element.
     const int top_margin_dip = child_count() == 0
-                                   ? kFirstCardMarginTopDip
-                                   : kFirstCardMarginTopDip - kSpacingDip;
+                                   ? GetFirstCardMarginTopDip()
+                                   : GetFirstCardMarginTopDip() - kSpacingDip;
 
     // We effectively create a top margin by applying an empty border.
     card_element_view->SetBorder(
@@ -271,7 +296,7 @@
   // We cache the view for use during animations and its desired opacity that
   // we'll animate to while processing the next query response.
   ui_element_views_.push_back(std::pair<ui::LayerOwner*, float>(
-      text_element_view, kTextElementAnimationFadeOutOpacity));
+      text_element_view, GetTextElementAnimationFadeOutOpacity()));
 
   content_view()->AddChildView(text_element_view);
 }
diff --git a/ash/dbus/DEPS b/ash/dbus/DEPS
index 5ea2f34..c4c77ff 100644
--- a/ash/dbus/DEPS
+++ b/ash/dbus/DEPS
@@ -1,4 +1,6 @@
 include_rules = [
   "+chromeos/dbus/services",
+  # TODO(stevenjb): Eliminate this, https://crbug.com/644350.
+  "+chromeos/dbus/session_manager_client.h",
   "+dbus",
 ]
diff --git a/ash/home_screen/home_screen_controller.cc b/ash/home_screen/home_screen_controller.cc
index daab566..2292fad 100644
--- a/ash/home_screen/home_screen_controller.cc
+++ b/ash/home_screen/home_screen_controller.cc
@@ -5,17 +5,83 @@
 #include "ash/home_screen/home_screen_controller.h"
 
 #include "ash/home_screen/home_launcher_gesture_handler.h"
+#include "ash/home_screen/home_screen_delegate.h"
+#include "ash/session/session_controller.h"
+#include "ash/shelf/shelf.h"
+#include "ash/shell.h"
+#include "ash/wallpaper/wallpaper_controller.h"
+#include "ash/wm/overview/overview_controller.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "base/logging.h"
+#include "ui/aura/window.h"
 
 namespace ash {
 
 HomeScreenController::HomeScreenController()
     : home_launcher_gesture_handler_(
-          std::make_unique<HomeLauncherGestureHandler>()) {}
+          std::make_unique<HomeLauncherGestureHandler>()) {
+  wallpaper_controller_observer_.Add(Shell::Get()->wallpaper_controller());
+}
 
 HomeScreenController::~HomeScreenController() = default;
 
+bool HomeScreenController::IsHomeScreenAvailable() {
+  return Shell::Get()
+      ->tablet_mode_controller()
+      ->IsTabletModeWindowManagerEnabled();
+}
+
+void HomeScreenController::Show() {
+  DCHECK(IsHomeScreenAvailable());
+
+  if (!Shell::Get()->session_controller()->IsActiveUserSessionStarted())
+    return;
+
+  delegate_->ShowHomeScreen();
+  UpdateVisibility();
+
+  aura::Window* window = delegate_->GetHomeScreenWindow();
+  if (window)
+    Shelf::ForWindow(window)->MaybeUpdateShelfBackground();
+}
+
 void HomeScreenController::SetDelegate(HomeScreenDelegate* delegate) {
   delegate_ = delegate;
 }
 
+void HomeScreenController::OnWindowDragStarted() {
+  in_window_dragging_ = true;
+  UpdateVisibility();
+}
+
+void HomeScreenController::OnWindowDragEnded() {
+  in_window_dragging_ = false;
+  UpdateVisibility();
+}
+
+void HomeScreenController::OnWallpaperPreviewStarted() {
+  in_wallpaper_preview_ = true;
+  UpdateVisibility();
+}
+
+void HomeScreenController::OnWallpaperPreviewEnded() {
+  in_wallpaper_preview_ = false;
+  UpdateVisibility();
+}
+
+void HomeScreenController::UpdateVisibility() {
+  if (!IsHomeScreenAvailable())
+    return;
+
+  aura::Window* window = delegate_->GetHomeScreenWindow();
+  if (!window)
+    return;
+
+  const bool in_overview = Shell::Get()->overview_controller()->IsSelecting();
+  if (in_overview || in_wallpaper_preview_ || in_window_dragging_)
+    window->Hide();
+  else
+    window->Show();
+}
+
 }  // namespace ash
diff --git a/ash/home_screen/home_screen_controller.h b/ash/home_screen/home_screen_controller.h
index b9d6ea407..2969e0d 100644
--- a/ash/home_screen/home_screen_controller.h
+++ b/ash/home_screen/home_screen_controller.h
@@ -8,24 +8,39 @@
 #include <memory>
 
 #include "ash/ash_export.h"
+#include "ash/wallpaper/wallpaper_controller_observer.h"
 #include "base/macros.h"
+#include "base/scoped_observer.h"
 
 namespace ash {
 
 class HomeLauncherGestureHandler;
 class HomeScreenDelegate;
+class WallpaperController;
 
 // HomeScreenController handles the home launcher (e.g., tablet-mode app list)
 // and owns the HomeLauncherGestureHandler that transitions the launcher window
 // and other windows when the launcher is shown, hidden or animated.
-class ASH_EXPORT HomeScreenController {
+class ASH_EXPORT HomeScreenController : public WallpaperControllerObserver {
  public:
   HomeScreenController();
-  ~HomeScreenController();
+  ~HomeScreenController() override;
+
+  // Returns true if the home screen can be shown (generally corresponds to the
+  // device being in tablet mode).
+  bool IsHomeScreenAvailable();
+
+  // Shows the home screen.
+  void Show();
 
   // Sets the delegate for home screen animations.
   void SetDelegate(HomeScreenDelegate* delegate);
 
+  // Called when a window starts/ends dragging. If the home screen is shown, we
+  // should hide it during dragging a window and reshow it when the drag ends.
+  void OnWindowDragStarted();
+  void OnWindowDragEnded();
+
   HomeLauncherGestureHandler* home_launcher_gesture_handler() {
     return home_launcher_gesture_handler_.get();
   }
@@ -33,6 +48,21 @@
   HomeScreenDelegate* delegate() { return delegate_; }
 
  private:
+  // WallpaperControllerObserver:
+  void OnWallpaperPreviewStarted() override;
+  void OnWallpaperPreviewEnded() override;
+
+  // Updates the visibility of the home screen based on e.g. if the device is
+  // in overview mode.
+  void UpdateVisibility();
+
+  // Whether the wallpaper is being previewed. The home screen should be hidden
+  // during wallpaper preview.
+  bool in_wallpaper_preview_ = false;
+
+  // Whether we're currently in a window dragging process.
+  bool in_window_dragging_ = false;
+
   // Not owned.
   HomeScreenDelegate* delegate_ = nullptr;
 
@@ -40,6 +70,9 @@
   // launcher.
   std::unique_ptr<HomeLauncherGestureHandler> home_launcher_gesture_handler_;
 
+  ScopedObserver<WallpaperController, WallpaperControllerObserver>
+      wallpaper_controller_observer_{this};
+
   DISALLOW_COPY_AND_ASSIGN(HomeScreenController);
 };
 
diff --git a/ash/home_screen/home_screen_delegate.h b/ash/home_screen/home_screen_delegate.h
index 461cae4f..ecb070e7 100644
--- a/ash/home_screen/home_screen_delegate.h
+++ b/ash/home_screen/home_screen_delegate.h
@@ -8,6 +8,10 @@
 #include "base/callback.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 
+namespace aura {
+class Window;
+}  // namespace aura
+
 namespace ash {
 
 // Delegate for implementation-specific home screen behavior.
@@ -21,6 +25,14 @@
 
   virtual ~HomeScreenDelegate() = default;
 
+  // Shows the home screen view.
+  virtual void ShowHomeScreen() = 0;
+
+  // Gets the home screen window, if available, or null if the home screen
+  // window is being hidden for effects (e.g. when dragging windows or
+  // previewing the wallpaper).
+  virtual aura::Window* GetHomeScreenWindow() = 0;
+
   // Updates the y position and opacity of the home launcher view. If |callback|
   // is non-null, it should be called with animation settings.
   virtual void UpdateYPositionAndOpacityForHomeLauncher(
diff --git a/ash/public/cpp/app_list/app_list_features.cc b/ash/public/cpp/app_list/app_list_features.cc
index d7c0c46..308090c 100644
--- a/ash/public/cpp/app_list/app_list_features.cc
+++ b/ash/public/cpp/app_list/app_list_features.cc
@@ -13,8 +13,6 @@
 
 const base::Feature kEnableAnswerCard{"EnableAnswerCard",
                                       base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kEnableAppShortcutSearch{"EnableAppShortcutSearch",
-                                             base::FEATURE_ENABLED_BY_DEFAULT};
 const base::Feature kEnableBackgroundBlur{"EnableBackgroundBlur",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kEnablePlayStoreAppSearch{
@@ -45,10 +43,6 @@
          !IsEmbeddedAssistantUIEnabled();
 }
 
-bool IsAppShortcutSearchEnabled() {
-  return base::FeatureList::IsEnabled(kEnableAppShortcutSearch);
-}
-
 bool IsBackgroundBlurEnabled() {
   return base::FeatureList::IsEnabled(kEnableBackgroundBlur);
 }
diff --git a/ash/public/cpp/app_list/app_list_features.h b/ash/public/cpp/app_list/app_list_features.h
index b7c7d69..f69ec90 100644
--- a/ash/public/cpp/app_list/app_list_features.h
+++ b/ash/public/cpp/app_list/app_list_features.h
@@ -21,9 +21,6 @@
 // Enables the answer card in the app list.
 ASH_PUBLIC_EXPORT extern const base::Feature kEnableAnswerCard;
 
-// Enables app shortcuts search.
-ASH_PUBLIC_EXPORT extern const base::Feature kEnableAppShortcutSearch;
-
 // Enables background blur for the app list, lock screen, and tab switcher, also
 // enables the AppsGridView mask layer. In this mode, slower devices may have
 // choppier app list animations. crbug.com/765292.
@@ -61,7 +58,6 @@
 ASH_PUBLIC_EXPORT extern const base::Feature kEnableAppGridGhost;
 
 bool ASH_PUBLIC_EXPORT IsAnswerCardEnabled();
-bool ASH_PUBLIC_EXPORT IsAppShortcutSearchEnabled();
 bool ASH_PUBLIC_EXPORT IsBackgroundBlurEnabled();
 bool ASH_PUBLIC_EXPORT IsPlayStoreAppSearchEnabled();
 bool ASH_PUBLIC_EXPORT IsAppDataSearchEnabled();
diff --git a/ash/public/interfaces/shell_test_api.test-mojom b/ash/public/interfaces/shell_test_api.test-mojom
index ab932ae..3dbd259 100644
--- a/ash/public/interfaces/shell_test_api.test-mojom
+++ b/ash/public/interfaces/shell_test_api.test-mojom
@@ -33,8 +33,4 @@
 
   // Set the minimum velocity to cause fling gesture.
   SetMinFlingVelocity(float velocity);
-
-  // Returns the number of child windows for the given container in the primary
-  // root window.
-  GetChildWindowCountInContainer(int32 container_id) => (int32 count);
 };
diff --git a/ash/shelf/app_list_button.cc b/ash/shelf/app_list_button.cc
index bdda4de..3d37e025 100644
--- a/ash/shelf/app_list_button.cc
+++ b/ash/shelf/app_list_button.cc
@@ -12,6 +12,7 @@
 #include "ash/assistant/assistant_controller.h"
 #include "ash/assistant/assistant_ui_controller.h"
 #include "ash/assistant/model/assistant_ui_model.h"
+#include "ash/home_screen/home_screen_controller.h"
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/session/session_controller.h"
 #include "ash/shelf/assistant_overlay.h"
@@ -52,10 +53,8 @@
 constexpr uint8_t kVoiceInteractionRunningAlpha = 255;     // 100% alpha
 constexpr uint8_t kVoiceInteractionNotRunningAlpha = 138;  // 54% alpha
 
-bool IsTabletMode() {
-  return Shell::Get()
-      ->tablet_mode_controller()
-      ->IsTabletModeWindowManagerEnabled();
+bool IsHomeScreenAvailable() {
+  return Shell::Get()->home_screen_controller()->IsHomeScreenAvailable();
 }
 
 }  // namespace
@@ -97,9 +96,9 @@
 }
 
 void AppListButton::OnAppListShown() {
-  // Do not show a highlight in tablet mode since the "homecher" view is always
-  // open in the background.
-  if (!IsTabletMode())
+  // Do not show a highlight if the home screen is available, since the home
+  // screen view is always open in the background.
+  if (!IsHomeScreenAvailable())
     AnimateInkDrop(views::InkDropState::ACTIVATED, nullptr);
   is_showing_app_list_ = true;
   shelf_->UpdateAutoHideState();
@@ -120,8 +119,10 @@
         assistant_overlay_->EndAnimation();
         assistant_animation_delay_timer_->Stop();
       }
-      if (!Shell::Get()->app_list_controller()->IsVisible() || IsTabletMode())
+      if (!Shell::Get()->app_list_controller()->IsVisible() ||
+          IsHomeScreenAvailable()) {
         AnimateInkDrop(views::InkDropState::ACTION_TRIGGERED, event);
+      }
 
       Button::OnGestureEvent(event);
       return;
@@ -141,8 +142,10 @@
             base::Bind(&AppListButton::StartVoiceInteractionAnimation,
                        base::Unretained(this)));
       }
-      if (!Shell::Get()->app_list_controller()->IsVisible() || IsTabletMode())
+      if (!Shell::Get()->app_list_controller()->IsVisible() ||
+          IsHomeScreenAvailable()) {
         AnimateInkDrop(views::InkDropState::ACTION_PENDING, event);
+      }
 
       Button::OnGestureEvent(event);
       // If assistant overlay animation starts, we need to make sure the event
diff --git a/ash/shell_test_api.cc b/ash/shell_test_api.cc
index 1cdbdda8..f1d0ef8 100644
--- a/ash/shell_test_api.cc
+++ b/ash/shell_test_api.cc
@@ -131,15 +131,4 @@
   ui::GestureConfiguration::GetInstance()->set_min_fling_velocity(velocity);
 }
 
-void ShellTestApi::GetChildWindowCountInContainer(
-    int container_id,
-    GetChildWindowCountInContainerCallback cb) {
-  auto* container =
-      ash::Shell::GetPrimaryRootWindow()->GetChildById(container_id);
-  // Return an negative count to indicate that the container is invalid.
-  if (!container)
-    std::move(cb).Run(-1);
-  std::move(cb).Run(container->children().size());
-}
-
 }  // namespace ash
diff --git a/ash/shell_test_api.h b/ash/shell_test_api.h
index a68e97e..97f815b 100644
--- a/ash/shell_test_api.h
+++ b/ash/shell_test_api.h
@@ -63,9 +63,6 @@
   void ToggleOverviewMode(ToggleOverviewModeCallback cb) override;
   void AddRemoveDisplay() override;
   void SetMinFlingVelocity(float velocity) override;
-  void GetChildWindowCountInContainer(
-      int container_id,
-      GetChildWindowCountInContainerCallback cb) override;
 
  private:
   Shell* shell_;  // not owned
diff --git a/ash/system/power/power_button_controller_unittest.cc b/ash/system/power/power_button_controller_unittest.cc
index 9a796c5..0bcab3b 100644
--- a/ash/system/power/power_button_controller_unittest.cc
+++ b/ash/system/power/power_button_controller_unittest.cc
@@ -28,7 +28,6 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "chromeos/dbus/fake_power_manager_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
 #include "chromeos/dbus/power_manager/suspend.pb.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/display/test/display_manager_test_api.h"
@@ -402,7 +401,7 @@
   PressLockButton();
   ReleaseLockButton();
   EXPECT_TRUE(lock_state_test_api_->is_animating_lock());
-  EXPECT_EQ(1, session_manager_client_->request_lock_screen_call_count());
+  EXPECT_TRUE(GetLockedState());
 }
 
 // Tests press lock/power button before release power/lock button.
@@ -417,7 +416,7 @@
   ReleaseLockButton();
   ReleasePowerButton();
   EXPECT_FALSE(lock_state_test_api_->is_animating_lock());
-  EXPECT_EQ(0, session_manager_client_->request_lock_screen_call_count());
+  EXPECT_FALSE(GetLockedState());
   EXPECT_TRUE(power_manager_client()->backlights_forced_off());
 
   // Turn the screen on.
@@ -430,7 +429,7 @@
   ReleasePowerButton();
   ReleaseLockButton();
   EXPECT_TRUE(lock_state_test_api_->is_animating_lock());
-  EXPECT_EQ(1, session_manager_client_->request_lock_screen_call_count());
+  EXPECT_TRUE(GetLockedState());
   EXPECT_FALSE(power_manager_client()->backlights_forced_off());
 }
 
diff --git a/ash/system/power/power_button_test_base.cc b/ash/system/power/power_button_test_base.cc
index 4a3de7ab..2a78c90 100644
--- a/ash/system/power/power_button_test_base.cc
+++ b/ash/system/power/power_button_test_base.cc
@@ -17,9 +17,7 @@
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "base/test/simple_test_tick_clock.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_power_manager_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
 #include "ui/events/event.h"
 #include "ui/events/test/event_generator.h"
 
@@ -30,12 +28,6 @@
 PowerButtonTestBase::~PowerButtonTestBase() = default;
 
 void PowerButtonTestBase::SetUp() {
-  // This also initializes DBusThreadManager.
-  std::unique_ptr<chromeos::DBusThreadManagerSetter> dbus_setter =
-      chromeos::DBusThreadManager::GetSetterForTesting();
-  session_manager_client_ = new chromeos::FakeSessionManagerClient;
-  dbus_setter->SetSessionManagerClient(
-      base::WrapUnique(session_manager_client_));
   AshTestBase::SetUp();
 
   lock_state_controller_ = Shell::Get()->lock_state_controller();
@@ -45,7 +37,6 @@
 
 void PowerButtonTestBase::TearDown() {
   AshTestBase::TearDown();
-  chromeos::DBusThreadManager::Shutdown();
 }
 
 void PowerButtonTestBase::ResetPowerButtonController() {
diff --git a/ash/system/power/power_button_test_base.h b/ash/system/power/power_button_test_base.h
index b2a37eb..823b70a 100644
--- a/ash/system/power/power_button_test_base.h
+++ b/ash/system/power/power_button_test_base.h
@@ -12,10 +12,6 @@
 #include "base/test/simple_test_tick_clock.h"
 #include "ui/events/keycodes/keyboard_codes_posix.h"
 
-namespace chromeos {
-class FakeSessionManagerClient;
-}  // namespace chromeos
-
 namespace ash {
 
 class LockStateController;
@@ -84,9 +80,6 @@
   // they come too close.
   void AdvanceClockToAvoidIgnoring();
 
-  // Ownership is passed on to chromeos::DBusThreadManager.
-  chromeos::FakeSessionManagerClient* session_manager_client_ = nullptr;
-
   PowerButtonController* power_button_controller_ = nullptr;  // Not owned.
   LockStateController* lock_state_controller_ = nullptr;      // Not owned.
   PowerButtonScreenshotController* screenshot_controller_ =
diff --git a/ash/wm/lock_state_controller.cc b/ash/wm/lock_state_controller.cc
index 44395df..7120da1 100644
--- a/ash/wm/lock_state_controller.cc
+++ b/ash/wm/lock_state_controller.cc
@@ -30,8 +30,6 @@
 #include "base/strings/string_util.h"
 #include "base/system/sys_info.h"
 #include "base/timer/timer.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/views/controls/menu/menu_controller.h"
 #include "ui/wm/core/compound_event_filter.h"
@@ -506,9 +504,7 @@
       base::RecordAction(
           base::UserMetricsAction("Accel_LockScreen_LockButton"));
     }
-    chromeos::DBusThreadManager::Get()
-        ->GetSessionManagerClient()
-        ->RequestLockScreen();
+    Shell::Get()->session_controller()->LockScreen();
   }
 
   lock_fail_timer_.Start(FROM_HERE, kLockFailTimeout, this,
diff --git a/ash/wm/lock_state_controller_unittest.cc b/ash/wm/lock_state_controller_unittest.cc
index e6620ba..1a78300 100644
--- a/ash/wm/lock_state_controller_unittest.cc
+++ b/ash/wm/lock_state_controller_unittest.cc
@@ -26,7 +26,6 @@
 #include "base/run_loop.h"
 #include "base/time/time.h"
 #include "chromeos/dbus/fake_power_manager_client.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
 #include "ui/display/manager/display_configurator.h"
 #include "ui/display/manager/fake_display_snapshot.h"
 #include "ui/display/types/display_constants.h"
@@ -316,13 +315,12 @@
   test_animator_->CompleteAllAnimations(true);
   ExpectPreLockAnimationFinished();
 
-  EXPECT_EQ(1, session_manager_client_->request_lock_screen_call_count());
-
   // Notify that we locked successfully.
   lock_state_controller_->OnStartingLock();
   EXPECT_EQ(0u, test_animator_->GetAnimationCount());
 
-  LockScreen();
+  Shell::Get()->session_controller()->FlushMojoForTest();
+  EXPECT_TRUE(Shell::Get()->session_controller()->IsScreenLocked());
 
   ExpectPostLockAnimationStarted();
   test_animator_->CompleteAllAnimations(true);
@@ -443,7 +441,7 @@
   PressLockButton();
   EXPECT_FALSE(lock_state_test_api_->is_animating_lock());
   ReleaseLockButton();
-  EXPECT_EQ(0, session_manager_client_->request_lock_screen_call_count());
+  EXPECT_FALSE(Shell::Get()->session_controller()->IsScreenLocked());
 }
 
 // Test the basic operation of the lock button (guest).
@@ -454,7 +452,7 @@
   PressLockButton();
   EXPECT_FALSE(lock_state_test_api_->is_animating_lock());
   ReleaseLockButton();
-  EXPECT_EQ(0, session_manager_client_->request_lock_screen_call_count());
+  EXPECT_FALSE(Shell::Get()->session_controller()->IsScreenLocked());
 }
 
 // Test the basic operation of the lock button.
@@ -474,14 +472,16 @@
   Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
 
   ExpectUnlockedState();
-  EXPECT_EQ(0, session_manager_client_->request_lock_screen_call_count());
+  EXPECT_FALSE(Shell::Get()->session_controller()->IsScreenLocked());
 
   // Press the button again and let the lock timeout fire.  We should request
   // that the screen be locked.
   PressLockButton();
   ExpectPreLockAnimationStarted();
   Advance(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE);
-  EXPECT_EQ(1, session_manager_client_->request_lock_screen_call_count());
+
+  Shell::Get()->session_controller()->FlushMojoForTest();
+  EXPECT_TRUE(Shell::Get()->session_controller()->IsScreenLocked());
 
   // Pressing the lock button while we have a pending lock request shouldn't do
   // anything.
@@ -491,7 +491,6 @@
   ReleaseLockButton();
 
   // Pressing the button also shouldn't do anything after the screen is locked.
-  LockScreen();
   ExpectPostLockAnimationStarted();
 
   PressLockButton();
@@ -518,7 +517,7 @@
   EXPECT_LT(0u, test_animator_->GetAnimationCount());
 
   test_animator_->CompleteAllAnimations(true);
-  EXPECT_EQ(0, session_manager_client_->request_lock_screen_call_count());
+  EXPECT_FALSE(Shell::Get()->session_controller()->IsScreenLocked());
 }
 
 // When we hear that the process is exiting but we haven't had a chance to
diff --git a/ash/wm/overview/caption_container_view.cc b/ash/wm/overview/caption_container_view.cc
index 9c67eb8..2c0964a 100644
--- a/ash/wm/overview/caption_container_view.cc
+++ b/ash/wm/overview/caption_container_view.cc
@@ -7,8 +7,6 @@
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/wm/overview/overview_constants.h"
-#include "ash/wm/overview/overview_item.h"
-#include "ash/wm/overview/overview_utils.h"
 #include "ash/wm/overview/rounded_rect_view.h"
 #include "ash/wm/overview/scoped_overview_animation_settings.h"
 #include "ash/wm/splitview/split_view_constants.h"
@@ -42,11 +40,6 @@
 // title.
 constexpr gfx::Size kIconSize{24, 24};
 
-// The amount we need to offset the close button so that the icon, which is
-// smaller than the actual button is lined up with the right side of the window
-// preview.
-constexpr int kCloseButtonOffsetDp = 8;
-
 constexpr int kCloseButtonInkDropInsetDp = 2;
 
 constexpr SkColor kCloseButtonColor = SK_ColorWHITE;
@@ -70,13 +63,20 @@
   parent->AddChildView(child);
 }
 
+gfx::PointF ConvertToScreen(views::View* view, const gfx::Point& location) {
+  gfx::Point location_copy(location);
+  views::View::ConvertPointToScreen(view, &location_copy);
+  return gfx::PointF(location_copy);
+}
+
 }  // namespace
 
 // The close button for the caption container view. It has a custom ink drop.
 class CaptionContainerView::OverviewCloseButton : public views::ImageButton {
  public:
-  explicit OverviewCloseButton(views::ButtonListener* listener)
-      : views::ImageButton(listener) {
+  explicit OverviewCloseButton(
+      CaptionContainerView::EventDelegate* event_delegate)
+      : views::ImageButton(nullptr), event_delegate_(event_delegate) {
     SetInkDropMode(InkDropMode::ON_NO_GESTURE_HANDLER);
     SetImage(
         views::Button::STATE_NORMAL,
@@ -91,7 +91,7 @@
   ~OverviewCloseButton() override = default;
 
   // Resets the listener so that the listener can go out of scope.
-  void ResetListener() { listener_ = nullptr; }
+  void ResetEventDelegate() { event_delegate_ = nullptr; }
 
  protected:
   // views::Button:
@@ -118,6 +118,10 @@
     return std::make_unique<views::CircleInkDropMask>(
         size(), GetLocalBounds().CenterPoint(), GetInkDropRadius());
   }
+  void NotifyClick(const ui::Event& event) override {
+    if (event_delegate_)
+      event_delegate_->HandleCloseButtonClicked();
+  }
 
  private:
   int GetInkDropRadius() const {
@@ -125,123 +129,25 @@
            kCloseButtonInkDropInsetDp;
   }
 
+  CaptionContainerView::EventDelegate* event_delegate_;
+
   DISALLOW_COPY_AND_ASSIGN(OverviewCloseButton);
 };
 
-// A Button that has a listener and listens to mouse / gesture events on the
-// visible part of an overview window.
-class CaptionContainerView::ShieldButton : public views::Button {
- public:
-  ShieldButton(views::ButtonListener* listener, const base::string16& name)
-      : views::Button(listener) {
-    // The shield button should not be focusable. It's also to avoid
-    // accessibility error when |name| is empty.
-    SetFocusBehavior(FocusBehavior::NEVER);
-    SetAccessibleName(name);
-  }
-  ~ShieldButton() override = default;
-
-  // When OverviewItem (which is a ButtonListener) is destroyed, its
-  // |item_widget_| is allowed to stay around to complete any animations.
-  // Resetting the listener in all views that are targeted by events is
-  // necessary to prevent a crash when a user clicks on the fading out widget
-  // after the OverviewItem has been destroyed.
-  void ResetListener() { listener_ = nullptr; }
-
-  // views::View:
-  bool OnMousePressed(const ui::MouseEvent& event) override {
-    if (listener()) {
-      gfx::Point location(event.location());
-      views::View::ConvertPointToScreen(this, &location);
-      listener()->HandlePressEvent(gfx::PointF(location));
-      return true;
-    }
-    return views::Button::OnMousePressed(event);
-  }
-
-  bool OnMouseDragged(const ui::MouseEvent& event) override {
-    if (listener()) {
-      gfx::Point location(event.location());
-      views::View::ConvertPointToScreen(this, &location);
-      listener()->HandleDragEvent(gfx::PointF(location));
-      return true;
-    }
-    return views::Button::OnMouseDragged(event);
-  }
-
-  void OnMouseReleased(const ui::MouseEvent& event) override {
-    if (listener()) {
-      gfx::Point location(event.location());
-      views::View::ConvertPointToScreen(this, &location);
-      listener()->HandleReleaseEvent(gfx::PointF(location));
-      return;
-    }
-    views::Button::OnMouseReleased(event);
-  }
-
-  void OnGestureEvent(ui::GestureEvent* event) override {
-    if (IsSlidingOutOverviewFromShelf()) {
-      event->SetHandled();
-      return;
-    }
-
-    if (listener()) {
-      const gfx::PointF location =
-          event->details().bounding_box_f().CenterPoint();
-      switch (event->type()) {
-        case ui::ET_GESTURE_TAP_DOWN:
-          listener()->HandlePressEvent(location);
-          break;
-        case ui::ET_GESTURE_SCROLL_UPDATE:
-          listener()->HandleDragEvent(location);
-          break;
-        case ui::ET_SCROLL_FLING_START:
-          listener()->HandleFlingStartEvent(location,
-                                            event->details().velocity_x(),
-                                            event->details().velocity_y());
-          break;
-        case ui::ET_GESTURE_SCROLL_END:
-          listener()->HandleReleaseEvent(location);
-          break;
-        case ui::ET_GESTURE_LONG_PRESS:
-          listener()->HandleLongPressEvent(location);
-          break;
-        case ui::ET_GESTURE_TAP:
-          listener()->ActivateDraggedWindow();
-          break;
-        case ui::ET_GESTURE_END:
-          listener()->ResetDraggedWindowGesture();
-          break;
-        default:
-          break;
-      }
-      event->SetHandled();
-      return;
-    }
-    views::Button::OnGestureEvent(event);
-  }
-
-  OverviewItem* listener() { return static_cast<OverviewItem*>(listener_); }
-
- protected:
-  // views::View:
-  const char* GetClassName() const override { return "ShieldButton"; }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ShieldButton);
-};
-
-CaptionContainerView::CaptionContainerView(views::ButtonListener* listener,
-                                           aura::Window* window) {
-  listener_button_ = new ShieldButton(listener, window->GetTitle());
-  AddChildView(listener_button_);
+CaptionContainerView::CaptionContainerView(EventDelegate* event_delegate,
+                                           aura::Window* window)
+    : Button(nullptr), event_delegate_(event_delegate) {
+  // This should not be focusable. It's also to avoid accessibility error when
+  // |window->GetTitle()| is empty.
+  SetFocusBehavior(FocusBehavior::NEVER);
+  SetAccessibleName(window->GetTitle());
 
   header_view_ = new views::View();
   views::BoxLayout* layout =
       header_view_->SetLayoutManager(std::make_unique<views::BoxLayout>(
           views::BoxLayout::kHorizontal, gfx::Insets(),
           kHorizontalLabelPaddingDp));
-  AddChildWithLayer(listener_button_, header_view_);
+  AddChildWithLayer(this, header_view_);
 
   // Prefer kAppIconSmallKey (set by the client in Mash), then kAppIconKey and
   // kWindowIconKey (set for client windows in classic Ash but not Mash).
@@ -268,7 +174,7 @@
   header_view_->AddChildView(title_label_);
   layout->SetFlexForView(title_label_, 1);
 
-  close_button_ = new OverviewCloseButton(listener);
+  close_button_ = new OverviewCloseButton(event_delegate);
   AddChildWithLayer(header_view_, close_button_);
 }
 
@@ -336,18 +242,14 @@
                                   : SPLITVIEW_ANIMATION_OVERVIEW_ITEM_FADE_OUT);
 }
 
-void CaptionContainerView::ResetListener() {
-  listener_button_->ResetListener();
-  close_button_->ResetListener();
+void CaptionContainerView::ResetEventDelegate() {
+  event_delegate_ = nullptr;
+  close_button_->ResetEventDelegate();
 }
 
 void CaptionContainerView::SetTitle(const base::string16& title) {
   title_label_->SetText(title);
-  listener_button_->SetAccessibleName(title);
-}
-
-views::View* CaptionContainerView::GetListenerButton() {
-  return listener_button_;
+  SetAccessibleName(title);
 }
 
 views::ImageButton* CaptionContainerView::GetCloseButton() {
@@ -357,7 +259,6 @@
 void CaptionContainerView::Layout() {
   gfx::Rect bounds(GetLocalBounds());
   bounds.Inset(kOverviewMargin, kOverviewMargin);
-  listener_button_->SetBoundsRect(bounds);
 
   const int visible_height = close_button_->GetPreferredSize().height();
   if (backdrop_view_) {
@@ -382,12 +283,10 @@
     cannot_snap_container_->SetBoundsRect(cannot_snap_bounds);
   }
 
-  // Position the header at the top. The right side of the header should be
-  // positioned so that the rightmost of the close icon matches the right side
-  // of the window preview.
-  gfx::Rect header_bounds = GetLocalBounds();
-  header_bounds.Inset(0, 0, kCloseButtonOffsetDp, 0);
-  header_bounds.set_height(visible_height);
+  // Position the header at the top.
+  const gfx::Rect header_bounds(kOverviewMargin, kOverviewMargin,
+                                GetLocalBounds().width() - kOverviewMargin,
+                                visible_height);
   header_view_->SetBoundsRect(header_bounds);
 }
 
@@ -395,6 +294,84 @@
   return "CaptionContainerView";
 }
 
+bool CaptionContainerView::OnMousePressed(const ui::MouseEvent& event) {
+  if (!event_delegate_)
+    return Button::OnMousePressed(event);
+  event_delegate_->HandlePressEvent(ConvertToScreen(this, event.location()));
+  return true;
+}
+
+bool CaptionContainerView::OnMouseDragged(const ui::MouseEvent& event) {
+  if (!event_delegate_)
+    return Button::OnMouseDragged(event);
+  event_delegate_->HandleDragEvent(ConvertToScreen(this, event.location()));
+  return true;
+}
+
+void CaptionContainerView::OnMouseReleased(const ui::MouseEvent& event) {
+  if (!event_delegate_) {
+    Button::OnMouseReleased(event);
+    return;
+  }
+  event_delegate_->HandleReleaseEvent(ConvertToScreen(this, event.location()));
+}
+
+void CaptionContainerView::OnGestureEvent(ui::GestureEvent* event) {
+  if (!event_delegate_)
+    return;
+
+  if (event_delegate_->ShouldIgnoreGestureEvents()) {
+    event->SetHandled();
+    return;
+  }
+
+  const gfx::PointF location = event->details().bounding_box_f().CenterPoint();
+  switch (event->type()) {
+    case ui::ET_GESTURE_TAP_DOWN:
+      event_delegate_->HandlePressEvent(location);
+      break;
+    case ui::ET_GESTURE_SCROLL_UPDATE:
+      event_delegate_->HandleDragEvent(location);
+      break;
+    case ui::ET_SCROLL_FLING_START:
+      event_delegate_->HandleFlingStartEvent(location,
+                                             event->details().velocity_x(),
+                                             event->details().velocity_y());
+      break;
+    case ui::ET_GESTURE_SCROLL_END:
+      event_delegate_->HandleReleaseEvent(location);
+      break;
+    case ui::ET_GESTURE_LONG_PRESS:
+      event_delegate_->HandleLongPressEvent(location);
+      break;
+    case ui::ET_GESTURE_TAP:
+      event_delegate_->HandleTapEvent();
+      break;
+    case ui::ET_GESTURE_END:
+      event_delegate_->HandleGestureEndEvent();
+      break;
+    default:
+      break;
+  }
+  event->SetHandled();
+}
+
+bool CaptionContainerView::CanAcceptEvent(const ui::Event& event) {
+  bool accept_events = true;
+  // Do not process or accept press down events that are on the border.
+  static ui::EventType press_types[] = {ui::ET_GESTURE_TAP_DOWN,
+                                        ui::ET_MOUSE_PRESSED};
+  if (event.IsLocatedEvent() &&
+      base::ContainsValue(press_types, event.type())) {
+    gfx::Rect inset_bounds = GetLocalBounds();
+    inset_bounds.Inset(gfx::Insets(kOverviewMargin));
+    if (!inset_bounds.Contains(event.AsLocatedEvent()->location()))
+      accept_events = false;
+  }
+
+  return accept_events && Button::CanAcceptEvent(event);
+}
+
 void CaptionContainerView::AnimateLayerOpacity(ui::Layer* layer, bool visible) {
   float target_opacity = visible ? 1.f : 0.f;
   if (layer->GetTargetOpacity() == target_opacity)
diff --git a/ash/wm/overview/caption_container_view.h b/ash/wm/overview/caption_container_view.h
index 5b711de1..582e68bd 100644
--- a/ash/wm/overview/caption_container_view.h
+++ b/ash/wm/overview/caption_container_view.h
@@ -7,8 +7,7 @@
 
 #include "ash/ash_export.h"
 #include "base/macros.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/views/view.h"
+#include "ui/views/controls/button/button.h"
 
 namespace aura {
 class Window;
@@ -19,10 +18,10 @@
 }  // namespace ui
 
 namespace views {
-class ButtonListener;
 class ImageButton;
 class ImageView;
 class Label;
+class View;
 }  // namespace views
 
 namespace ash {
@@ -33,7 +32,7 @@
 // also draws a header for overview mode which contains a icon, title and close
 // button.
 // TODO(sammiequon): Rename this to something which describes it better.
-class ASH_EXPORT CaptionContainerView : public views::View {
+class ASH_EXPORT CaptionContainerView : public views::Button {
  public:
   // The visibility of the header. It may be fully visible or invisible, or
   // everything but the close button is visible.
@@ -43,7 +42,27 @@
     kVisible,
   };
 
-  CaptionContainerView(views::ButtonListener* listener, aura::Window* window);
+  class EventDelegate {
+   public:
+    // TODO: Maybe consolidate into just mouse and gesture events.
+    virtual void HandlePressEvent(const gfx::PointF& location_in_screen) = 0;
+    virtual void HandleDragEvent(const gfx::PointF& location_in_screen) = 0;
+    virtual void HandleReleaseEvent(const gfx::PointF& location_in_screen) = 0;
+    virtual void HandleFlingStartEvent(const gfx::PointF& location_in_screen,
+                                       float velocity_x,
+                                       float velocity_y) = 0;
+    virtual void HandleLongPressEvent(
+        const gfx::PointF& location_in_screen) = 0;
+    virtual void HandleTapEvent() = 0;
+    virtual void HandleGestureEndEvent() = 0;
+    virtual void HandleCloseButtonClicked() = 0;
+    virtual bool ShouldIgnoreGestureEvents() = 0;
+
+   protected:
+    virtual ~EventDelegate() {}
+  };
+
+  CaptionContainerView(EventDelegate* event_delegate, aura::Window* window);
   ~CaptionContainerView() override;
 
   // Returns |cannot_snap_container_|. This will create it if it has not been
@@ -58,12 +77,11 @@
   // Animates |cannot_snap_container_| to its visibility state.
   void SetCannotSnapLabelVisibility(bool visible);
 
-  void ResetListener();
+  void ResetEventDelegate();
 
   // Set the title of the view, and also updates the accessiblity name.
   void SetTitle(const base::string16& title);
 
-  views::View* GetListenerButton();
   views::ImageButton* GetCloseButton();
 
   views::View* header_view() { return header_view_; }
@@ -75,10 +93,14 @@
   // views::View:
   void Layout() override;
   const char* GetClassName() const override;
+  bool OnMousePressed(const ui::MouseEvent& event) override;
+  bool OnMouseDragged(const ui::MouseEvent& event) override;
+  void OnMouseReleased(const ui::MouseEvent& event) override;
+  void OnGestureEvent(ui::GestureEvent* event) override;
+  bool CanAcceptEvent(const ui::Event& event) override;
 
  private:
   class OverviewCloseButton;
-  class ShieldButton;
 
   // Animates |layer| from 0 -> 1 opacity if |visible| and 1 -> 0 opacity
   // otherwise. The tween type differs for |visible| and if |visible| is true
@@ -86,8 +108,8 @@
   // opacity matches |visible|.
   void AnimateLayerOpacity(ui::Layer* layer, bool visible);
 
-  // |listener_button_| handles input events and notifies the button listener.
-  ShieldButton* listener_button_ = nullptr;
+  // The delegate which all the events get forwarded to.
+  EventDelegate* event_delegate_;
 
   // View which contains the icon, title and close button.
   views::View* header_view_ = nullptr;
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc
index 79026bd..b103fa98 100644
--- a/ash/wm/overview/overview_item.cc
+++ b/ash/wm/overview/overview_item.cc
@@ -10,7 +10,6 @@
 #include "ash/public/cpp/window_properties.h"
 #include "ash/scoped_animation_disabler.h"
 #include "ash/shell.h"
-#include "ash/wm/overview/caption_container_view.h"
 #include "ash/wm/overview/overview_animation_type.h"
 #include "ash/wm/overview/overview_constants.h"
 #include "ash/wm/overview/overview_controller.h"
@@ -106,14 +105,18 @@
       overview_session_(overview_session),
       overview_grid_(overview_grid) {
   CreateWindowLabel();
-  for (auto* window_iter : wm::GetTransientTreeIterator(GetWindow()))
+  for (auto* window_iter : wm::WindowTransientDescendantIteratorRange(
+           wm::WindowTransientDescendantIterator(GetWindow()))) {
     window_iter->AddObserver(this);
+  }
   GetWindow()->SetProperty(ash::kIsShowingInOverviewKey, true);
 }
 
 OverviewItem::~OverviewItem() {
-  for (auto* window_iter : wm::GetTransientTreeIterator(GetWindow()))
+  for (auto* window_iter : wm::WindowTransientDescendantIteratorRange(
+           wm::WindowTransientDescendantIterator(GetWindow()))) {
     window_iter->RemoveObserver(this);
+  }
   GetWindow()->ClearProperty(ash::kIsShowingInOverviewKey);
 }
 
@@ -136,7 +139,7 @@
 }
 
 void OverviewItem::RestoreWindow(bool reset_transform) {
-  caption_container_view_->ResetListener();
+  caption_container_view_->ResetEventDelegate();
   transform_window_.RestoreWindow(
       reset_transform, overview_session_->enter_exit_overview_type());
 }
@@ -285,7 +288,7 @@
 }
 
 void OverviewItem::SendAccessibleSelectionEvent() {
-  caption_container_view_->GetListenerButton()->NotifyAccessibilityEvent(
+  caption_container_view_->NotifyAccessibilityEvent(
       ax::mojom::Event::kSelection, true);
 }
 
@@ -294,7 +297,7 @@
 
   animating_to_close_ = true;
   overview_session_->PositionWindows(/*animate=*/true);
-  caption_container_view_->ResetListener();
+  caption_container_view_->ResetEventDelegate();
 
   int translation_y = kSwipeToCloseCloseTranslationDp * (up ? -1 : 1);
   gfx::Transform transform;
@@ -411,61 +414,6 @@
   SetBounds(scaled_bounds, animation_type);
 }
 
-void OverviewItem::HandlePressEvent(const gfx::PointF& location_in_screen) {
-  // We allow switching finger while dragging, but do not allow dragging two or
-  // more items.
-  if (overview_session_->window_drag_controller() &&
-      overview_session_->window_drag_controller()->item()) {
-    return;
-  }
-
-  StartDrag();
-  overview_session_->InitiateDrag(this, location_in_screen);
-}
-
-void OverviewItem::HandleReleaseEvent(const gfx::PointF& location_in_screen) {
-  if (!IsDragItem())
-    return;
-
-  overview_grid_->SetSelectionWidgetVisibility(true);
-  overview_session_->CompleteDrag(this, location_in_screen);
-}
-
-void OverviewItem::HandleDragEvent(const gfx::PointF& location_in_screen) {
-  if (!IsDragItem())
-    return;
-
-  overview_session_->Drag(this, location_in_screen);
-}
-
-void OverviewItem::HandleLongPressEvent(const gfx::PointF& location_in_screen) {
-  if (!ShouldAllowSplitView())
-    return;
-
-  overview_session_->StartSplitViewDragMode(location_in_screen);
-}
-
-void OverviewItem::HandleFlingStartEvent(const gfx::PointF& location_in_screen,
-                                         float velocity_x,
-                                         float velocity_y) {
-  overview_session_->Fling(this, location_in_screen, velocity_x, velocity_y);
-}
-
-void OverviewItem::ActivateDraggedWindow() {
-  if (!IsDragItem())
-    return;
-
-  overview_session_->ActivateDraggedWindow();
-}
-
-void OverviewItem::ResetDraggedWindowGesture() {
-  if (!IsDragItem())
-    return;
-
-  OnSelectorItemDragEnded();
-  overview_session_->ResetDraggedWindowGesture();
-}
-
 bool OverviewItem::IsDragItem() {
   return overview_session_->window_drag_controller() &&
          overview_session_->window_drag_controller()->item() == this;
@@ -606,29 +554,78 @@
                                       : OVERVIEW_ANIMATION_RESTORE_WINDOW_ZERO;
 }
 
-void OverviewItem::ButtonPressed(views::Button* sender,
-                                 const ui::Event& event) {
-  if (IsSlidingOutOverviewFromShelf())
-    return;
-
-  if (sender == caption_container_view_->GetCloseButton()) {
-    base::RecordAction(
-        base::UserMetricsAction("WindowSelector_OverviewCloseButton"));
-    if (Shell::Get()
-            ->tablet_mode_controller()
-            ->IsTabletModeWindowManagerEnabled()) {
-      base::RecordAction(
-          base::UserMetricsAction("Tablet_WindowCloseFromOverviewButton"));
-    }
-    CloseWindow();
+void OverviewItem::HandlePressEvent(const gfx::PointF& location_in_screen) {
+  // We allow switching finger while dragging, but do not allow dragging two or
+  // more items.
+  if (overview_session_->window_drag_controller() &&
+      overview_session_->window_drag_controller()->item()) {
     return;
   }
 
-  CHECK_EQ(sender, caption_container_view_->GetListenerButton());
+  StartDrag();
+  overview_session_->InitiateDrag(this, location_in_screen);
+}
 
-  // For other cases, the event is handled in OverviewWindowDragController.
+void OverviewItem::HandleReleaseEvent(const gfx::PointF& location_in_screen) {
+  if (!IsDragItem())
+    return;
+
+  overview_grid_->SetSelectionWidgetVisibility(true);
+  overview_session_->CompleteDrag(this, location_in_screen);
+}
+
+void OverviewItem::HandleDragEvent(const gfx::PointF& location_in_screen) {
+  if (!IsDragItem())
+    return;
+
+  overview_session_->Drag(this, location_in_screen);
+}
+
+void OverviewItem::HandleLongPressEvent(const gfx::PointF& location_in_screen) {
   if (!ShouldAllowSplitView())
-    overview_session_->SelectWindow(this);
+    return;
+
+  overview_session_->StartSplitViewDragMode(location_in_screen);
+}
+
+void OverviewItem::HandleFlingStartEvent(const gfx::PointF& location_in_screen,
+                                         float velocity_x,
+                                         float velocity_y) {
+  overview_session_->Fling(this, location_in_screen, velocity_x, velocity_y);
+}
+
+void OverviewItem::HandleTapEvent() {
+  if (!IsDragItem())
+    return;
+
+  overview_session_->ActivateDraggedWindow();
+}
+
+void OverviewItem::HandleGestureEndEvent() {
+  if (!IsDragItem())
+    return;
+
+  OnSelectorItemDragEnded();
+  overview_session_->ResetDraggedWindowGesture();
+}
+
+void OverviewItem::HandleCloseButtonClicked() {
+  if (IsSlidingOutOverviewFromShelf())
+    return;
+
+  base::RecordAction(
+      base::UserMetricsAction("WindowSelector_OverviewCloseButton"));
+  if (Shell::Get()
+          ->tablet_mode_controller()
+          ->IsTabletModeWindowManagerEnabled()) {
+    base::RecordAction(
+        base::UserMetricsAction("Tablet_WindowCloseFromOverviewButton"));
+  }
+  CloseWindow();
+}
+
+bool OverviewItem::ShouldIgnoreGestureEvents() {
+  return IsSlidingOutOverviewFromShelf();
 }
 
 void OverviewItem::OnWindowBoundsChanged(aura::Window* window,
@@ -719,21 +716,21 @@
 }
 
 void OverviewItem::CreateWindowLabel() {
-  views::Widget::InitParams params_label;
-  params_label.type = views::Widget::InitParams::TYPE_POPUP;
-  params_label.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  params_label.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
-  params_label.visible_on_all_workspaces = true;
-  params_label.layer_type = ui::LAYER_NOT_DRAWN;
-  params_label.name = "OverviewModeLabel";
-  params_label.activatable =
+  views::Widget::InitParams params;
+  params.type = views::Widget::InitParams::TYPE_POPUP;
+  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
+  params.visible_on_all_workspaces = true;
+  params.layer_type = ui::LAYER_NOT_DRAWN;
+  params.name = "OverviewModeLabel";
+  params.activatable =
       views::Widget::InitParams::Activatable::ACTIVATABLE_DEFAULT;
-  params_label.accept_events = true;
-  params_label.parent = transform_window_.window()->parent();
+  params.accept_events = true;
+  params.parent = transform_window_.window()->parent();
 
   item_widget_ = std::make_unique<views::Widget>();
   item_widget_->set_focus_on_creation(false);
-  item_widget_->Init(params_label);
+  item_widget_->Init(params);
   aura::Window* widget_window = item_widget_->GetNativeWindow();
   widget_window->parent()->StackChildBelow(widget_window,
                                            transform_window_.window());
@@ -756,16 +753,9 @@
           transform_window_.GetTransformedBounds());
   ::wm::TranslateRectFromScreen(root_window_, &transformed_window_bounds);
 
-  gfx::Rect label_rect(kHeaderHeightDp, kHeaderHeightDp);
-  label_rect.set_width(transformed_window_bounds.width());
-  // For tabbed windows the initial bounds of the caption are set such that it
-  // appears to be "growing" up from the window content area.
-  label_rect.set_y(-label_rect.height());
-
   aura::Window* widget_window = item_widget_->GetNativeWindow();
   ScopedOverviewAnimationSettings animation_settings(animation_type,
                                                      widget_window);
-
   // Create a start animation observer if this is an enter overview layout
   // animation.
   if (animation_type == OVERVIEW_ANIMATION_LAYOUT_OVERVIEW_ITEMS_ON_ENTER) {
@@ -775,12 +765,13 @@
         std::move(start_observer));
   }
 
-  // |widget_window| covers both the transformed window and the header
-  // as well as the gap between the windows to prevent events from reaching
-  // the window including its sizing borders.
-  label_rect.set_height(kHeaderHeightDp + transformed_window_bounds.height());
+  // |widget_window| is sized to the same bounds as the original window plus
+  // some space for the header and a little padding.
+  gfx::Rect label_rect(0, -kHeaderHeightDp, transformed_window_bounds.width(),
+                       kHeaderHeightDp + transformed_window_bounds.height());
   label_rect.Inset(-kOverviewMargin, -kOverviewMargin);
   widget_window->SetBounds(label_rect);
+
   gfx::Transform label_transform;
   label_transform.Translate(gfx::ToRoundedInt(transformed_window_bounds.x()),
                             gfx::ToRoundedInt(transformed_window_bounds.y()));
diff --git a/ash/wm/overview/overview_item.h b/ash/wm/overview/overview_item.h
index f16f768..5a5bd73 100644
--- a/ash/wm/overview/overview_item.h
+++ b/ash/wm/overview/overview_item.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "ash/ash_export.h"
+#include "ash/wm/overview/caption_container_view.h"
 #include "ash/wm/overview/overview_session.h"
 #include "ash/wm/overview/scoped_overview_transform_window.h"
 #include "base/macros.h"
@@ -26,12 +27,10 @@
 }  // namespace views
 
 namespace ash {
-
-class CaptionContainerView;
 class OverviewGrid;
 
 // This class represents an item in overview mode.
-class ASH_EXPORT OverviewItem : public views::ButtonListener,
+class ASH_EXPORT OverviewItem : public CaptionContainerView::EventDelegate,
                                 public aura::WindowObserver,
                                 public ui::ImplicitAnimationObserver {
  public:
@@ -156,17 +155,6 @@
   // If the window item represents a minimized window, update its content view.
   void UpdateItemContentViewForMinimizedWindow();
 
-  // Handle the mouse/gesture event and facilitate dragging the item.
-  void HandlePressEvent(const gfx::PointF& location_in_screen);
-  void HandleReleaseEvent(const gfx::PointF& location_in_screen);
-  void HandleDragEvent(const gfx::PointF& location_in_screen);
-  void HandleLongPressEvent(const gfx::PointF& location_in_screen);
-  void HandleFlingStartEvent(const gfx::PointF& location_in_screen,
-                             float velocity_x,
-                             float velocity_y);
-  void ActivateDraggedWindow();
-  void ResetDraggedWindowGesture();
-
   // Checks if this item is current being dragged.
   bool IsDragItem();
 
@@ -194,8 +182,18 @@
   OverviewAnimationType GetExitOverviewAnimationType();
   OverviewAnimationType GetExitTransformAnimationType();
 
-  // views::ButtonListener:
-  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+  // CaptionContainerView::EventDelegate:
+  void HandlePressEvent(const gfx::PointF& location_in_screen) override;
+  void HandleReleaseEvent(const gfx::PointF& location_in_screen) override;
+  void HandleDragEvent(const gfx::PointF& location_in_screen) override;
+  void HandleLongPressEvent(const gfx::PointF& location_in_screen) override;
+  void HandleFlingStartEvent(const gfx::PointF& location_in_screen,
+                             float velocity_x,
+                             float velocity_y) override;
+  void HandleTapEvent() override;
+  void HandleGestureEndEvent() override;
+  void HandleCloseButtonClicked() override;
+  bool ShouldIgnoreGestureEvents() override;
 
   // aura::WindowObserver:
   void OnWindowBoundsChanged(aura::Window* window,
diff --git a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc
index b51b1f9b..4cac448 100644
--- a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc
+++ b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc
@@ -6,7 +6,7 @@
 
 #include <vector>
 
-#include "ash/app_list/app_list_controller_impl.h"
+#include "ash/home_screen/home_screen_controller.h"
 #include "ash/root_window_controller.h"
 #include "ash/scoped_animation_disabler.h"
 #include "ash/shell.h"
@@ -145,9 +145,7 @@
     }
 
     // Hide the home launcher if it's enabled during dragging.
-    // TODO(xdai): Move the hide/show home launcher logic to a general place in
-    // TabletModeWindowDragDelegate.
-    Shell::Get()->app_list_controller()->OnWindowDragStarted();
+    Shell::Get()->home_screen_controller()->OnWindowDragStarted();
 
     // Blurs the wallpaper background.
     RootWindowController::ForWindow(root_window)
@@ -188,7 +186,7 @@
     DCHECK(!Shell::Get()->overview_controller()->IsSelecting());
 
     // May reshow the home launcher after dragging.
-    Shell::Get()->app_list_controller()->OnWindowDragEnded();
+    Shell::Get()->home_screen_controller()->OnWindowDragEnded();
 
     // Clears the background wallpaper blur.
     RootWindowController::ForWindow(dragged_window_->GetRootWindow())
diff --git a/base/BUILD.gn b/base/BUILD.gn
index a2b1e0a..6379ad9 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -2808,6 +2808,7 @@
       "debug/elf_reader_unittest.cc",
       "files/dir_reader_posix_unittest.cc",
       "files/file_descriptor_watcher_posix_unittest.cc",
+      "fuchsia/file_utils_unittest.cc",
       "fuchsia/filtered_service_directory_unittest.cc",
       "fuchsia/service_directory_test_base.cc",
       "fuchsia/service_directory_test_base.h",
diff --git a/base/android/java/src/org/chromium/base/LocaleUtils.java b/base/android/java/src/org/chromium/base/LocaleUtils.java
index a993647..10d1142 100644
--- a/base/android/java/src/org/chromium/base/LocaleUtils.java
+++ b/base/android/java/src/org/chromium/base/LocaleUtils.java
@@ -195,8 +195,8 @@
     }
 
     /**
-     * @return a comma separated language tags string that represents a default locale.
-     *         Each language tag is well-formed IETF BCP 47 language tag with language and country
+     * @return a language tag string that represents the default locale.
+     *         The language tag is well-formed IETF BCP 47 language tag with language and country
      *         code.
      */
     @CalledByNative
diff --git a/base/containers/any_internal_unittest.cc b/base/containers/any_internal_unittest.cc
index dacd2ff8..2b237f7 100644
--- a/base/containers/any_internal_unittest.cc
+++ b/base/containers/any_internal_unittest.cc
@@ -4,13 +4,18 @@
 
 #include "base/containers/any_internal.h"
 
-#include <string>
-
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
 namespace internal {
 
+namespace {
+struct OutOfLineStruct {
+  void* one;
+  void* two;
+};
+}  // namespace
+
 TEST(AnyInternalTest, InlineOrOutlineStorage) {
   static_assert(AnyInternal::InlineStorageHelper<int>::kUseInlineStorage,
                 "int should be stored inline");
@@ -20,8 +25,8 @@
       AnyInternal::InlineStorageHelper<std::unique_ptr<int>>::kUseInlineStorage,
       "std::unique_ptr<int> should be stored inline");
   static_assert(
-      !AnyInternal::InlineStorageHelper<std::string>::kUseInlineStorage,
-      "std::string should be stored out of line");
+      !AnyInternal::InlineStorageHelper<OutOfLineStruct>::kUseInlineStorage,
+      "A struct with two pointers should be stored out of line");
 }
 
 }  // namespace internal
diff --git a/base/fuchsia/file_utils.cc b/base/fuchsia/file_utils.cc
index bb012b8..07e957a 100644
--- a/base/fuchsia/file_utils.cc
+++ b/base/fuchsia/file_utils.cc
@@ -4,10 +4,17 @@
 
 #include "base/fuchsia/file_utils.h"
 
+#include <fcntl.h>
 #include <lib/fdio/fd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
-#include "base/files/file.h"
+#include <utility>
+
+#include "base/files/scoped_file.h"
 #include "base/fuchsia/fuchsia_logging.h"
+#include "base/macros.h"
 
 namespace base {
 namespace fuchsia {
@@ -16,26 +23,25 @@
 const char kServiceDirectoryPath[] = "/svc";
 const char kPackageRootDirectoryPath[] = "/pkg";
 
-zx::handle GetHandleFromFile(File file) {
-  zx::handle handle;
-  zx_status_t status =
-      fdio_fd_transfer(file.GetPlatformFile(), handle.reset_and_get_address());
-  if (status != ZX_ERR_UNAVAILABLE)
-    ignore_result(file.TakePlatformFile());
-  if (status == ZX_OK)
-    return handle;
-  ZX_DLOG(ERROR, status) << "fdio_fd_transfer";
-  return zx::handle();
-}
+fidl::InterfaceHandle<::fuchsia::io::Directory> OpenDirectory(
+    const base::FilePath& path) {
+  ScopedFD fd(open(path.value().c_str(), O_DIRECTORY | O_RDONLY));
+  if (!fd.is_valid()) {
+    DPLOG(ERROR) << "Failed to open " << path;
+    return fidl::InterfaceHandle<::fuchsia::io::Directory>();
+  }
 
-base::File GetFileFromHandle(zx::handle handle) {
-  base::ScopedFD fd;
+  zx::channel channel;
   zx_status_t status =
-      fdio_fd_create(handle.release(), base::ScopedFD::Receiver(fd).get());
-  if (status == ZX_OK)
-    return base::File(fd.release());
-  ZX_LOG(WARNING, status) << "fdio_fd_create";
-  return base::File();
+      fdio_fd_transfer(fd.get(), channel.reset_and_get_address());
+  if (status != ZX_ERR_UNAVAILABLE)
+    ignore_result(fd.release());
+  if (status != ZX_OK) {
+    ZX_DLOG(ERROR, status) << "fdio_fd_transfer";
+    return fidl::InterfaceHandle<::fuchsia::io::Directory>();
+  }
+
+  return fidl::InterfaceHandle<::fuchsia::io::Directory>(std::move(channel));
 }
 
 }  // namespace fuchsia
diff --git a/base/fuchsia/file_utils.h b/base/fuchsia/file_utils.h
index 1b249929..b1df755 100644
--- a/base/fuchsia/file_utils.h
+++ b/base/fuchsia/file_utils.h
@@ -5,14 +5,12 @@
 #ifndef BASE_FUCHSIA_FILE_UTILS_H_
 #define BASE_FUCHSIA_FILE_UTILS_H_
 
-#include <lib/zx/handle.h>
+#include <fuchsia/io/cpp/fidl.h>
 
 #include "base/base_export.h"
+#include "base/files/file_path.h"
 
 namespace base {
-
-class File;
-
 namespace fuchsia {
 
 // Persisted data directory, i.e. /data . Returned as DIR_APP_DATA from
@@ -25,14 +23,10 @@
 // Package root directory, i.e. /pkg .
 BASE_EXPORT extern const char kPackageRootDirectoryPath[];
 
-// Gets a Zircon handle from a file or directory |path| in the process'
-// namespace.
-BASE_EXPORT zx::handle GetHandleFromFile(base::File file);
-
-// Makes a File object from a Zircon handle.
-// Returns an empty File if |handle| is invalid or not a valid PA_FDIO_REMOTE
-// descriptor.
-BASE_EXPORT base::File GetFileFromHandle(zx::handle handle);
+// Returns fuchsia.io.Directory for the specified |path| or null InterfaceHandle
+// if the path doesn't exist or it's not a directory.
+BASE_EXPORT fidl::InterfaceHandle<::fuchsia::io::Directory> OpenDirectory(
+    const base::FilePath& path);
 
 }  // namespace fuchsia
 }  // namespace base
diff --git a/base/fuchsia/file_utils_unittest.cc b/base/fuchsia/file_utils_unittest.cc
new file mode 100644
index 0000000..11bb1a2
--- /dev/null
+++ b/base/fuchsia/file_utils_unittest.cc
@@ -0,0 +1,44 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/fuchsia/file_utils.h"
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace fuchsia {
+
+class OpenDirectoryTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    EXPECT_TRUE(temp_dir.CreateUniqueTempDirUnderPath(
+        base::FilePath(kPersistedDataDirectoryPath)));
+  }
+
+  ScopedTempDir temp_dir;
+};
+
+TEST_F(OpenDirectoryTest, Open) {
+  auto dir = OpenDirectory(temp_dir.GetPath());
+  ASSERT_TRUE(dir);
+}
+
+// OpenDirectory() should fail when opening a directory that doesn't exist.
+TEST_F(OpenDirectoryTest, OpenNonExistent) {
+  auto dir = OpenDirectory(temp_dir.GetPath().AppendASCII("non_existent"));
+  ASSERT_FALSE(dir);
+}
+
+// OpenDirectory() should open only directories.
+TEST_F(OpenDirectoryTest, OpenFile) {
+  auto file_path = temp_dir.GetPath().AppendASCII("test_file");
+  ASSERT_TRUE(WriteFile(file_path, "foo", 3));
+  auto dir = OpenDirectory(file_path);
+  ASSERT_FALSE(dir);
+}
+
+}  // namespace fuchsia
+}  // namespace base
\ No newline at end of file
diff --git a/base/fuchsia/service_directory_client.cc b/base/fuchsia/service_directory_client.cc
index c3b1a47..3dc964f 100644
--- a/base/fuchsia/service_directory_client.cc
+++ b/base/fuchsia/service_directory_client.cc
@@ -17,19 +17,11 @@
 
 namespace {
 
-fidl::InterfaceHandle<::fuchsia::io::Directory> ConnectToServiceRoot() {
-  fidl::InterfaceHandle<::fuchsia::io::Directory> directory;
-  zx_status_t result = fdio_service_connect(
-      kServiceDirectoryPath, directory.NewRequest().TakeChannel().release());
-  ZX_CHECK(result == ZX_OK, result) << "Failed to open /svc";
-  return directory;
-}
-
 // Singleton container for the process-global ServiceDirectoryClient instance.
 std::unique_ptr<ServiceDirectoryClient>* ProcessServiceDirectoryClient() {
   static base::NoDestructor<std::unique_ptr<ServiceDirectoryClient>>
-      service_directory_client_ptr(
-          std::make_unique<ServiceDirectoryClient>(ConnectToServiceRoot()));
+      service_directory_client_ptr(std::make_unique<ServiceDirectoryClient>(
+          OpenDirectory(base::FilePath(kServiceDirectoryPath))));
   return service_directory_client_ptr.get();
 }
 
diff --git a/base/process/launch_fuchsia.cc b/base/process/launch_fuchsia.cc
index 53c99f2b..3e840cdf 100644
--- a/base/process/launch_fuchsia.cc
+++ b/base/process/launch_fuchsia.cc
@@ -180,14 +180,15 @@
     }
 
     for (const auto& path_to_clone : options.paths_to_clone) {
-      zx::handle handle = fuchsia::GetHandleFromFile(
-          base::File(base::FilePath(path_to_clone),
-                     base::File::FLAG_OPEN | base::File::FLAG_READ));
-      if (!handle) {
+      fidl::InterfaceHandle<::fuchsia::io::Directory> directory =
+          base::fuchsia::OpenDirectory(path_to_clone);
+      if (!directory) {
         LOG(WARNING) << "Could not open handle for path: " << path_to_clone;
         return base::Process();
       }
 
+      zx::handle handle = directory.TakeChannel();
+
       spawn_actions.push_back(FdioSpawnActionAddNamespaceEntry(
           path_to_clone.value().c_str(), handle.get()));
       transferred_handles.push_back(std::move(handle));
diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc
index c694196..b08292b 100644
--- a/base/process/process_util_unittest.cc
+++ b/base/process/process_util_unittest.cc
@@ -264,13 +264,14 @@
 
   // Attach the tempdir to "data", but also try to duplicate the existing "data"
   // directory.
-  options.paths_to_clone.push_back(base::FilePath("/data"));
+  options.paths_to_clone.push_back(
+      base::FilePath(base::fuchsia::kPersistedDataDirectoryPath));
   options.paths_to_clone.push_back(base::FilePath("/tmp"));
   options.paths_to_transfer.push_back(
-      {FilePath("/data"),
-       fuchsia::GetHandleFromFile(
-           base::File(base::FilePath(tmpdir_with_staged.GetPath()),
-                      base::File::FLAG_OPEN | base::File::FLAG_READ))
+      {FilePath(base::fuchsia::kPersistedDataDirectoryPath),
+       base::fuchsia::OpenDirectory(
+           base::FilePath(tmpdir_with_staged.GetPath()))
+           .TakeChannel()
            .release()});
 
   // Verify from that "/data/staged" exists from the child process' perspective.
@@ -307,14 +308,14 @@
   staged_file.Close();
 
   // Mount the tempdir to "/foo".
-  zx::handle tmp_handle = fuchsia::GetHandleFromFile(
-      base::File(base::FilePath(new_tmpdir.GetPath()),
-                 base::File::FLAG_OPEN | base::File::FLAG_READ));
-  ASSERT_TRUE(tmp_handle.is_valid());
+  zx::channel tmp_channel =
+      base::fuchsia::OpenDirectory(new_tmpdir.GetPath()).TakeChannel();
+
+  ASSERT_TRUE(tmp_channel.is_valid());
   LaunchOptions options;
   options.paths_to_clone.push_back(base::FilePath("/tmp"));
   options.paths_to_transfer.push_back(
-      {base::FilePath("/foo"), tmp_handle.release()});
+      {base::FilePath("/foo"), tmp_channel.release()});
   options.spawn_flags = FDIO_SPAWN_CLONE_STDIO;
 
   // Verify from that "/foo/staged" exists from the child process' perspective.
diff --git a/base/task/sequence_manager/sequence_manager_impl.cc b/base/task/sequence_manager/sequence_manager_impl.cc
index 5d45100b..1dbafee 100644
--- a/base/task/sequence_manager/sequence_manager_impl.cc
+++ b/base/task/sequence_manager/sequence_manager_impl.cc
@@ -352,16 +352,16 @@
   empty_queues_to_reload_.RunActiveCallbacks();
 }
 
-void SequenceManagerImpl::WakeUpReadyDelayedQueues(LazyNow* lazy_now) {
+void SequenceManagerImpl::MoveReadyDelayedTasksToWorkQueues(LazyNow* lazy_now) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("sequence_manager"),
-               "SequenceManagerImpl::WakeUpReadyDelayedQueues");
+               "SequenceManagerImpl::MoveReadyDelayedTasksToWorkQueues");
 
   for (TimeDomain* time_domain : main_thread_only().time_domains) {
     if (time_domain == main_thread_only().real_time_domain.get()) {
-      time_domain->WakeUpReadyDelayedQueues(lazy_now);
+      time_domain->MoveReadyDelayedTasksToWorkQueues(lazy_now);
     } else {
       LazyNow time_domain_lazy_now = time_domain->CreateLazyNow();
-      time_domain->WakeUpReadyDelayedQueues(&time_domain_lazy_now);
+      time_domain->MoveReadyDelayedTasksToWorkQueues(&time_domain_lazy_now);
     }
   }
 }
@@ -426,7 +426,7 @@
 
   ReloadEmptyWorkQueues();
   LazyNow lazy_now(controller_->GetClock());
-  WakeUpReadyDelayedQueues(&lazy_now);
+  MoveReadyDelayedTasksToWorkQueues(&lazy_now);
 
   // If we sampled now, check if it's time to reclaim memory next time we go
   // idle.
@@ -506,8 +506,9 @@
     return TimeDelta();
 
   // Otherwise we need to find the shortest delay, if any.  NB we don't need to
-  // call WakeUpReadyDelayedQueues because it's assumed DelayTillNextTask will
-  // return TimeDelta>() if the delayed task is due to run now.
+  // call MoveReadyDelayedTasksToWorkQueues because it's assumed
+  // DelayTillNextTask will return TimeDelta>() if the delayed task is due to
+  // run now.
   TimeDelta delay_till_next_task = TimeDelta::Max();
   for (TimeDomain* time_domain : main_thread_only().time_domains) {
     Optional<TimeDelta> delay = time_domain->DelayTillNextTask(lazy_now);
diff --git a/base/task/sequence_manager/sequence_manager_impl.h b/base/task/sequence_manager/sequence_manager_impl.h
index 4ca8d599..7718efc 100644
--- a/base/task/sequence_manager/sequence_manager_impl.h
+++ b/base/task/sequence_manager/sequence_manager_impl.h
@@ -311,7 +311,7 @@
 
   // Delayed Tasks with run_times <= Now() are enqueued onto the work queue and
   // reloads any empty work queues.
-  void WakeUpReadyDelayedQueues(LazyNow* lazy_now);
+  void MoveReadyDelayedTasksToWorkQueues(LazyNow* lazy_now);
 
   void NotifyWillProcessTask(ExecutingTask* task, LazyNow* time_before_task);
   void NotifyDidProcessTask(ExecutingTask* task, LazyNow* time_after_task);
diff --git a/base/task/sequence_manager/sequence_manager_impl_unittest.cc b/base/task/sequence_manager/sequence_manager_impl_unittest.cc
index 8ca4c366..b0985f6 100644
--- a/base/task/sequence_manager/sequence_manager_impl_unittest.cc
+++ b/base/task/sequence_manager/sequence_manager_impl_unittest.cc
@@ -755,13 +755,14 @@
 
   // Move the task into the |delayed_work_queue|.
   LazyNow lazy_now(mock_tick_clock());
-  sequence_manager()->WakeUpReadyDelayedQueues(&lazy_now);
+  sequence_manager()->MoveReadyDelayedTasksToWorkQueues(&lazy_now);
+  sequence_manager()->ScheduleWork();
   EXPECT_FALSE(queue->GetTaskQueueImpl()->delayed_work_queue()->Empty());
   EXPECT_TRUE(queue->HasTaskToRunImmediately());
 
   // Run the task, making the queue empty.
   RunLoop().RunUntilIdle();
-  EXPECT_FALSE(queue->HasTaskToRunImmediately());
+  EXPECT_TRUE(queue->GetTaskQueueImpl()->delayed_work_queue()->Empty());
 }
 
 TEST_P(SequenceManagerTest, DelayedTaskPosting) {
@@ -1770,15 +1771,16 @@
   // Move time forwards until just before the delayed task should run.
   AdvanceMockTickClock(TimeDelta::FromMilliseconds(10));
   LazyNow lazy_now_1(mock_tick_clock());
-  sequence_manager()->WakeUpReadyDelayedQueues(&lazy_now_1);
+  sequence_manager()->MoveReadyDelayedTasksToWorkQueues(&lazy_now_1);
   EXPECT_FALSE(queue->HasTaskToRunImmediately());
 
   // Force the delayed task onto the work queue.
   AdvanceMockTickClock(TimeDelta::FromMilliseconds(2));
   LazyNow lazy_now_2(mock_tick_clock());
-  sequence_manager()->WakeUpReadyDelayedQueues(&lazy_now_2);
+  sequence_manager()->MoveReadyDelayedTasksToWorkQueues(&lazy_now_2);
   EXPECT_TRUE(queue->HasTaskToRunImmediately());
 
+  sequence_manager()->ScheduleWork();
   RunLoop().RunUntilIdle();
   EXPECT_FALSE(queue->HasTaskToRunImmediately());
 }
@@ -4120,7 +4122,7 @@
       TimeDelta::FromMilliseconds(10));
   AdvanceMockTickClock(TimeDelta::FromMilliseconds(100));
   LazyNow lazy_now(mock_tick_clock());
-  sequence_manager()->WakeUpReadyDelayedQueues(&lazy_now);
+  sequence_manager()->MoveReadyDelayedTasksToWorkQueues(&lazy_now);
 
   EXPECT_THAT(tasks_alive,
               UnorderedElementsAre("Q1 I1 1", "Q1 D1 0", "Q2 D1 1", "Q3 I1 0",
diff --git a/base/task/sequence_manager/task_queue_impl.cc b/base/task/sequence_manager/task_queue_impl.cc
index 1b67160b..77bfc92 100644
--- a/base/task/sequence_manager/task_queue_impl.cc
+++ b/base/task/sequence_manager/task_queue_impl.cc
@@ -365,7 +365,9 @@
     pending_task.delayed_run_time = time_domain_now;
     main_thread_only().delayed_incoming_queue.push(std::move(pending_task));
     LazyNow lazy_now(time_domain_now);
-    WakeUpForDelayedWork(&lazy_now);
+    MoveReadyDelayedTasksToWorkQueue(&lazy_now);
+    // if (IsQueueEnabled() || !main_thread_only().current_fence)
+    //  sequence_manager_->ScheduleWork();
   } else {
     // If |delayed_run_time| is in the future we can queue it as normal.
     PushOntoDelayedIncomingQueueFromMainThread(std::move(pending_task),
@@ -475,30 +477,26 @@
   return wake_up->time;
 }
 
-void TaskQueueImpl::WakeUpForDelayedWork(LazyNow* lazy_now) {
+void TaskQueueImpl::MoveReadyDelayedTasksToWorkQueue(LazyNow* lazy_now) {
   // Enqueue all delayed tasks that should be running now, skipping any that
   // have been canceled.
+  WorkQueue::TaskPusher delayed_work_queue_task_pusher(
+      main_thread_only().delayed_work_queue->CreateTaskPusher());
+
   while (!main_thread_only().delayed_incoming_queue.empty()) {
-    Task& task =
-        const_cast<Task&>(main_thread_only().delayed_incoming_queue.top());
-    if (!task.task || task.task.IsCancelled()) {
+    Task* task =
+        const_cast<Task*>(&main_thread_only().delayed_incoming_queue.top());
+    if (!task->task || task->task.IsCancelled()) {
       main_thread_only().delayed_incoming_queue.pop();
       continue;
     }
-    if (task.delayed_run_time > lazy_now->Now())
+    if (task->delayed_run_time > lazy_now->Now())
       break;
-    ActivateDelayedFenceIfNeeded(task.delayed_run_time);
-    DCHECK(!task.enqueue_order_set());
-    task.set_enqueue_order(sequence_manager_->GetNextSequenceNumber());
-    main_thread_only().delayed_work_queue->Push(std::move(task));
+    ActivateDelayedFenceIfNeeded(task->delayed_run_time);
+    DCHECK(!task->enqueue_order_set());
+    task->set_enqueue_order(sequence_manager_->GetNextSequenceNumber());
+    delayed_work_queue_task_pusher.Push(task);
     main_thread_only().delayed_incoming_queue.pop();
-
-    // Normally WakeUpForDelayedWork is called inside DoWork, but it also
-    // can be called elsewhere (e.g. tests and fast-path for posting
-    // delayed tasks). Ensure that there is a DoWork posting. No-op inside
-    // existing DoWork due to DoWork deduplication.
-    if (IsQueueEnabled() || !main_thread_only().current_fence)
-      sequence_manager_->ScheduleWork();
   }
 
   UpdateDelayedWakeUp(lazy_now);
diff --git a/base/task/sequence_manager/task_queue_impl.h b/base/task/sequence_manager/task_queue_impl.h
index 255f9df..c759083 100644
--- a/base/task/sequence_manager/task_queue_impl.h
+++ b/base/task/sequence_manager/task_queue_impl.h
@@ -171,9 +171,8 @@
   }
 
   // Enqueues any delayed tasks which should be run now on the
-  // |delayed_work_queue|.
-  // Must be called from the main thread.
-  void WakeUpForDelayedWork(LazyNow* lazy_now);
+  // |delayed_work_queue|. Must be called from the main thread.
+  void MoveReadyDelayedTasksToWorkQueue(LazyNow* lazy_now);
 
   base::internal::HeapHandle heap_handle() const {
     return main_thread_only().heap_handle;
diff --git a/base/task/sequence_manager/test/sequence_manager_for_test.h b/base/task/sequence_manager/test/sequence_manager_for_test.h
index 82a6297b..16f1a43 100644
--- a/base/task/sequence_manager/test/sequence_manager_for_test.h
+++ b/base/task/sequence_manager/test/sequence_manager_for_test.h
@@ -45,8 +45,8 @@
   size_t QueuesToShutdownCount();
 
   using internal::SequenceManagerImpl::GetNextSequenceNumber;
+  using internal::SequenceManagerImpl::MoveReadyDelayedTasksToWorkQueues;
   using internal::SequenceManagerImpl::ReloadEmptyWorkQueues;
-  using internal::SequenceManagerImpl::WakeUpReadyDelayedQueues;
 
  private:
   explicit SequenceManagerForTest(
diff --git a/base/task/sequence_manager/time_domain.cc b/base/task/sequence_manager/time_domain.cc
index 1d81608..b34f32f 100644
--- a/base/task/sequence_manager/time_domain.cc
+++ b/base/task/sequence_manager/time_domain.cc
@@ -121,7 +121,7 @@
   }
 }
 
-void TimeDomain::WakeUpReadyDelayedQueues(LazyNow* lazy_now) {
+void TimeDomain::MoveReadyDelayedTasksToWorkQueues(LazyNow* lazy_now) {
   DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   // Wake up any queues with pending delayed work.  Note std::multimap stores
   // the elements sorted by key, so the begin() iterator points to the earliest
@@ -129,7 +129,7 @@
   while (!delayed_wake_up_queue_.empty() &&
          delayed_wake_up_queue_.Min().wake_up.time <= lazy_now->Now()) {
     internal::TaskQueueImpl* queue = delayed_wake_up_queue_.Min().queue;
-    queue->WakeUpForDelayedWork(lazy_now);
+    queue->MoveReadyDelayedTasksToWorkQueue(lazy_now);
   }
 }
 
diff --git a/base/task/sequence_manager/time_domain.h b/base/task/sequence_manager/time_domain.h
index 04cab726..4ffdf4d 100644
--- a/base/task/sequence_manager/time_domain.h
+++ b/base/task/sequence_manager/time_domain.h
@@ -115,8 +115,9 @@
   // Remove the TaskQueue from any internal data sctructures.
   void UnregisterQueue(internal::TaskQueueImpl* queue);
 
-  // Wake up each TaskQueue where the delay has elapsed.
-  void WakeUpReadyDelayedQueues(LazyNow* lazy_now);
+  // Wake up each TaskQueue where the delay has elapsed. Note this doesn't
+  // ScheduleWork.
+  void MoveReadyDelayedTasksToWorkQueues(LazyNow* lazy_now);
 
   struct ScheduledDelayedWakeUp {
     internal::DelayedWakeUp wake_up;
diff --git a/base/task/sequence_manager/time_domain_unittest.cc b/base/task/sequence_manager/time_domain_unittest.cc
index e51be10..7a20bbd 100644
--- a/base/task/sequence_manager/time_domain_unittest.cc
+++ b/base/task/sequence_manager/time_domain_unittest.cc
@@ -39,10 +39,10 @@
 
   ~TestTimeDomain() override = default;
 
+  using TimeDomain::MoveReadyDelayedTasksToWorkQueues;
   using TimeDomain::NextScheduledRunTime;
   using TimeDomain::SetNextWakeUpForQueue;
   using TimeDomain::UnregisterQueue;
-  using TimeDomain::WakeUpReadyDelayedQueues;
 
   LazyNow CreateLazyNow() const override { return LazyNow(now_); }
   TimeTicks Now() const override { return now_; }
@@ -234,7 +234,7 @@
   EXPECT_TRUE(time_domain_->Empty());
 }
 
-TEST_F(TimeDomainTest, WakeUpReadyDelayedQueues) {
+TEST_F(TimeDomainTest, MoveReadyDelayedTasksToWorkQueues) {
   TimeDelta delay = TimeDelta::FromMilliseconds(50);
   TimeTicks now = time_domain_->Now();
   LazyNow lazy_now_1(now);
@@ -245,17 +245,17 @@
 
   EXPECT_EQ(delayed_runtime, time_domain_->NextScheduledRunTime());
 
-  time_domain_->WakeUpReadyDelayedQueues(&lazy_now_1);
+  time_domain_->MoveReadyDelayedTasksToWorkQueues(&lazy_now_1);
   EXPECT_EQ(delayed_runtime, time_domain_->NextScheduledRunTime());
 
   EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, TimeTicks::Max()));
   time_domain_->SetNow(delayed_runtime);
   LazyNow lazy_now_2(time_domain_->CreateLazyNow());
-  time_domain_->WakeUpReadyDelayedQueues(&lazy_now_2);
+  time_domain_->MoveReadyDelayedTasksToWorkQueues(&lazy_now_2);
   ASSERT_FALSE(time_domain_->NextScheduledRunTime());
 }
 
-TEST_F(TimeDomainTest, WakeUpReadyDelayedQueuesWithIdenticalRuntimes) {
+TEST_F(TimeDomainTest, MoveReadyDelayedTasksToWorkQueuesWithIdenticalRuntimes) {
   int sequence_num = 0;
   TimeDelta delay = TimeDelta::FromMilliseconds(50);
   TimeTicks now = time_domain_->Now();
@@ -273,7 +273,7 @@
   task_queue_->SetDelayedWakeUpForTesting(
       internal::DelayedWakeUp{delayed_runtime, ++sequence_num});
 
-  time_domain_->WakeUpReadyDelayedQueues(&lazy_now);
+  time_domain_->MoveReadyDelayedTasksToWorkQueues(&lazy_now);
 
   // The second task queue should wake up first since it has a lower sequence
   // number.
diff --git a/base/task/sequence_manager/work_queue.cc b/base/task/sequence_manager/work_queue.cc
index 3cf0cb4..206c0f1 100644
--- a/base/task/sequence_manager/work_queue.cc
+++ b/base/task/sequence_manager/work_queue.cc
@@ -70,7 +70,7 @@
   // Make sure the |enqueue_order()| is monotonically increasing.
   DCHECK(was_empty || tasks_.back().enqueue_order() < task.enqueue_order());
 
-  // Amoritized O(1).
+  // Amortized O(1).
   tasks_.push_back(std::move(task));
 
   if (!was_empty)
@@ -81,6 +81,42 @@
     work_queue_sets_->OnTaskPushedToEmptyQueue(this);
 }
 
+WorkQueue::TaskPusher::TaskPusher(WorkQueue* work_queue)
+    : work_queue_(work_queue), was_empty_(work_queue->Empty()) {}
+
+WorkQueue::TaskPusher::TaskPusher(TaskPusher&& other)
+    : work_queue_(other.work_queue_), was_empty_(other.was_empty_) {
+  other.work_queue_ = nullptr;
+}
+
+void WorkQueue::TaskPusher::Push(Task* task) {
+  DCHECK(work_queue_);
+
+#ifndef NDEBUG
+  DCHECK(task->enqueue_order_set());
+#endif
+
+  // Make sure the |enqueue_order()| is monotonically increasing.
+  DCHECK(work_queue_->tasks_.empty() ||
+         work_queue_->tasks_.back().enqueue_order() < task->enqueue_order());
+
+  // Amortized O(1).
+  work_queue_->tasks_.push_back(std::move(*task));
+}
+
+WorkQueue::TaskPusher::~TaskPusher() {
+  // If |work_queue_| became non empty and it isn't blocked by a fence then we
+  // must notify |work_queue_->work_queue_sets_|.
+  if (was_empty_ && work_queue_ && !work_queue_->Empty() &&
+      work_queue_->work_queue_sets_ && !work_queue_->BlockedByFence()) {
+    work_queue_->work_queue_sets_->OnTaskPushedToEmptyQueue(work_queue_);
+  }
+}
+
+WorkQueue::TaskPusher WorkQueue::CreateTaskPusher() {
+  return TaskPusher(this);
+}
+
 void WorkQueue::PushNonNestableTaskToFront(Task task) {
   DCHECK(task.nestable == Nestable::kNonNestable);
 
@@ -97,7 +133,7 @@
         << " : " << name_;
   }
 
-  // Amoritized O(1).
+  // Amortized O(1).
   tasks_.push_front(std::move(task));
 
   if (!work_queue_sets_)
diff --git a/base/task/sequence_manager/work_queue.h b/base/task/sequence_manager/work_queue.h
index fd80f32b..469be50 100644
--- a/base/task/sequence_manager/work_queue.h
+++ b/base/task/sequence_manager/work_queue.h
@@ -65,6 +65,27 @@
   // it informs the WorkQueueSets if the head changed.
   void Push(Task task);
 
+  // RAII helper that helps efficiently push N Tasks to a WorkQueue.
+  class BASE_EXPORT TaskPusher {
+   public:
+    TaskPusher(const TaskPusher&) = delete;
+    TaskPusher(TaskPusher&& other);
+    ~TaskPusher();
+
+    void Push(Task* task);
+
+   private:
+    friend class WorkQueue;
+
+    explicit TaskPusher(WorkQueue* work_queue);
+
+    WorkQueue* work_queue_;
+    const bool was_empty_;
+  };
+
+  // Returns an RAII helper to efficiently push multiple tasks.
+  TaskPusher CreateTaskPusher();
+
   // Pushes the task onto the front of the |tasks_| and if it's before any
   // fence it informs the WorkQueueSets the head changed. Use with caution this
   // API can easily lead to task starvation if misused.
diff --git a/base/task/sequence_manager/work_queue_unittest.cc b/base/task/sequence_manager/work_queue_unittest.cc
index d4b4571..51e6d2a8 100644
--- a/base/task/sequence_manager/work_queue_unittest.cc
+++ b/base/task/sequence_manager/work_queue_unittest.cc
@@ -158,6 +158,17 @@
   EXPECT_EQ(work_queue_.get(), work_queue_sets_->GetOldestQueueInSet(0));
 }
 
+TEST_F(WorkQueueTest, PushMultiple) {
+  EXPECT_EQ(nullptr, work_queue_sets_->GetOldestQueueInSet(0));
+
+  work_queue_->Push(FakeTaskWithEnqueueOrder(2));
+  work_queue_->Push(FakeTaskWithEnqueueOrder(3));
+  work_queue_->Push(FakeTaskWithEnqueueOrder(4));
+  EXPECT_EQ(work_queue_.get(), work_queue_sets_->GetOldestQueueInSet(0));
+  EXPECT_EQ(2ull, work_queue_->GetFrontTask()->enqueue_order());
+  EXPECT_EQ(4ull, work_queue_->GetBackTask()->enqueue_order());
+}
+
 TEST_F(WorkQueueTest, PushAfterFenceHit) {
   work_queue_->InsertFence(EnqueueOrder::blocking_fence());
   EXPECT_EQ(nullptr, work_queue_sets_->GetOldestQueueInSet(0));
@@ -166,6 +177,53 @@
   EXPECT_EQ(nullptr, work_queue_sets_->GetOldestQueueInSet(0));
 }
 
+TEST_F(WorkQueueTest, CreateTaskPusherNothingPushed) {
+  EXPECT_EQ(nullptr, work_queue_sets_->GetOldestQueueInSet(0));
+  { WorkQueue::TaskPusher task_pusher(work_queue_->CreateTaskPusher()); }
+  EXPECT_EQ(nullptr, work_queue_sets_->GetOldestQueueInSet(0));
+}
+
+TEST_F(WorkQueueTest, CreateTaskPusherOneTask) {
+  EXPECT_EQ(nullptr, work_queue_sets_->GetOldestQueueInSet(0));
+  {
+    WorkQueue::TaskPusher task_pusher(work_queue_->CreateTaskPusher());
+    Task task = FakeTaskWithEnqueueOrder(2);
+    task_pusher.Push(&task);
+  }
+  EXPECT_EQ(work_queue_.get(), work_queue_sets_->GetOldestQueueInSet(0));
+}
+
+TEST_F(WorkQueueTest, CreateTaskPusherThreeTasks) {
+  EXPECT_EQ(nullptr, work_queue_sets_->GetOldestQueueInSet(0));
+  {
+    WorkQueue::TaskPusher task_pusher(work_queue_->CreateTaskPusher());
+    Task task1 = FakeTaskWithEnqueueOrder(2);
+    Task task2 = FakeTaskWithEnqueueOrder(3);
+    Task task3 = FakeTaskWithEnqueueOrder(4);
+    task_pusher.Push(&task1);
+    task_pusher.Push(&task2);
+    task_pusher.Push(&task3);
+  }
+  EXPECT_EQ(work_queue_.get(), work_queue_sets_->GetOldestQueueInSet(0));
+  EXPECT_EQ(2ull, work_queue_->GetFrontTask()->enqueue_order());
+  EXPECT_EQ(4ull, work_queue_->GetBackTask()->enqueue_order());
+}
+
+TEST_F(WorkQueueTest, CreateTaskPusherAfterFenceHit) {
+  work_queue_->InsertFence(EnqueueOrder::blocking_fence());
+  EXPECT_EQ(nullptr, work_queue_sets_->GetOldestQueueInSet(0));
+  {
+    WorkQueue::TaskPusher task_pusher(work_queue_->CreateTaskPusher());
+    Task task1 = FakeTaskWithEnqueueOrder(2);
+    Task task2 = FakeTaskWithEnqueueOrder(3);
+    Task task3 = FakeTaskWithEnqueueOrder(4);
+    task_pusher.Push(&task1);
+    task_pusher.Push(&task2);
+    task_pusher.Push(&task3);
+  }
+  EXPECT_EQ(nullptr, work_queue_sets_->GetOldestQueueInSet(0));
+}
+
 TEST_F(WorkQueueTest, PushNonNestableTaskToFront) {
   EXPECT_EQ(nullptr, work_queue_sets_->GetOldestQueueInSet(0));
 
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
index a041c55..ccecde3 100644
--- a/base/test/launcher/test_launcher.cc
+++ b/base/test/launcher/test_launcher.cc
@@ -367,12 +367,8 @@
 
   // Bind the new test subdirectory to /data in the child process' namespace.
   new_options.paths_to_transfer.push_back(
-      {kDataPath, base::fuchsia::GetHandleFromFile(
-                      base::File(nested_data_path,
-                                 base::File::FLAG_OPEN | base::File::FLAG_READ |
-                                     base::File::FLAG_DELETE_ON_CLOSE))
-                      .release()});
-
+      {kDataPath,
+       base::fuchsia::OpenDirectory(nested_data_path).TakeChannel().release()});
 #endif  // defined(OS_FUCHSIA)
 
 #if defined(OS_LINUX)
@@ -452,9 +448,8 @@
     zx_status_t status = job_handle.kill();
     ZX_CHECK(status == ZX_OK, status);
 
-    // The child process' data dir should have been deleted automatically,
-    // thanks to the DELETE_ON_CLOSE flag.
-    DCHECK(!base::DirectoryExists(nested_data_path));
+    // Cleanup the data directory.
+    CHECK(DeleteFile(nested_data_path, true));
 #elif defined(OS_POSIX)
     if (exit_code != 0) {
       // On POSIX, in case the test does not exit cleanly, either due to a crash
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 0afd629..1ef3795 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-1fdc2abd281892f5d2c914bb83b6bae6108619c6
\ No newline at end of file
+ddcb12bc41acc7d54223765e22f78a305954bcbc
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 1249cc9..077fa9d8 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-d5208460c502e92a7c0c718f986b482617ec1c90
\ No newline at end of file
+bf01df1020cecebcf7bcc39fdd72c783bb14a923
\ No newline at end of file
diff --git a/buildtools/DEPS b/buildtools/DEPS
index a56d460..89fab254 100644
--- a/buildtools/DEPS
+++ b/buildtools/DEPS
@@ -3,6 +3,16 @@
 vars = {
   'chromium_url': 'https://chromium.googlesource.com',
 
+  #
+  # TODO(crbug.com/941824): These revisions need to be kept in sync
+  # between //DEPS and //buildtools/DEPS, so if you're updating one,
+  # update the other. There is a presubmit check that checks that
+  # you've done so; if you are adding new tools to //buildtools and
+  # hence new revisions to this list, make sure you update the
+  # _CheckBuildtoolsRevsAreInSync in PRESUBMIT.py to include the additional
+  # revisions.
+  #
+
   # When changing these, also update the svn revisions in deps_revisions.gni
   'clang_format_revision': '96636aa0e9f047f17447f2d45a094d0b59ed7917',
   'libcxx_revision':       'a50f5035629b7621e92acef968403f71b7d48553',
diff --git a/cc/paint/display_item_list.cc b/cc/paint/display_item_list.cc
index 5a467fb..7244679 100644
--- a/cc/paint/display_item_list.cc
+++ b/cc/paint/display_item_list.cc
@@ -153,7 +153,10 @@
     for (const PaintOp* op : PaintOpBuffer::Iterator(&paint_op_buffer_)) {
       state->BeginDictionary();
       state->SetString("name", PaintOpTypeToString(op->GetType()));
-      MathUtil::AddToTracedValue("visual_rect", bounds[i++], state.get());
+
+      // rtree_ generation drops empty rects
+      if (i < bounds.size())
+        MathUtil::AddToTracedValue("visual_rect", bounds[i++], state.get());
 
       SkPictureRecorder recorder;
       SkCanvas* canvas =
diff --git a/cc/paint/display_item_list.h b/cc/paint/display_item_list.h
index 1eb89208..50f3e9e 100644
--- a/cc/paint/display_item_list.h
+++ b/cc/paint/display_item_list.h
@@ -198,6 +198,7 @@
                              int max_ops_to_analyze = 1);
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, TraceEmptyVisualRect);
   FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, AsValueWithNoOps);
   FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, AsValueWithOps);
   friend gpu::raster::RasterImplementation;
diff --git a/cc/paint/display_item_list_unittest.cc b/cc/paint/display_item_list_unittest.cc
index 0abe50d53..e76d52b 100644
--- a/cc/paint/display_item_list_unittest.cc
+++ b/cc/paint/display_item_list_unittest.cc
@@ -77,6 +77,31 @@
     EXPECT_EQ(height, d);                                  \
   } while (false)
 
+// CreateTracedValue should not crash if there are different numbers of
+// visual_rect are paint_op
+TEST(DisplayItemListTest, TraceEmptyVisualRect) {
+  // |layer_rect| is empty to cause rtree generation to skip it.
+  gfx::Rect layer_rect(0, 10);
+  PaintFlags red_paint;
+  red_paint.setColor(SK_ColorRED);
+  auto list = base::MakeRefCounted<DisplayItemList>();
+
+  gfx::Point offset(8, 9);
+
+  list->StartPaint();
+  list->push<SaveOp>();
+  list->push<TranslateOp>(static_cast<float>(offset.x()),
+                          static_cast<float>(offset.y()));
+  list->push<DrawRectOp>(SkRect::MakeLTRB(0.f, 0.f, 60.f, 60.f), red_paint);
+  list->push<RestoreOp>();
+  list->EndPaintOfUnpaired(gfx::Rect(offset, layer_rect.size()));
+  list->Finalize();
+
+  // Pass: we don't crash
+  std::unique_ptr<base::Value> root =
+      list->CreateTracedValue(true)->ToBaseValue();
+}
+
 TEST(DisplayItemListTest, SingleUnpairedRange) {
   gfx::Rect layer_rect(100, 100);
   PaintFlags blue_flags;
diff --git a/chrome/android/java/res/layout/bookmark_widget.xml b/chrome/android/java/res/layout/bookmark_widget.xml
index 61af800..a0e17dfa 100644
--- a/chrome/android/java/res/layout/bookmark_widget.xml
+++ b/chrome/android/java/res/layout/bookmark_widget.xml
@@ -7,7 +7,7 @@
     android:id="@+id/bookmarks_list"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="#ddffffff"
+    android:background="@color/bookmark_widget_background"
     android:divider="@null"
     android:drawSelectorOnTop="true"
     android:listSelector="@drawable/bookmark_widget_list_selector" />
diff --git a/chrome/android/java/res/layout/bookmark_widget_item.xml b/chrome/android/java/res/layout/bookmark_widget_item.xml
index 2f80d4b..ecbe33b 100644
--- a/chrome/android/java/res/layout/bookmark_widget_item.xml
+++ b/chrome/android/java/res/layout/bookmark_widget_item.xml
@@ -28,7 +28,6 @@
         android:paddingEnd="16dp"
         android:singleLine="true"
         android:textAlignment="viewStart"
-        android:textColor="@color/default_text_color"
-        android:textSize="16sp" />
+        android:textAppearance="@style/TextAppearance.BookmarkWidgetItemText" />
 
 </LinearLayout>
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml
index 892601f..76d28d9e 100644
--- a/chrome/android/java/res/values-v17/styles.xml
+++ b/chrome/android/java/res/values-v17/styles.xml
@@ -730,6 +730,10 @@
         parent="@style/TextAppearance.AppCompat.Medium">
         <item name="android:textColor">@color/standard_mode_tint</item>
     </style>
+    <style name="TextAppearance.BookmarkWidgetItemText"
+        parent="@style/TextAppearance.BlackTitle1">
+        <item name="android:textColor">@color/default_text_color_dark</item>
+    </style>
 
     <!-- Download Home -->
     <style name="DateView">
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index fea2b31..a13f8f1 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -181,6 +181,7 @@
 
     <!-- Bookmark widget colors -->
     <color name="bookmark_widget_pressed_highlight">@color/black_alpha_11</color>
+    <color name="bookmark_widget_background">#DDFFFFFF</color>
 
     <!-- Payments UI colors -->
     <color name="payments_section_edit_background">@color/modern_secondary_color</color>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java
index bfe6add..ac0afc3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/SingleTabActivity.java
@@ -11,6 +11,10 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 
+import org.chromium.base.ActivityState;
+import org.chromium.base.ApplicationStatus;
+import org.chromium.base.CommandLine;
+import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabBuilder;
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
@@ -20,6 +24,7 @@
 import org.chromium.chrome.browser.tabmodel.TabSelectionType;
 import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
 import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 /**
  * Base class for task-focused activities that need to display a single tab.
@@ -28,6 +33,8 @@
  * activities - anything where maintaining multiple tabs is unnecessary.
  */
 public abstract class SingleTabActivity extends ChromeActivity {
+    private static final int PREWARM_RENDERER_DELAY_MS = 500;
+
     @Override
     protected void onNewIntent(Intent intent) {
         super.onNewIntent(intent);
@@ -138,4 +145,31 @@
 
     @Override
     public void onUpdateStateChanged() {}
+
+    @Override
+    public void onStopWithNative() {
+        super.onStopWithNative();
+        if (CommandLine.getInstance().hasSwitch(ChromeSwitches.AGGRESSIVELY_PREWARM_RENDERERS)) {
+            PostTask.postDelayedTask(UiThreadTaskTraits.DEFAULT, new Runnable() {
+                @Override
+                public void run() {
+                    // If we're not still stopped, we don't need the spare WebContents.
+                    if (ApplicationStatus.getStateForActivity(SingleTabActivity.this)
+                            == ActivityState.STOPPED) {
+                        WarmupManager.getInstance().createSpareWebContents(!WarmupManager.FOR_CCT);
+                    }
+                }
+            }, PREWARM_RENDERER_DELAY_MS);
+        }
+    }
+
+    @Override
+    public void onTrimMemory(int level) {
+        super.onTrimMemory(level);
+        if (CommandLine.getInstance().hasSwitch(ChromeSwitches.AGGRESSIVELY_PREWARM_RENDERERS)) {
+            if (ChromeApplication.isSevereMemorySignal(level)) {
+                WarmupManager.getInstance().destroySpareWebContents();
+            }
+        }
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java b/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
index 15684aa..185b31b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
@@ -19,7 +19,6 @@
 
 import org.chromium.base.Log;
 import org.chromium.base.StrictModeContext;
-import org.chromium.base.SysUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.TraceEvent;
 import org.chromium.base.VisibleForTesting;
@@ -53,11 +52,13 @@
     private static final String TAG = "WarmupManager";
 
     @VisibleForTesting
-    static final String WEBCONTENTS_STATUS_HISTOGRAM = "CustomTabs.SpareWebContents.Status";
+    static final String WEBCONTENTS_STATUS_HISTOGRAM = "CustomTabs.SpareWebContents.Status2";
+
+    public static final boolean FOR_CCT = true;
 
     // See CustomTabs.SpareWebContentsStatus histogram. Append-only.
     @IntDef({WebContentsStatus.CREATED, WebContentsStatus.USED, WebContentsStatus.KILLED,
-            WebContentsStatus.DESTROYED})
+            WebContentsStatus.DESTROYED, WebContentsStatus.STOLEN})
     @Retention(RetentionPolicy.SOURCE)
     @interface WebContentsStatus {
         @VisibleForTesting
@@ -68,7 +69,9 @@
         int KILLED = 2;
         @VisibleForTesting
         int DESTROYED = 3;
-        int NUM_ENTRIES = 4;
+        @VisibleForTesting
+        int STOLEN = 4;
+        int NUM_ENTRIES = 5;
     }
 
     /**
@@ -83,7 +86,7 @@
             recordWebContentsStatus(WebContentsStatus.KILLED);
             destroySpareWebContentsInternal();
         }
-    };
+    }
 
     @SuppressLint("StaticFieldLeak")
     private static WarmupManager sWarmupManager;
@@ -97,6 +100,7 @@
     WebContents mSpareWebContents;
     private long mWebContentsCreationTimeMs;
     private RenderProcessGoneObserver mObserver;
+    private boolean mWebContentsCreatedForCCT;
 
     /**
      * @return The singleton instance for the WarmupManager, creating one if necessary.
@@ -326,14 +330,14 @@
      *
      * This creates a renderer that is suitable for any navigation. It can be picked up by any tab.
      * Can be called multiple times, and must be called from the UI thread.
-     * Note that this is a no-op on low-end devices.
+     *
+     * @param forCCT Whether this WebContents is being created for CCT.
      */
-    public void createSpareWebContents() {
+    public void createSpareWebContents(boolean forCCT) {
         ThreadUtils.assertOnUiThread();
-        if (!LibraryLoader.getInstance().isInitialized() || mSpareWebContents != null
-                || SysUtils.isLowEndDevice()) {
-            return;
-        }
+        if (!LibraryLoader.getInstance().isInitialized() || mSpareWebContents != null) return;
+
+        mWebContentsCreatedForCCT = forCCT;
         mSpareWebContents = new WebContentsFactory().createWebContentsWithWarmRenderer(
                 false /* incognito */, true /* initiallyHidden */);
         mObserver = new RenderProcessGoneObserver();
@@ -356,10 +360,12 @@
      * Returns a spare WebContents or null, depending on the availability of one.
      *
      * The parameters are the same as for {@link WebContentsFactory#createWebContents()}.
+     * @param forCCT Whether this WebContents is being taken by CCT.
      *
      * @return a WebContents, or null.
      */
-    public WebContents takeSpareWebContents(boolean incognito, boolean initiallyHidden) {
+    public WebContents takeSpareWebContents(
+            boolean incognito, boolean initiallyHidden, boolean forCCT) {
         ThreadUtils.assertOnUiThread();
         if (incognito) return null;
         WebContents result = mSpareWebContents;
@@ -368,7 +374,8 @@
         result.removeObserver(mObserver);
         mObserver = null;
         if (!initiallyHidden) result.onShow();
-        recordWebContentsStatus(WebContentsStatus.USED);
+        recordWebContentsStatus(mWebContentsCreatedForCCT == forCCT ? WebContentsStatus.USED
+                                                                    : WebContentsStatus.STOLEN);
         return result;
     }
 
@@ -386,7 +393,8 @@
         mObserver = null;
     }
 
-    private static void recordWebContentsStatus(@WebContentsStatus int status) {
+    private void recordWebContentsStatus(@WebContentsStatus int status) {
+        if (!mWebContentsCreatedForCCT) return;
         RecordHistogram.recordEnumeratedHistogram(
                 WEBCONTENTS_STATUS_HISTOGRAM, status, WebContentsStatus.NUM_ENTRIES);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillExpirationDateFixFlowPrompt.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillExpirationDateFixFlowPrompt.java
index dbd32c45e..9eddd72 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillExpirationDateFixFlowPrompt.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillExpirationDateFixFlowPrompt.java
@@ -20,8 +20,6 @@
 import org.chromium.ui.modaldialog.ModalDialogProperties;
 import org.chromium.ui.modelutil.PropertyModel;
 
-import java.util.Calendar;
-
 /**
  * Prompt that asks users to confirm the expiration date before saving card to Google.
  * TODO(crbug.com/848955)
@@ -135,11 +133,8 @@
         if (buttonType == ModalDialogProperties.ButtonType.POSITIVE) {
             String monthString = mMonthInput.getText().toString().trim();
             String yearString = mYearInput.getText().toString().trim();
-            if (isValidExpirationDate(monthString, yearString)) {
-                mDelegate.onUserAccept(monthString, yearString);
-                mModalDialogManager.dismissDialog(
-                        model, DialogDismissalCause.POSITIVE_BUTTON_CLICKED);
-            }
+            mDelegate.onUserAccept(monthString, yearString);
+            mModalDialogManager.dismissDialog(model, DialogDismissalCause.POSITIVE_BUTTON_CLICKED);
         } else if (buttonType == ModalDialogProperties.ButtonType.NEGATIVE) {
             mModalDialogManager.dismissDialog(model, DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
         }
@@ -150,36 +145,6 @@
         mDelegate.onPromptDismissed();
     }
 
-    private boolean isValidExpirationDate(String monthString, String yearString) {
-        if (monthString.isEmpty() || yearString.isEmpty()) {
-            return false;
-        }
-
-        Calendar calendar = Calendar.getInstance();
-        int currentMonth = calendar.get(Calendar.MONTH);
-        int currentYear = calendar.get(Calendar.YEAR) % 100;
-        int year, month;
-        try {
-            year = Integer.valueOf(yearString.trim());
-            month = Integer.valueOf(monthString.trim());
-        } catch (NumberFormatException e) {
-            return false;
-        }
-
-        if (month <= 0 || month > 12) {
-            return false;
-        }
-
-        if (year < currentYear) {
-            return false;
-        }
-
-        if (year == currentYear) {
-            return month >= currentMonth;
-        }
-        return true;
-    }
-
     /**
      * Validates the values of the input fields to determine whether the submit button should be
      * enabled. Also displays a detailed error message and highlights the fields for which the value
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java
index 0adacd5..4f80741 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarkswidget/BookmarkWidgetService.java
@@ -288,7 +288,7 @@
             mWidgetId = widgetId;
             mPreferences = getWidgetState(mContext, mWidgetId);
             mIconColor = ApiCompatibilityUtils.getColor(
-                    mContext.getResources(), R.color.default_icon_color);
+                    mContext.getResources(), R.color.default_icon_color_dark);
         }
 
         @UiThread
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java
index 52f6baf5..742c07d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/Stack.java
@@ -6,10 +6,12 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.RectF;
 import android.support.annotation.IntDef;
+import android.util.Pair;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.Interpolator;
 
@@ -17,6 +19,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.animation.CompositorAnimator;
+import org.chromium.chrome.browser.compositor.animation.FloatProperty;
 import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
 import org.chromium.chrome.browser.compositor.layouts.Layout.Orientation;
@@ -32,6 +35,8 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Iterator;
 
 /**
  * Handles all the drawing and events of a stack of stackTabs.
@@ -222,6 +227,7 @@
 
     // Running set of animations applied to tabs.
     private ChromeAnimation<?> mTabAnimations;
+    private Pair<AnimatorSet, ArrayList<FloatProperty>> mAnimatorSetTabAnimations;
     private Animator mViewAnimations;
 
     // The parent Layout
@@ -548,17 +554,23 @@
                 // Build the AnimatorSet using the TabSwitcherAnimationFactory.
                 // This will give us the appropriate AnimatorSet based on the current
                 // state of the tab switcher and the OverviewAnimationType specified.
-                mTabAnimations = mAnimationFactory.createAnimatorSetForType(type, this, mStackTabs,
-                        focusIndex, sourceIndex, mSpacing, getDiscardRange());
+                mTabAnimations = mAnimationFactory.createChromeAnimationSetForType(type, this,
+                        mStackTabs, focusIndex, sourceIndex, mSpacing, getDiscardRange());
+                mAnimatorSetTabAnimations = mAnimationFactory.createAnimatorSetForType(type, this,
+                        mStackTabs, focusIndex, sourceIndex, mSpacing, getDiscardRange());
             }
 
             if (mTabAnimations != null) mTabAnimations.start();
+            if (mAnimatorSetTabAnimations != null) mAnimatorSetTabAnimations.first.start();
             if (mViewAnimations != null) mViewAnimations.start();
-            if (mTabAnimations != null || mViewAnimations != null) {
+            if (mTabAnimations != null || mAnimatorSetTabAnimations != null
+                    || mViewAnimations != null) {
                 mLayout.onStackAnimationStarted();
             }
 
-            if ((mTabAnimations == null && mViewAnimations == null) || finishImmediately) {
+            if ((mTabAnimations == null && mAnimatorSetTabAnimations == null
+                        && mViewAnimations == null)
+                    || finishImmediately) {
                 finishAnimation(time);
             }
         }
@@ -573,8 +585,12 @@
      */
     protected void finishAnimation(long time) {
         if (mTabAnimations != null) mTabAnimations.updateAndFinish();
+        if (mAnimatorSetTabAnimations != null) mAnimatorSetTabAnimations.first.end();
         if (mViewAnimations != null) mViewAnimations.end();
-        if (mTabAnimations != null || mViewAnimations != null) mLayout.onStackAnimationFinished();
+        if (mTabAnimations != null || mAnimatorSetTabAnimations != null
+                || mViewAnimations != null) {
+            mLayout.onStackAnimationFinished();
+        }
 
         switch (mOverviewAnimationType) {
             case OverviewAnimationType.ENTER_STACK:
@@ -628,6 +644,7 @@
         mOverviewAnimationType = OverviewAnimationType.NONE;
 
         mTabAnimations = null;
+        mAnimatorSetTabAnimations = null;
         mViewAnimations = null;
     }
 
@@ -692,8 +709,8 @@
                         || mOverviewAnimationType == OverviewAnimationType.UNDISCARD
                         || mOverviewAnimationType == OverviewAnimationType.DISCARD_ALL)
                     && (type == OverviewAnimationType.DISCARD
-                               || type == OverviewAnimationType.UNDISCARD
-                               || type == OverviewAnimationType.DISCARD_ALL)) {
+                            || type == OverviewAnimationType.UNDISCARD
+                            || type == OverviewAnimationType.DISCARD_ALL)) {
                 return true;
             }
         }
@@ -709,6 +726,17 @@
                 || mOverviewAnimationType == OverviewAnimationType.UNDISCARD
                 || mOverviewAnimationType == OverviewAnimationType.DISCARD_ALL) {
             mTabAnimations.cancel(null, StackTab.Property.SCROLL_OFFSET);
+            if (mAnimatorSetTabAnimations != null) {
+                Iterator<FloatProperty> propertyIterator =
+                        mAnimatorSetTabAnimations.second.iterator();
+                Iterator<Animator> animatorIterator =
+                        mAnimatorSetTabAnimations.first.getChildAnimations().iterator();
+
+                while (animatorIterator.hasNext()) {
+                    CompositorAnimator a = (CompositorAnimator) animatorIterator.next();
+                    if (propertyIterator.next() == StackTab.SCROLL_OFFSET) a.cancel();
+                }
+            }
             return true;
         }
         return false;
@@ -738,30 +766,44 @@
     public boolean onUpdateCompositorAnimations(long time, boolean jumpToEnd) {
         if (!jumpToEnd) updateScrollOffset(time);
 
-        boolean finished = true;
+        boolean chromeAnimationsFinished = true;
         if (mTabAnimations != null) {
-            if (jumpToEnd) {
-                finished = mTabAnimations.finished();
-            } else {
-                finished = mTabAnimations.update(time);
-            }
-            finishAnimationsIfDone(time, jumpToEnd);
+            chromeAnimationsFinished =
+                    jumpToEnd ? mTabAnimations.finished() : mTabAnimations.update(time);
         }
 
+        boolean animatorSetFinished = true;
+        if (mAnimatorSetTabAnimations != null) {
+            animatorSetFinished = jumpToEnd ? true : !mAnimatorSetTabAnimations.first.isRunning();
+        }
+
+        if (mTabAnimations != null || mAnimatorSetTabAnimations != null) {
+            finishAnimationsIfDone(time, jumpToEnd);
+        }
         if (jumpToEnd) forceScrollStop();
-        return finished;
+
+        return chromeAnimationsFinished && animatorSetFinished;
     }
 
     private void finishAnimationsIfDone(long time, boolean jumpToEnd) {
         boolean hasViewAnimations = mViewAnimations != null;
-        boolean hasTabAnimations = mTabAnimations != null;
-        boolean hasAnimations = hasViewAnimations || hasTabAnimations;
         boolean isViewFinished = hasViewAnimations ? !mViewAnimations.isRunning() : true;
+
+        boolean hasTabAnimations = mTabAnimations != null;
         boolean isTabFinished = hasTabAnimations ? mTabAnimations.finished() : true;
 
+        boolean hasAnimatorSetTabAnimations = mAnimatorSetTabAnimations != null;
+        boolean isAnimatorSetTabFinished =
+                hasAnimatorSetTabAnimations ? !mAnimatorSetTabAnimations.first.isRunning() : true;
+
+        boolean hasAnimations =
+                hasViewAnimations || hasTabAnimations || hasAnimatorSetTabAnimations;
+
         boolean shouldFinish = jumpToEnd && hasAnimations;
         shouldFinish |= hasAnimations && (!hasViewAnimations || isViewFinished)
-                && (!hasTabAnimations || isTabFinished);
+                && (!hasTabAnimations || isTabFinished)
+                && (!hasAnimatorSetTabAnimations || isAnimatorSetTabFinished);
+
         if (shouldFinish) finishAnimation(time);
     }
 
@@ -853,9 +895,9 @@
     private void discard(float x, float y, float amountX, float amountY) {
         if (mStackTabs == null
                 || (mOverviewAnimationType != OverviewAnimationType.NONE
-                           && mOverviewAnimationType != OverviewAnimationType.DISCARD
-                           && mOverviewAnimationType != OverviewAnimationType.DISCARD_ALL
-                           && mOverviewAnimationType != OverviewAnimationType.UNDISCARD)) {
+                        && mOverviewAnimationType != OverviewAnimationType.DISCARD
+                        && mOverviewAnimationType != OverviewAnimationType.DISCARD_ALL
+                        && mOverviewAnimationType != OverviewAnimationType.UNDISCARD)) {
             return;
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/StackAnimation.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/StackAnimation.java
index 36f389db..0f583bd4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/StackAnimation.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/stack/StackAnimation.java
@@ -6,11 +6,14 @@
 
 import static org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.AnimatableAnimation.addAnimation;
 
+import android.animation.AnimatorSet;
 import android.support.annotation.IntDef;
+import android.util.Pair;
 import android.view.animation.Interpolator;
 
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.animation.CompositorAnimator;
+import org.chromium.chrome.browser.compositor.animation.FloatProperty;
 import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation;
 import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animatable;
 import org.chromium.chrome.browser.compositor.layouts.Layout.Orientation;
@@ -19,6 +22,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 
 /**
  * A factory that builds animations for the tab stack.
@@ -165,8 +169,9 @@
      * @param discardRange  The range of the discard amount value.
      * @return              The resulting TabSwitcherAnimation that will animate the tabs.
      */
-    public ChromeAnimation<?> createAnimatorSetForType(@OverviewAnimationType int type, Stack stack,
-            StackTab[] tabs, int focusIndex, int sourceIndex, int spacing, float discardRange) {
+    public ChromeAnimation<?> createChromeAnimationSetForType(@OverviewAnimationType int type,
+            Stack stack, StackTab[] tabs, int focusIndex, int sourceIndex, int spacing,
+            float discardRange) {
         if (tabs == null) return null;
         switch (type) {
             case OverviewAnimationType.ENTER_STACK:
@@ -194,6 +199,27 @@
         }
     }
 
+    /**
+     * The wrapper method responsible for delegating the animations request to the appropriate
+     * helper method.  Not all parameters are used for each request.
+     *
+     * @param type          The type of animation to be created.  This is what
+     *                      determines which helper method is called.
+     * @param stack         The current stack.
+     * @param tabs          The tabs that make up the current stack that will
+     *                      be animated.
+     * @param focusIndex    The index of the tab that is the focus of this animation.
+     * @param sourceIndex   The index of the tab that triggered this animation.
+     * @param spacing       The default spacing between the tabs.
+     * @param discardRange  The range of the discard amount value.
+     * @return              The resulting TabSwitcherAnimation that will animate the tabs.
+     */
+    public Pair<AnimatorSet, ArrayList<FloatProperty>> createAnimatorSetForType(
+            @OverviewAnimationType int type, Stack stack, StackTab[] tabs, int focusIndex,
+            int sourceIndex, int spacing, float discardRange) {
+        return null;
+    }
+
     protected abstract float getScreenSizeInScrollDirection();
 
     protected abstract float getScreenPositionInScrollDirection(StackTab tab);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 95dc3416..e1da8afd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -53,7 +53,6 @@
 import org.chromium.chrome.browser.IntentHandler.ExternalAppId;
 import org.chromium.chrome.browser.KeyboardShortcuts;
 import org.chromium.chrome.browser.LaunchIntentDispatcher;
-import org.chromium.chrome.browser.WarmupManager;
 import org.chromium.chrome.browser.appmenu.AppMenuPropertiesDelegate;
 import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantFacade;
 import org.chromium.chrome.browser.browserservices.BrowserSessionContentHandler;
@@ -731,7 +730,7 @@
             // of users open several Custom Tabs in a row. The delay is there to avoid jank in the
             // transition animation when closing the tab.
             PostTask.postDelayedTask(UiThreadTaskTraits.DEFAULT,
-                    () -> WarmupManager.getInstance().createSpareWebContents(), 500);
+                    () -> CustomTabsConnection.createSpareWebContents(), 500);
         }
 
         handleFinishAndClose();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
index 55d5d1ce..35ce0e0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -35,6 +35,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.StrictModeContext;
+import org.chromium.base.SysUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.TimeUtils;
 import org.chromium.base.TraceEvent;
@@ -429,7 +430,7 @@
                     return;
                 }
                 try (TraceEvent e = TraceEvent.scoped("CreateSpareWebContents")) {
-                    WarmupManager.getInstance().createSpareWebContents();
+                    createSpareWebContents();
                 }
             });
         }
@@ -448,7 +449,7 @@
                 try (TraceEvent e = TraceEvent.scoped("WarmupInternalFinishInitialization")) {
                     // (4)
                     Profile profile = Profile.getLastUsedProfile();
-                    WarmupManager.getInstance().startPreconnectPredictorInitialization(profile);
+                    WarmupManager.startPreconnectPredictorInitialization(profile);
 
                     // (5)
                     // The throttling database uses shared preferences, that can cause a
@@ -508,7 +509,7 @@
     boolean lowConfidenceMayLaunchUrl(List<Bundle> likelyBundles) {
         ThreadUtils.assertOnUiThread();
         if (!preconnectUrls(likelyBundles)) return false;
-        WarmupManager.getInstance().createSpareWebContents();
+        createSpareWebContents();
         return true;
     }
 
@@ -1376,7 +1377,7 @@
             recordSpeculationStatusOnStart(SPECULATION_STATUS_ON_START_BACKGROUND_TAB);
             launchUrlInHiddenTab(session, url, extras);
         } else {
-            warmupManager.createSpareWebContents();
+            createSpareWebContents();
         }
         warmupManager.maybePreconnectUrlAndSubResources(profile, url);
     }
@@ -1497,4 +1498,9 @@
     @Nullable HiddenTabHolder.SpeculationParams getSpeculationParamsForTesting() {
         return mHiddenTabHolder.getSpeculationParamsForTesting();
     }
+
+    /* package */ static void createSpareWebContents() {
+        if (SysUtils.isLowEndDevice()) return;
+        WarmupManager.getInstance().createSpareWebContents(WarmupManager.FOR_CCT);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
index a875245..aa3a10a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
@@ -424,7 +424,7 @@
             webContents.resumeLoadingCreatedWebContents();
         } else {
             webContents = mWarmupManager.takeSpareWebContents(mIntentDataProvider.isIncognito(),
-                    false /*initiallyHidden*/);
+                    false /*initiallyHidden*/, WarmupManager.FOR_CCT);
             if (webContents != null) {
                 webContentsStateOnLaunch = WebContentsState.SPARE_WEBCONTENTS;
             } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
index 8952325..35f45b51 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
@@ -346,11 +346,9 @@
         if (params.getUrl().startsWith(WTAI_MC_URL_PREFIX)) {
             // wtai://wp/mc;number
             // number=string(phone-number)
-            Intent wtaiIntent = new Intent(Intent.ACTION_VIEW,
+            mDelegate.startActivity(new Intent(Intent.ACTION_VIEW,
                     Uri.parse(WebView.SCHEME_TEL
-                            + params.getUrl().substring(WTAI_MC_URL_PREFIX.length())));
-            wtaiIntent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
-            mDelegate.startActivity(wtaiIntent, false);
+                            + params.getUrl().substring(WTAI_MC_URL_PREFIX.length()))), false);
             if (DEBUG) Log.i(TAG, "OVERRIDE_WITH_EXTERNAL_INTENT wtai:// link handled");
             RecordUserAction.record("Android.PhoneIntent");
             return OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT;
@@ -405,9 +403,6 @@
         // Sanitize the Intent, ensuring web pages can not bypass browser
         // security (only access to BROWSABLE activities).
         intent.addCategory(Intent.CATEGORY_BROWSABLE);
-        // Do not target packages that have not been launched directly by the
-        // user at least once.
-        intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
         intent.setComponent(null);
         Intent selector = intent.getSelector();
         if (selector != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainer.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainer.java
index af7db4d..e5e4886 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainer.java
@@ -32,6 +32,7 @@
 import org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver;
 import org.chromium.content_public.browser.NavigationHandle;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.ui.KeyboardVisibilityDelegate.KeyboardVisibilityListener;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.display.DisplayAndroid;
 import org.chromium.ui.display.DisplayUtil;
@@ -44,7 +45,8 @@
  * When initiated from native code, special code is needed to keep the Java and native infobar in
  * sync, see NativeInfoBar.
  */
-public class InfoBarContainer extends SwipableOverlayView implements UserData {
+public class InfoBarContainer
+        extends SwipableOverlayView implements UserData, KeyboardVisibilityListener {
     private static final String TAG = "InfoBarContainer";
 
     private static final Class<InfoBarContainer> USER_DATA_KEY = InfoBarContainer.class;
@@ -248,8 +250,7 @@
         mLayout.addAnimationListener(mIPHSupport);
         addObserver(mIPHSupport);
 
-        mTab.getWindowAndroid().getKeyboardDelegate().addKeyboardVisibilityListener(
-                this::updateVisibilityForKeyboard);
+        mTab.getWindowAndroid().getKeyboardDelegate().addKeyboardVisibilityListener(this);
 
         // Chromium's InfoBarContainer may add an InfoBar immediately during this initialization
         // call, so make sure everything in the InfoBarContainer is completely ready beforehand.
@@ -426,6 +427,10 @@
         if (activity != null && mBottomSheetObserver != null && activity.getBottomSheet() != null) {
             activity.getBottomSheet().removeObserver(mBottomSheetObserver);
         }
+        WindowAndroid windowAndroid = mTab.getWindowAndroid();
+        if (windowAndroid != null) {
+            windowAndroid.getKeyboardDelegate().removeKeyboardVisibilityListener(this);
+        }
         mLayout.removeAnimationListener(mIPHSupport);
         removeObserver(mIPHSupport);
         mDestroyed = true;
@@ -517,7 +522,8 @@
         }
     }
 
-    private void updateVisibilityForKeyboard(boolean isKeyboardShowing) {
+    @Override
+    public void keyboardVisibilityChanged(boolean isKeyboardShowing) {
         boolean isShowing = (getVisibility() == View.VISIBLE);
         if (isKeyboardShowing) {
             if (isShowing) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
index 2c5f3ec5..5cd45ff 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
@@ -157,7 +157,9 @@
     /** Controls the parameter of {@link NativeInitializationController#startBackgroundTasks}.*/
     @VisibleForTesting
     public boolean shouldAllocateChildConnection() {
-        return true;
+        // If a spare WebContents exists, a child connection has already been allocated that will be
+        // used by the next created tab.
+        return !WarmupManager.getInstance().hasSpareWebContents();
     }
 
     @CallSuper
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 41d7b40..ae67a091 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -973,7 +973,7 @@
             boolean creatingWebContents = webContents == null;
             if (creatingWebContents) {
                 webContents = WarmupManager.getInstance().takeSpareWebContents(
-                        isIncognito(), initiallyHidden);
+                        isIncognito(), initiallyHidden, isCurrentlyACustomTab());
                 if (webContents == null) {
                     webContents =
                             WebContentsFactory.createWebContents(isIncognito(), initiallyHidden);
@@ -1541,7 +1541,12 @@
 
         if (mPendingLoadParams != null) {
             assert isFrozen();
-            initWebContents(WebContentsFactory.createWebContents(isIncognito(), isHidden()));
+            WebContents webContents = WarmupManager.getInstance().takeSpareWebContents(
+                    isIncognito(), isHidden(), isCurrentlyACustomTab());
+            if (webContents == null) {
+                webContents = WebContentsFactory.createWebContents(isIncognito(), isHidden());
+            }
+            initWebContents(webContents);
             loadUrl(mPendingLoadParams);
             mPendingLoadParams = null;
             return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDisclosureSnackbarController.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDisclosureSnackbarController.java
index 583f60a0..d7660f1c8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDisclosureSnackbarController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDisclosureSnackbarController.java
@@ -7,6 +7,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.snackbar.Snackbar;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
+import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.webapk.lib.common.WebApkConstants;
 
 /**
@@ -72,6 +73,11 @@
             return false;
         }
 
+        // This UI isn't great for no-touch and will be handled a different way.
+        if (FeatureUtilities.isNoTouchModeEnabled()) {
+            return false;
+        }
+
         // This will be null for Webapps or bound WebAPKs.
         String packageName = activity.getWebApkPackageName();
         // Show for unbound WebAPKs.
diff --git a/chrome/android/java_templates/ChromeSwitches.java.tmpl b/chrome/android/java_templates/ChromeSwitches.java.tmpl
index 0fa50fbf..436000a 100644
--- a/chrome/android/java_templates/ChromeSwitches.java.tmpl
+++ b/chrome/android/java_templates/ChromeSwitches.java.tmpl
@@ -77,6 +77,12 @@
      */
     public static final String DISABLE_TAB_MERGING_FOR_TESTING = "disable-tab-merging";
 
+    /**
+     * Aggressively pre-warms renderers when Chrome is backgrounded. Currently only works for
+     * SingleTabActivity-derived Activities.
+     */
+    public static final String AGGRESSIVELY_PREWARM_RENDERERS = "aggressively-prewarm-renderers";
+
     ///////////////////////////////////////////////////////////////////////////////////////////////
     // Native Switches
     ///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
index 11af81e..b4fb256 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
@@ -915,7 +915,6 @@
     }
 
     @Test
-    @DisabledTest(message = "crbug.com/940831")
     @LargeTest
     @Feature({"Android-TabSwitcher"})
     @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/WarmupManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/WarmupManagerTest.java
index cca31e5..3b10124 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/WarmupManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/WarmupManagerTest.java
@@ -4,9 +4,6 @@
 
 package org.chromium.chrome.browser;
 
-import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_LOW_END_DEVICE;
-import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE;
-
 import android.content.Context;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.annotation.UiThreadTest;
@@ -24,7 +21,6 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.MetricsUtils;
-import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -74,24 +70,15 @@
 
     @Test
     @SmallTest
-    @UiThreadTest
-    @Restriction(RESTRICTION_TYPE_LOW_END_DEVICE)
-    public void testNoSpareRendererOnLowEndDevices() throws Throwable {
-        mWarmupManager.createSpareWebContents();
-        Assert.assertFalse(mWarmupManager.hasSpareWebContents());
-    }
-
-    @Test
-    @SmallTest
-    @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
     public void testCreateAndTakeSpareRenderer() {
         final AtomicBoolean isRenderViewReady = new AtomicBoolean();
         final AtomicReference<WebContents> webContentsReference = new AtomicReference<>();
 
         ThreadUtils.runOnUiThread(() -> {
-            mWarmupManager.createSpareWebContents();
+            mWarmupManager.createSpareWebContents(!WarmupManager.FOR_CCT);
             Assert.assertTrue(mWarmupManager.hasSpareWebContents());
-            WebContents webContents = mWarmupManager.takeSpareWebContents(false, false);
+            WebContents webContents =
+                    mWarmupManager.takeSpareWebContents(false, false, !WarmupManager.FOR_CCT);
             Assert.assertNotNull(webContents);
             Assert.assertFalse(mWarmupManager.hasSpareWebContents());
             WebContentsObserver observer = new WebContentsObserver(webContents) {
@@ -119,10 +106,10 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
     public void testTakeSpareWebContents() throws Throwable {
-        mWarmupManager.createSpareWebContents();
-        WebContents webContents = mWarmupManager.takeSpareWebContents(false, false);
+        mWarmupManager.createSpareWebContents(!WarmupManager.FOR_CCT);
+        WebContents webContents =
+                mWarmupManager.takeSpareWebContents(false, false, !WarmupManager.FOR_CCT);
         Assert.assertNotNull(webContents);
         Assert.assertFalse(mWarmupManager.hasSpareWebContents());
         webContents.destroy();
@@ -131,31 +118,30 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
     public void testTakeSpareWebContentsChecksArguments() throws Throwable {
-        mWarmupManager.createSpareWebContents();
-        Assert.assertNull(mWarmupManager.takeSpareWebContents(true, false));
-        Assert.assertNull(mWarmupManager.takeSpareWebContents(true, true));
+        mWarmupManager.createSpareWebContents(!WarmupManager.FOR_CCT);
+        Assert.assertNull(mWarmupManager.takeSpareWebContents(true, false, !WarmupManager.FOR_CCT));
+        Assert.assertNull(mWarmupManager.takeSpareWebContents(true, true, !WarmupManager.FOR_CCT));
         Assert.assertTrue(mWarmupManager.hasSpareWebContents());
-        Assert.assertNotNull(mWarmupManager.takeSpareWebContents(false, true));
+        Assert.assertNotNull(
+                mWarmupManager.takeSpareWebContents(false, true, !WarmupManager.FOR_CCT));
         Assert.assertFalse(mWarmupManager.hasSpareWebContents());
     }
 
     @Test
     @SmallTest
     @UiThreadTest
-    @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
     public void testClearsDeadWebContents() throws Throwable {
-        mWarmupManager.createSpareWebContents();
+        mWarmupManager.createSpareWebContents(!WarmupManager.FOR_CCT);
         WebContentsUtils.simulateRendererKilled(mWarmupManager.mSpareWebContents, false);
-        Assert.assertNull(mWarmupManager.takeSpareWebContents(false, false));
+        Assert.assertNull(
+                mWarmupManager.takeSpareWebContents(false, false, !WarmupManager.FOR_CCT));
     }
 
     @Test
     @SmallTest
     @UiThreadTest
-    @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
-    public void testRecordSpareWebContentsStatus() throws Throwable {
+    public void testRecordWebContentsStatus() throws Throwable {
         String name = WarmupManager.WEBCONTENTS_STATUS_HISTOGRAM;
         MetricsUtils.HistogramDelta createdDelta =
                 new MetricsUtils.HistogramDelta(name, WarmupManager.WebContentsStatus.CREATED);
@@ -165,27 +151,45 @@
                 new MetricsUtils.HistogramDelta(name, WarmupManager.WebContentsStatus.KILLED);
         MetricsUtils.HistogramDelta destroyedDelta =
                 new MetricsUtils.HistogramDelta(name, WarmupManager.WebContentsStatus.DESTROYED);
+        MetricsUtils.HistogramDelta stolenDelta =
+                new MetricsUtils.HistogramDelta(name, WarmupManager.WebContentsStatus.STOLEN);
 
         // Created, used.
-        mWarmupManager.createSpareWebContents();
+        mWarmupManager.createSpareWebContents(WarmupManager.FOR_CCT);
         Assert.assertEquals(1, createdDelta.getDelta());
-        Assert.assertNotNull(mWarmupManager.takeSpareWebContents(false, false));
+        Assert.assertNotNull(
+                mWarmupManager.takeSpareWebContents(false, false, WarmupManager.FOR_CCT));
         Assert.assertEquals(1, usedDelta.getDelta());
 
         // Created, killed.
-        mWarmupManager.createSpareWebContents();
+        mWarmupManager.createSpareWebContents(WarmupManager.FOR_CCT);
         Assert.assertEquals(2, createdDelta.getDelta());
         Assert.assertNotNull(mWarmupManager.mSpareWebContents);
         WebContentsUtils.simulateRendererKilled(mWarmupManager.mSpareWebContents, false);
         Assert.assertEquals(1, killedDelta.getDelta());
-        Assert.assertNull(mWarmupManager.takeSpareWebContents(false, false));
+        Assert.assertNull(mWarmupManager.takeSpareWebContents(false, false, WarmupManager.FOR_CCT));
 
         // Created, destroyed.
-        mWarmupManager.createSpareWebContents();
+        mWarmupManager.createSpareWebContents(WarmupManager.FOR_CCT);
         Assert.assertEquals(3, createdDelta.getDelta());
         Assert.assertNotNull(mWarmupManager.mSpareWebContents);
         mWarmupManager.destroySpareWebContents();
         Assert.assertEquals(1, destroyedDelta.getDelta());
+
+        // Created, stolen.
+        mWarmupManager.createSpareWebContents(WarmupManager.FOR_CCT);
+        Assert.assertEquals(4, createdDelta.getDelta());
+        Assert.assertNotNull(
+                mWarmupManager.takeSpareWebContents(false, false, !WarmupManager.FOR_CCT));
+        Assert.assertEquals(1, stolenDelta.getDelta());
+
+        // Created, used, not for CCT.
+        mWarmupManager.createSpareWebContents(!WarmupManager.FOR_CCT);
+        Assert.assertEquals(4, createdDelta.getDelta());
+        Assert.assertNotNull(
+                mWarmupManager.takeSpareWebContents(false, false, !WarmupManager.FOR_CCT));
+        Assert.assertEquals(1, stolenDelta.getDelta());
+        Assert.assertEquals(1, usedDelta.getDelta());
     }
 
     /** Checks that the View inflation works. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
index b639588..7852f56f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -1589,8 +1589,8 @@
     @Test
     @SmallTest
     @Feature({"ContextualSearch"})
-    @DisableIf.Build(message = "Flaky except on M-Phone.  See https://crbug.com/837998",
-            sdk_is_less_than = Build.VERSION_CODES.M, sdk_is_greater_than = Build.VERSION_CODES.M)
+    @DisableIf.Build(sdk_is_less_than = Build.VERSION_CODES.M,
+            message = "Flaky except on M+ Phones.  See https://crbug.com/837998")
     @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
     public void
     testLongPressGestureFollowedByTapDoesntSelect() throws InterruptedException, TimeoutException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionTest.java
index 9450fbd..4007305e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionTest.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.customtabs;
 
+import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_LOW_END_DEVICE;
 import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE;
 
 import android.content.ComponentName;
@@ -122,7 +123,8 @@
         ThreadUtils.runOnUiThreadBlocking(() -> {
             WarmupManager warmupManager = WarmupManager.getInstance();
             Assert.assertTrue(warmupManager.hasSpareWebContents());
-            WebContents webContents = warmupManager.takeSpareWebContents(false, false);
+            WebContents webContents =
+                    warmupManager.takeSpareWebContents(false, false, WarmupManager.FOR_CCT);
             Assert.assertNotNull(webContents);
             Assert.assertFalse(warmupManager.hasSpareWebContents());
             webContents.destroy();
@@ -131,6 +133,20 @@
 
     @Test
     @SmallTest
+    @Restriction(RESTRICTION_TYPE_LOW_END_DEVICE)
+    public void testDoNotCreateSpareRendererOnLowEnd() throws Exception {
+        CustomTabsTestUtils.warmUpAndWait();
+        // On UI thread because:
+        // 1. takeSpareWebContents needs to be called from the UI thread.
+        // 2. warmup() is non-blocking and posts tasks to the UI thread, it ensures proper ordering.
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            WarmupManager warmupManager = WarmupManager.getInstance();
+            Assert.assertFalse(warmupManager.hasSpareWebContents());
+        });
+    }
+
+    @Test
+    @SmallTest
     @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
     public void testCreateSpareRendererCanBeRecreated() throws Exception {
         CustomTabsTestUtils.warmUpAndWait();
@@ -352,12 +368,14 @@
 
         mCustomTabsConnection.mayLaunchUrl(token, Uri.parse(URL), null, urls);
         ThreadUtils.runOnUiThreadBlocking(
-                () -> Assert.assertNull(WarmupManager.getInstance()
-                        .takeSpareWebContents(false, false)));
+                ()
+                        -> Assert.assertNull(WarmupManager.getInstance().takeSpareWebContents(
+                                false, false, WarmupManager.FOR_CCT)));
     }
 
     private void assertSpareWebContentsNotNullAndDestroy() {
-        WebContents webContents = WarmupManager.getInstance().takeSpareWebContents(false, false);
+        WebContents webContents = WarmupManager.getInstance().takeSpareWebContents(
+                false, false, WarmupManager.FOR_CCT);
         Assert.assertNotNull(webContents);
         webContents.destroy();
     }
@@ -558,8 +576,9 @@
 
         Assert.assertTrue(mCustomTabsConnection.mayLaunchUrl(token, Uri.parse(URL), null, null));
         ThreadUtils.runOnUiThreadBlocking(
-                () -> Assert.assertNull(WarmupManager.getInstance()
-                        .takeSpareWebContents(false, false)));
+                ()
+                        -> Assert.assertNull(WarmupManager.getInstance().takeSpareWebContents(
+                                false, false, WarmupManager.FOR_CCT)));
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
index 4f5cc0f..e4e83d5d3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
@@ -1950,18 +1950,6 @@
             Assert.assertEquals(expectStartFile, mDelegate.startFileIntentCalled);
             Assert.assertEquals(expectProxyForIA, mDelegate.mCalledWithProxy);
 
-            if (startActivityCalled) {
-                final Intent intent = mDelegate.startActivityIntent;
-                final Uri uri = intent.getData();
-                if (uri == null || uri.getScheme() == null || !uri.getScheme().equals("market")) {
-                    Assert.assertTrue("The intent URL " + mUrl + " (" + uri
-                                    + ") doesn't have FLAG_EXCLUDE_STOPPED_PACKAGES set\n",
-                            (mDelegate.startActivityIntent.getFlags()
-                                    & Intent.FLAG_EXCLUDE_STOPPED_PACKAGES)
-                                    != 0);
-                }
-            }
-
             if (startActivityCalled && expectSaneIntent) {
                 checkIntentSanity(mDelegate.startActivityIntent, "Intent");
                 if (mDelegate.startActivityIntent.getSelector() != null) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreatorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreatorTest.java
index 04eb55ae..84b0fda 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreatorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreatorTest.java
@@ -120,11 +120,8 @@
 
     /**
      * Verify that the spare WebContents is used.
-     *
-     * Spare WebContents are not created on low-devices, so don't run the test.
      */
     @Test
-    @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
     @MediumTest
     @Feature({"Browser"})
     public void testCreateNewTabTakesSpareWebContents() throws Throwable {
@@ -132,7 +129,7 @@
             @Override
             public void run() {
                 Tab currentTab = mActivityTestRule.getActivity().getActivityTab();
-                WarmupManager.getInstance().createSpareWebContents();
+                WarmupManager.getInstance().createSpareWebContents(!WarmupManager.FOR_CCT);
                 Assert.assertTrue(WarmupManager.getInstance().hasSpareWebContents());
                 mActivityTestRule.getActivity().getCurrentTabCreator().createNewTab(
                         new LoadUrlParams(mTestServer.getURL(TEST_PATH)),
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java
index 35fc421..3b25edd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java
@@ -334,6 +334,8 @@
      */
     @Test
     @MediumTest
+    @DisableIf.
+    Build(message = "K/M https://crbug.com/897259", sdk_is_less_than = Build.VERSION_CODES.N)
     @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
     public void testPresentationLocksFocus() throws InterruptedException {
         presentationLocksFocusImpl(
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerTest.java
index bbe4a99..fe57b658 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerTest.java
@@ -344,7 +344,8 @@
 
     private WebContents prepareSpareWebcontents() {
         WebContents webContents = mock(WebContents.class);
-        when(mWarmupManager.takeSpareWebContents(anyBoolean(), anyBoolean()))
+        when(mWarmupManager.takeSpareWebContents(
+                     anyBoolean(), anyBoolean(), eq(WarmupManager.FOR_CCT)))
                 .thenReturn(webContents);
         return webContents;
     }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 65ea7792..00f5271 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1072,16 +1072,12 @@
     "performance_manager/common/page_almost_idle_data.h",
     "performance_manager/decorators/page_almost_idle_decorator.cc",
     "performance_manager/decorators/page_almost_idle_decorator.h",
-    "performance_manager/frame_resource_coordinator.cc",
-    "performance_manager/frame_resource_coordinator.h",
     "performance_manager/graph/frame_node_impl.cc",
     "performance_manager/graph/frame_node_impl.h",
     "performance_manager/graph/graph.cc",
     "performance_manager/graph/graph.h",
     "performance_manager/graph/graph_introspector_impl.cc",
     "performance_manager/graph/graph_introspector_impl.h",
-    "performance_manager/graph/graph_node_provider_impl.cc",
-    "performance_manager/graph/graph_node_provider_impl.h",
     "performance_manager/graph/node_attached_data.cc",
     "performance_manager/graph/node_attached_data.h",
     "performance_manager/graph/node_attached_data_impl.h",
@@ -1102,21 +1098,14 @@
     "performance_manager/observers/page_signal_generator_impl.h",
     "performance_manager/observers/working_set_trimmer_win.cc",
     "performance_manager/observers/working_set_trimmer_win.h",
-    "performance_manager/page_resource_coordinator.cc",
-    "performance_manager/page_resource_coordinator.h",
     "performance_manager/performance_manager.cc",
     "performance_manager/performance_manager.h",
     "performance_manager/performance_manager_tab_helper.cc",
     "performance_manager/performance_manager_tab_helper.h",
-    "performance_manager/process_resource_coordinator.cc",
-    "performance_manager/process_resource_coordinator.h",
     "performance_manager/render_process_user_data.cc",
     "performance_manager/render_process_user_data.h",
     "performance_manager/resource_coordinator_clock.cc",
     "performance_manager/resource_coordinator_clock.h",
-    "performance_manager/resource_coordinator_interface.h",
-    "performance_manager/system_resource_coordinator.cc",
-    "performance_manager/system_resource_coordinator.h",
     "performance_manager/webui_graph_dump_impl.cc",
     "performance_manager/webui_graph_dump_impl.h",
     "performance_monitor/metric_evaluator_helper_win.cc",
@@ -1462,6 +1451,8 @@
     "resource_coordinator/utils.h",
     "resources_util.cc",
     "resources_util.h",
+    "scoped_visibility_tracker.cc",
+    "scoped_visibility_tracker.h",
     "search/instant_io_context.cc",
     "search/instant_io_context.h",
     "search/ntp_icon_source.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index e352258..cd01abad 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3494,11 +3494,6 @@
          "")},
 
 #if defined(OS_CHROMEOS)
-    {"enable-app-shortcut-search",
-     flag_descriptions::kEnableAppShortcutSearchName,
-     flag_descriptions::kEnableAppShortcutSearchDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(app_list_features::kEnableAppShortcutSearch)},
-
     {"enable-play-store-search", flag_descriptions::kEnablePlayStoreSearchName,
      flag_descriptions::kEnablePlayStoreSearchDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(app_list_features::kEnablePlayStoreAppSearch)},
@@ -4091,6 +4086,13 @@
      FEATURE_VALUE_TYPE(views::kInstallableInkDropFeature)},
 #endif  // defined(TOOLKIT_VIEWS)
 
+#if defined(OS_CHROMEOS)
+    {"enable-assistant-launcher-integration",
+     flag_descriptions::kEnableAssistantLauncherIntegrationName,
+     flag_descriptions::kEnableAssistantLauncherIntegrationDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(app_list_features::kEnableEmbeddedAssistantUI)},
+#endif  // OS_CHROMEOS
+
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
     // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 20de66e..f532dbdc 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -5611,3 +5611,13 @@
   Profile* profile = Profile::FromBrowserContext(browser_context);
   return AccessibilityLabelsServiceFactory::GetForProfile(profile)->GetAXMode();
 }
+
+#if defined(OS_ANDROID)
+content::ContentBrowserClient::WideColorGamutHeuristic
+ChromeContentBrowserClient::GetWideColorGamutHeuristic() const {
+  if (features::UseDisplayWideColorGamut()) {
+    return WideColorGamutHeuristic::kUseDisplay;
+  }
+  return WideColorGamutHeuristic::kNone;
+}
+#endif
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 5ba3c8dc..36e37d1 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -579,6 +579,11 @@
   ui::AXMode GetAXModeForBrowserContext(
       content::BrowserContext* browser_context) override;
 
+#if defined(OS_ANDROID)
+  ContentBrowserClient::WideColorGamutHeuristic GetWideColorGamutHeuristic()
+      const override;
+#endif
+
   // Determines the committed previews state for the passed in params.
   static content::PreviewsState DetermineCommittedPreviewsForURL(
       const GURL& url,
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.cc b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.cc
index 75d7cec..044c8c0e 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_app_setup_controller_impl.cc
@@ -22,6 +22,7 @@
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
+#include "net/base/url_util.h"
 #include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "url/gurl.h"
 
@@ -85,9 +86,9 @@
               kDefaultToPersistCookieValue, std::string() /* domain */,
               std::string() /* path */, base::Time::Now() /* creation_time */,
               base::Time() /* expiration_time */,
-              base::Time::Now() /* last_access_time */, true /* secure */,
-              false /* http_only */, net::CookieSameSite::STRICT_MODE,
-              net::COOKIE_PRIORITY_DEFAULT),
+              base::Time::Now() /* last_access_time */,
+              !net::IsLocalhost(app_url) /* secure */, false /* http_only */,
+              net::CookieSameSite::STRICT_MODE, net::COOKIE_PRIORITY_DEFAULT),
           "https", false /* modify_http_only */,
           base::BindOnce(&AndroidSmsAppSetupControllerImpl::
                              OnSetRememberDeviceByDefaultCookieResult,
@@ -272,9 +273,9 @@
               std::string() /* domain */, std::string() /* path */,
               base::Time::Now() /* creation_time */,
               base::Time() /* expiration_time */,
-              base::Time::Now() /* last_access_time */, true /* secure */,
-              false /* http_only */, net::CookieSameSite::STRICT_MODE,
-              net::COOKIE_PRIORITY_DEFAULT),
+              base::Time::Now() /* last_access_time */,
+              !net::IsLocalhost(app_url) /* secure */, false /* http_only */,
+              net::CookieSameSite::STRICT_MODE, net::COOKIE_PRIORITY_DEFAULT),
           "https", false /* modify_http_only */,
           base::BindOnce(
               &AndroidSmsAppSetupControllerImpl::OnSetMigrationCookieResult,
diff --git a/chrome/browser/chromeos/android_sms/android_sms_switches.cc b/chrome/browser/chromeos/android_sms/android_sms_switches.cc
index 19b460d..e6ca818 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_switches.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_switches.cc
@@ -8,4 +8,7 @@
 
 const char kAlternateAndroidMessagesUrl[] = "alternate-android-messages-url";
 
+const char kAlternateAndroidMessagesInstallUrl[] =
+    "alternate-android-messages-install-url";
+
 }  // namespace switches
diff --git a/chrome/browser/chromeos/android_sms/android_sms_switches.h b/chrome/browser/chromeos/android_sms/android_sms_switches.h
index d8020ff..4106bd0 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_switches.h
+++ b/chrome/browser/chromeos/android_sms/android_sms_switches.h
@@ -11,6 +11,10 @@
 // Android Messages for Web url used by AndroidSmsService.
 extern const char kAlternateAndroidMessagesUrl[];
 
+// When specified with a url string as parameter, the given url overrides the
+// Android Messages for Web PWA installation url used by AndroidSmsService.
+extern const char kAlternateAndroidMessagesInstallUrl[];
+
 }  // namespace switches
 
 #endif  // CHROME_BROWSER_CHROMEOS_ANDROID_SMS_ANDROID_SMS_SWITCHES_H_
diff --git a/chrome/browser/chromeos/android_sms/android_sms_urls.cc b/chrome/browser/chromeos/android_sms/android_sms_urls.cc
index f2c34f2f..9b26907 100644
--- a/chrome/browser/chromeos/android_sms/android_sms_urls.cc
+++ b/chrome/browser/chromeos/android_sms/android_sms_urls.cc
@@ -56,12 +56,22 @@
 }
 
 GURL GetAndroidMessagesURL(bool use_install_url, PwaDomain pwa_domain) {
-  // If a custom URL was passed via a command line argument, use it.
-  std::string url_from_command_line_arg =
-      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-          switches::kAlternateAndroidMessagesUrl);
-  if (!url_from_command_line_arg.empty())
-    return GURL(url_from_command_line_arg);
+  // If present, use commandline override for the preferred domain.
+  if (pwa_domain == GetPreferredPwaDomain()) {
+    std::string url_from_command_line_arg;
+    if (use_install_url) {
+      url_from_command_line_arg =
+          base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+              switches::kAlternateAndroidMessagesInstallUrl);
+    } else {
+      url_from_command_line_arg =
+          base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+              switches::kAlternateAndroidMessagesUrl);
+    }
+
+    if (!url_from_command_line_arg.empty())
+      return GURL(url_from_command_line_arg);
+  }
 
   switch (pwa_domain) {
     case PwaDomain::kProdAndroid:
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc b/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
index 3843dda..d85d40d7 100644
--- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
+++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
@@ -547,7 +547,7 @@
                              "\",\"vpnConfigDisabled\":true}");
 }
 
-TEST_P(ArcPolicyBridgeAffiliatedTest, ApkCacheEnabledTest) {
+TEST_P(ArcPolicyBridgeAffiliatedTest, DISABLED_ApkCacheEnabledTest) {
   const std::string apk_cache_enabled_policy(
       "{\"apkCacheEnabled\":true,\"guid\":\"" + instance_guid() + "\"}");
   policy_map().Set(policy::key::kArcPolicy, policy::POLICY_LEVEL_MANDATORY,
diff --git a/chrome/browser/chromeos/arc/tracing/arc_tracing_event_matcher.cc b/chrome/browser/chromeos/arc/tracing/arc_tracing_event_matcher.cc
index 140f78f..657c5c9 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_tracing_event_matcher.cc
+++ b/chrome/browser/chromeos/arc/tracing/arc_tracing_event_matcher.cc
@@ -16,7 +16,7 @@
   DCHECK(position);
   category_ = data.substr(0, position);
   name_ = data.substr(position + 1);
-  DCHECK(!category_.empty() && !name_.empty());
+  DCHECK(!category_.empty());
   position = name_.find('(');
   if (position == std::string::npos)
     return;
diff --git a/chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.cc b/chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.cc
index da7bedb..ce26725 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.cc
+++ b/chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.cc
@@ -47,18 +47,8 @@
 constexpr char kDequeueBufferQuery[] = "android:dequeueBuffer";
 constexpr char kQueueBufferQuery[] = "android:queueBuffer";
 
-constexpr char kAttachSurfaceQueury[] =
-    "toplevel:OnLibevent/exo:Surface::Attach";
-constexpr char kProduceTransferableResourceQuery[] =
-    "toplevel:OnLibevent/exo:Surface::Commit/"
-    "exo:Buffer::ProduceTransferableResource";
-constexpr char kReleaseContentQuery[] =
-    "toplevel:MessageLoop::RunTask/exo:Buffer::ReleaseContents";
 constexpr char kBarrierOrderingSubQuery[] =
     "gpu:CommandBufferProxyImpl::OrderingBarrier";
-constexpr char kBarrierFlushQuery[] =
-    "toplevel:MessageLoop::RunTask/gpu:Scheduler::RunNextTask/"
-    "gpu:CommandBufferStub::OnAsyncFlush";
 constexpr char kBufferInUseQuery[] = "exo:BufferInUse";
 constexpr char kHandleMessageRefreshQuery[] =
     "android:onMessageReceived/android:handleMessageRefresh";
@@ -69,6 +59,14 @@
 constexpr char kVsyncQuery0[] = "android:HW_VSYNC_0|0";
 constexpr char kVsyncQuery1[] = "android:HW_VSYNC_0|1";
 
+constexpr char kBarrierFlushMatcher[] = "gpu:CommandBufferStub::OnAsyncFlush";
+
+constexpr char kExoSurfaceAttachMatcher[] = "exo:Surface::Attach";
+constexpr char kExoBufferProduceResourceMatcher[] =
+    "exo:Buffer::ProduceTransferableResource";
+constexpr char kExoBufferReleaseContentsMatcher[] =
+    "exo:Buffer::ReleaseContents";
+
 constexpr ssize_t kInvalidBufferIndex = -1;
 
 // Helper factory class that produces graphic buffer events from the giving
@@ -91,16 +89,17 @@
   BufferGraphicsEventMapper() {
     // exo rules
     rules_.emplace_back(std::make_pair(
-        std::make_unique<ArcTracingEventMatcher>("exo:Surface::Attach"),
+        std::make_unique<ArcTracingEventMatcher>(kExoSurfaceAttachMatcher),
         MappingRule(BufferEventType::kExoSurfaceAttach,
                     BufferEventType::kNone)));
     rules_.emplace_back(
         std::make_pair(std::make_unique<ArcTracingEventMatcher>(
-                           "exo:Buffer::ProduceTransferableResource"),
+                           kExoBufferProduceResourceMatcher),
                        MappingRule(BufferEventType::kExoProduceResource,
                                    BufferEventType::kNone)));
     rules_.emplace_back(std::make_pair(
-        std::make_unique<ArcTracingEventMatcher>("exo:Buffer::ReleaseContents"),
+        std::make_unique<ArcTracingEventMatcher>(
+            kExoBufferReleaseContentsMatcher),
         MappingRule(BufferEventType::kNone, BufferEventType::kExoReleased)));
     rules_.emplace_back(std::make_pair(
         std::make_unique<ArcTracingEventMatcher>("exo:BufferInUse(step=bound)"),
@@ -117,11 +116,10 @@
                            "gpu:CommandBufferProxyImpl::OrderingBarrier"),
                        MappingRule(BufferEventType::kChromeBarrierOrder,
                                    BufferEventType::kNone)));
-    rules_.emplace_back(
-        std::make_pair(std::make_unique<ArcTracingEventMatcher>(
-                           "gpu:CommandBufferStub::OnAsyncFlush"),
-                       MappingRule(BufferEventType::kNone,
-                                   BufferEventType::kChromeBarrierFlush)));
+    rules_.emplace_back(std::make_pair(
+        std::make_unique<ArcTracingEventMatcher>(kBarrierFlushMatcher),
+        MappingRule(BufferEventType::kNone,
+                    BufferEventType::kChromeBarrierFlush)));
 
     // android rules
     rules_.emplace_back(std::make_pair(
@@ -177,19 +175,18 @@
             "viz,benchmark:Graphics.Pipeline.DrawAndSwap(step=WaitForAck)"),
         MappingRule(BufferEventType::kChromeOSWaitForAck,
                     BufferEventType::kNone)));
-    rules_.emplace_back(std::make_pair(
-        std::make_unique<ArcTracingEventMatcher>(
-            "viz,benchmark:Graphics.Pipeline.DrawAndSwap(step="
-            "WaitForPresentation)"),
-        MappingRule(BufferEventType::kChromeOSWaitForPresentation,
-                    BufferEventType::kNone)));
+    rules_.emplace_back(
+        std::make_pair(std::make_unique<ArcTracingEventMatcher>(
+                           "viz,benchmark:Graphics.Pipeline.DrawAndSwap(step="
+                           "WaitForPresentation)"),
+                       MappingRule(BufferEventType::kChromeOSPresentationDone,
+                                   BufferEventType::kNone)));
     matcher = std::make_unique<ArcTracingEventMatcher>(
         "viz,benchmark:Graphics.Pipeline.DrawAndSwap");
     matcher->SetPhase(TRACE_EVENT_PHASE_ASYNC_END);
-    rules_.emplace_back(
-        std::make_pair(std::move(matcher),
-                       MappingRule(BufferEventType::kNone,
-                                   BufferEventType::kChromeOSDrawFinished)));
+    rules_.emplace_back(std::make_pair(
+        std::move(matcher), MappingRule(BufferEventType::kNone,
+                                        BufferEventType::kChromeOSSwapDone)));
   }
 
   ~BufferGraphicsEventMapper() = default;
@@ -361,21 +358,76 @@
   }
 }
 
+std::string RouteToSelector(const std::vector<const ArcTracingEvent*>& route) {
+  std::string result;
+  for (const ArcTracingEvent* segment : route)
+    result = result + "/" + segment->GetCategory() + ":" + segment->GetName();
+  return result;
+}
+
+void DetermineHierarchy(std::vector<const ArcTracingEvent*>* route,
+                        const ArcTracingEvent* event,
+                        const ArcTracingEventMatcher& matcher,
+                        std::string* out_query) {
+  if (!out_query->empty())
+    return;
+
+  route->emplace_back(event);
+
+  if (matcher.Match(*event)) {
+    *out_query = RouteToSelector(*route);
+  } else {
+    for (const auto& child : event->children())
+      DetermineHierarchy(route, child.get(), matcher, out_query);
+  }
+
+  route->pop_back();
+}
+
 BufferToEvents GetChromeEvents(
     const ArcTracingModel& common_model,
     std::map<std::string, int>* buffer_id_to_task_id) {
+  // The tracing hierarchy may be easy changed any time in Chrome. This makes
+  // using static queries fragile and dependent of many external components. To
+  // provide the reliable way of requesting the needed information, let scan
+  // |common_model| for top level events and determine the hierarchy of
+  // interesting events dynamically.
+  const ArcTracingModel::TracingEventPtrs top_level_events =
+      common_model.Select("toplevel:");
+  std::vector<const ArcTracingEvent*> route;
+  std::string barrier_flush_query;
+  const ArcTracingEventMatcher barrier_flush_matcher(kBarrierFlushMatcher);
+  std::string attach_surface_query;
+  const ArcTracingEventMatcher attach_surface_matcher(kExoSurfaceAttachMatcher);
+  std::string produce_resource_query;
+  const ArcTracingEventMatcher produce_resource_matcher(
+      kExoBufferProduceResourceMatcher);
+  std::string release_contents_query;
+  const ArcTracingEventMatcher release_contents_matcher(
+      kExoBufferReleaseContentsMatcher);
+  for (const ArcTracingEvent* top_level_event : top_level_events) {
+    DetermineHierarchy(&route, top_level_event, barrier_flush_matcher,
+                       &barrier_flush_query);
+    DetermineHierarchy(&route, top_level_event, attach_surface_matcher,
+                       &attach_surface_query);
+    DetermineHierarchy(&route, top_level_event, produce_resource_matcher,
+                       &produce_resource_query);
+    DetermineHierarchy(&route, top_level_event, release_contents_matcher,
+                       &release_contents_query);
+  }
+
   BufferToEvents per_buffer_chrome_events;
   // Only exo:Surface::Attach has app id argument.
-  ProcessChromeEvents(common_model, kAttachSurfaceQueury,
+  ProcessChromeEvents(common_model, attach_surface_query,
                       &per_buffer_chrome_events, buffer_id_to_task_id);
-  ProcessChromeEvents(common_model, kReleaseContentQuery,
+  ProcessChromeEvents(common_model, release_contents_query,
                       &per_buffer_chrome_events,
                       nullptr /* buffer_id_to_task_id */);
 
   // Handle ProduceTransferableResource events. They have extra link to barrier
   // events. Use buffer_id to bind events for the same graphics buffer.
   const ArcTracingModel::TracingEventPtrs produce_resource_events =
-      common_model.Select(kProduceTransferableResourceQuery);
+      common_model.Select(produce_resource_query);
   std::map<int, std::string> put_offset_to_buffer_id_map;
   for (const ArcTracingEvent* event : produce_resource_events) {
     const std::string buffer_id = event->GetArgAsString(
@@ -416,7 +468,7 @@
 
   // Find associated barrier flush event using put_offset argument.
   const ArcTracingModel::TracingEventPtrs barrier_flush_events =
-      common_model.Select(kBarrierFlushQuery);
+      common_model.Select(barrier_flush_query);
   for (const ArcTracingEvent* event : barrier_flush_events) {
     const int put_offset =
         event->GetArgAsInteger(kArgumentPutOffset, 0 /* default_value */);
@@ -672,7 +724,7 @@
         !IsInRange(type, BufferEventType::kVsync,
                    BufferEventType::kSurfaceFlingerCompositionDone) &&
         !IsInRange(type, BufferEventType::kChromeOSDraw,
-                   BufferEventType::kChromeOSDrawFinished)) {
+                   BufferEventType::kChromeOSSwapDone)) {
       return false;
     }
 
@@ -942,4 +994,10 @@
   return true;
 }
 
+std::ostream& operator<<(std::ostream& os,
+                         ArcTracingGraphicsModel::BufferEventType event_type) {
+  return os << static_cast<typename std::underlying_type<
+             ArcTracingGraphicsModel::BufferEventType>::type>(event_type);
+}
+
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.h b/chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.h
index bea1e39..1709164 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.h
+++ b/chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.h
@@ -68,11 +68,11 @@
     kSurfaceFlingerCompositionDone,    // 403
 
     // Chrome OS top level events.
-    kChromeOSDraw = 500,           // 500
-    kChromeOSSwap,                 // 501
-    kChromeOSWaitForAck,           // 502
-    kChromeOSWaitForPresentation,  // 503
-    kChromeOSDrawFinished,         // 504
+    kChromeOSDraw = 500,        // 500
+    kChromeOSSwap,              // 501
+    kChromeOSWaitForAck,        // 502
+    kChromeOSPresentationDone,  // 503
+    kChromeOSSwapDone,          // 504
   };
 
   struct BufferEvent {
@@ -142,6 +142,9 @@
   DISALLOW_COPY_AND_ASSIGN(ArcTracingGraphicsModel);
 };
 
+std::ostream& operator<<(std::ostream& os,
+                         ArcTracingGraphicsModel::BufferEventType);
+
 }  // namespace arc
 
 #endif  // CHROME_BROWSER_CHROMEOS_ARC_TRACING_ARC_TRACING_GRAPHICS_MODEL_H_
diff --git a/chrome/browser/chromeos/arc/tracing/arc_tracing_model_unittest.cc b/chrome/browser/chromeos/arc/tracing/arc_tracing_model_unittest.cc
index c432b7e..9490722 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_tracing_model_unittest.cc
+++ b/chrome/browser/chromeos/arc/tracing/arc_tracing_model_unittest.cc
@@ -62,15 +62,26 @@
   int64_t previous_timestamp = 0;
   std::set<GraphicsEventType> used_types;
   for (const auto& event : events) {
-    if (event.timestamp < previous_timestamp)
+    if (event.timestamp < previous_timestamp) {
+      LOG(ERROR) << "Timestamp sequence broken: " << event.timestamp << " vs "
+                 << previous_timestamp << ".";
       return false;
+    }
     previous_timestamp = event.timestamp;
-    if (!allowed_types.count(event.type))
+    if (!allowed_types.count(event.type)) {
+      LOG(ERROR) << "Unexpected event type " << event.type << ".";
       return false;
+    }
     used_types.insert(event.type);
   }
-  if (used_types.size() != allowed_types.size())
+  if (used_types.size() != allowed_types.size()) {
+    for (const auto& allowed_type : allowed_types) {
+      if (!used_types.count(allowed_type))
+        LOG(ERROR) << "Required event type " << allowed_type
+                   << " << is not found.";
+    }
     return false;
+  }
   return true;
 }
 
@@ -141,8 +152,8 @@
                                 GraphicsEventType::kChromeOSDraw,
                                 GraphicsEventType::kChromeOSSwap,
                                 GraphicsEventType::kChromeOSWaitForAck,
-                                GraphicsEventType::kChromeOSWaitForPresentation,
-                                GraphicsEventType::kChromeOSDrawFinished,
+                                GraphicsEventType::kChromeOSPresentationDone,
+                                GraphicsEventType::kChromeOSSwapDone,
                             }));
   EXPECT_FALSE(graphics_model.view_buffers().empty());
   for (const auto& view : graphics_model.view_buffers()) {
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index a10c1d60..6d44a28 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -640,6 +640,8 @@
         TestCase("transferFromDownloadsToTeamDrive").EnableDriveFs(),
         TestCase("transferBetweenTeamDrives").DisableDriveFs(),
         TestCase("transferBetweenTeamDrives").EnableDriveFs(),
+        TestCase("transferDragAndDrop"),
+        TestCase("transferDragAndHover"),
         TestCase("transferFromDownloadsToDownloads")));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/chromeos/login/screens/reset_screen.cc b/chrome/browser/chromeos/login/screens/reset_screen.cc
index 72c1969b..0d2410ff 100644
--- a/chrome/browser/chromeos/login/screens/reset_screen.cc
+++ b/chrome/browser/chromeos/login/screens/reset_screen.cc
@@ -41,20 +41,6 @@
 constexpr const char kUserActionTPMFirmwareUpdateLearnMore[] =
     "tpm-firmware-update-learn-more-link";
 
-constexpr const char kContextKeyIsRollbackAvailable[] = "rollback-available";
-constexpr const char kContextKeyIsRollbackChecked[] = "rollback-checked";
-constexpr const char kContextKeyIsTPMFirmwareUpdateAvailable[] =
-    "tpm-firmware-update-available";
-constexpr const char kContextKeyIsTPMFirmwareUpdateChecked[] =
-    "tpm-firmware-update-checked";
-constexpr const char kContextKeyIsTPMFirmwareUpdateEditable[] =
-    "tpm-firmware-update-editable";
-constexpr const char kContextKeyTPMFirmwareUpdateMode[] =
-    "tpm-firmware-update-mode";
-constexpr const char kContextKeyIsConfirmational[] = "is-confirmational-view";
-constexpr const char kContextKeyIsOfficialBuild[] = "is-official-build";
-constexpr const char kContextKeyScreenState[] = "screen-state";
-
 void StartTPMFirmwareUpdate(
     tpm_firmware_update::Mode requested_mode,
     const std::set<tpm_firmware_update::Mode>& available_modes) {
@@ -101,21 +87,21 @@
       exit_callback_(exit_callback),
       weak_ptr_factory_(this) {
   DCHECK(view_);
-  if (view_)
+  if (view_) {
     view_->Bind(this);
-  context_.SetInteger(kContextKeyScreenState, STATE_RESTART_REQUIRED);
-  context_.SetBoolean(kContextKeyIsRollbackAvailable, false);
-  context_.SetBoolean(kContextKeyIsRollbackChecked, false);
-  context_.SetBoolean(kContextKeyIsTPMFirmwareUpdateAvailable, false);
-  context_.SetBoolean(kContextKeyIsTPMFirmwareUpdateChecked, false);
-  context_.SetBoolean(kContextKeyIsTPMFirmwareUpdateEditable, true);
-  context_.SetInteger(kContextKeyTPMFirmwareUpdateMode,
-                      static_cast<int>(tpm_firmware_update::Mode::kPowerwash));
-  context_.SetBoolean(kContextKeyIsConfirmational, false);
-  context_.SetBoolean(kContextKeyIsOfficialBuild, false);
+    view_->SetScreenState(ResetView::State::kRestartRequired);
+    view_->SetIsRollbackAvailable(false);
+    view_->SetIsRollbackChecked(false);
+    view_->SetIsTpmFirmwareUpdateAvailable(false);
+    view_->SetIsTpmFirmwareUpdateChecked(false);
+    view_->SetIsTpmFirmwareUpdateEditable(true);
+    view_->SetTpmFirmwareUpdateMode(tpm_firmware_update::Mode::kPowerwash);
+    view_->SetIsConfirmational(false);
+    view_->SetIsOfficialBuild(false);
 #if defined(OFFICIAL_BUILD)
-  context_.SetBoolean(kContextKeyIsOfficialBuild, true);
+    view_->SetIsOfficialBuild(true);
 #endif
+  }
 }
 
 ResetScreen::~ResetScreen() {
@@ -139,22 +125,23 @@
   reset::DialogViewType dialog_type =
       reset::DIALOG_VIEW_TYPE_SIZE;  // used by UMA metrics.
 
-  ContextEditor context_editor = GetContextEditor();
-
   bool restart_required = user_manager::UserManager::Get()->IsUserLoggedIn() ||
                           !base::CommandLine::ForCurrentProcess()->HasSwitch(
                               switches::kFirstExecAfterBoot);
   if (restart_required) {
-    context_editor.SetInteger(kContextKeyScreenState, STATE_RESTART_REQUIRED);
+    if (view_)
+      view_->SetScreenState(ResetView::State::kRestartRequired);
     dialog_type = reset::DIALOG_SHORTCUT_RESTART_REQUIRED;
   } else {
-    context_editor.SetInteger(kContextKeyScreenState, STATE_POWERWASH_PROPOSAL);
+    if (view_)
+      view_->SetScreenState(ResetView::State::kPowerwashProposal);
   }
 
   // Set availability of Rollback feature.
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisableRollbackOption)) {
-    context_editor.SetBoolean(kContextKeyIsRollbackAvailable, false);
+    if (view_)
+      view_->SetIsRollbackAvailable(false);
     dialog_type = reset::DIALOG_SHORTCUT_OFFERING_ROLLBACK_UNAVAILABLE;
   } else {
     chromeos::DBusThreadManager::Get()
@@ -177,10 +164,11 @@
     // availability test to initialize the dialog. This avoids a race condition
     // where the powerwash dialog gets shown immediately after reboot before the
     // init job to determine update availability has completed.
-    context_editor.SetBoolean(kContextKeyIsTPMFirmwareUpdateAvailable, true);
-    context_editor.SetInteger(
-        kContextKeyTPMFirmwareUpdateMode,
-        prefs->GetInteger(prefs::kFactoryResetTPMFirmwareUpdateMode));
+    if (view_) {
+      view_->SetIsTpmFirmwareUpdateAvailable(true);
+      view_->SetTpmFirmwareUpdateMode(static_cast<tpm_firmware_update::Mode>(
+          prefs->GetInteger(prefs::kFactoryResetTPMFirmwareUpdateMode)));
+    }
   } else {
     // If a TPM firmware update hasn't previously been requested, check the
     // system to see whether to offer the checkbox to update TPM firmware. Note
@@ -192,10 +180,10 @@
         base::TimeDelta::FromSeconds(10));
   }
 
-  context_editor.SetBoolean(kContextKeyIsTPMFirmwareUpdateChecked,
-                            tpm_firmware_update_requested);
-  context_editor.SetBoolean(kContextKeyIsTPMFirmwareUpdateEditable,
-                            !tpm_firmware_update_requested);
+  if (view_) {
+    view_->SetIsTpmFirmwareUpdateChecked(tpm_firmware_update_requested);
+    view_->SetIsTpmFirmwareUpdateEditable(!tpm_firmware_update_requested);
+  }
 
   // Clear prefs so the reset screen isn't triggered again the next time the
   // device is about to show the login screen.
@@ -236,50 +224,45 @@
 }
 
 void ResetScreen::OnCancel() {
-  if (context_.GetInteger(kContextKeyScreenState, STATE_RESTART_REQUIRED) ==
-      STATE_REVERT_PROMISE) {
+  if (view_ && view_->GetScreenState() == ResetView::State::kRevertPromise) {
     return;
   }
-
   // Hide Rollback view for the next show.
-  if (context_.GetBoolean(kContextKeyIsRollbackAvailable) &&
-      context_.GetBoolean(kContextKeyIsRollbackChecked)) {
+  if (view_ && view_->GetIsRollbackAvailable() && view_->GetIsRollbackChecked())
     OnToggleRollback();
-  }
   DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
   exit_callback_.Run();
 }
 
 void ResetScreen::OnPowerwash() {
-  if (context_.GetInteger(kContextKeyScreenState, 0) !=
-      STATE_POWERWASH_PROPOSAL)
+  if (view_ &&
+      view_->GetScreenState() != ResetView::State::kPowerwashProposal) {
     return;
+  }
 
-  GetContextEditor().SetBoolean(kContextKeyIsConfirmational, false);
-  CommitContextChanges();
+  if (view_)
+    view_->SetIsConfirmational(false);
 
-  if (context_.GetBoolean(kContextKeyIsRollbackChecked) &&
-      !context_.GetBoolean(kContextKeyIsRollbackAvailable)) {
+  if (view_ && view_->GetIsRollbackChecked() &&
+      !view_->GetIsRollbackAvailable()) {
     NOTREACHED()
         << "Rollback was checked but not available. Starting powerwash.";
   }
 
-  if (context_.GetBoolean(kContextKeyIsRollbackAvailable) &&
-      context_.GetBoolean(kContextKeyIsRollbackChecked)) {
-    GetContextEditor().SetInteger(kContextKeyScreenState, STATE_REVERT_PROMISE);
+  if (view_ && view_->GetIsRollbackAvailable() &&
+      view_->GetIsRollbackChecked()) {
+    view_->SetScreenState(ResetView::State::kRevertPromise);
     DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this);
     VLOG(1) << "Starting Rollback";
     DBusThreadManager::Get()->GetUpdateEngineClient()->Rollback();
-  } else if (context_.GetBoolean(kContextKeyIsTPMFirmwareUpdateChecked)) {
+  } else if (view_ && view_->GetIsTpmFirmwareUpdateChecked()) {
     VLOG(1) << "Starting TPM firmware update";
     // Re-check availability with a couple seconds timeout. This addresses the
     // case where the powerwash dialog gets shown immediately after reboot and
     // the decision on whether the update is available is not known immediately.
     tpm_firmware_update::GetAvailableUpdateModes(
-        base::BindOnce(
-            &StartTPMFirmwareUpdate,
-            static_cast<tpm_firmware_update::Mode>(
-                context_.GetInteger(kContextKeyTPMFirmwareUpdateMode))),
+        base::BindOnce(&StartTPMFirmwareUpdate,
+                       view_->GetTpmFirmwareUpdateMode()),
         base::TimeDelta::FromSeconds(10));
   } else {
     VLOG(1) << "Starting Powerwash";
@@ -290,7 +273,7 @@
 void ResetScreen::OnRestart() {
   PrefService* prefs = g_browser_process->local_state();
   prefs->SetBoolean(prefs::kFactoryResetRequested, true);
-  if (context_.GetBoolean(kContextKeyIsTPMFirmwareUpdateChecked)) {
+  if (view_ && view_->GetIsTpmFirmwareUpdateChecked()) {
     prefs->SetInteger(prefs::kFactoryResetTPMFirmwareUpdateMode,
                       static_cast<int>(tpm_firmware_update::Mode::kPowerwash));
   } else {
@@ -304,39 +287,38 @@
 
 void ResetScreen::OnToggleRollback() {
   // Hide Rollback if visible.
-  if (context_.GetBoolean(kContextKeyIsRollbackAvailable) &&
-      context_.GetBoolean(kContextKeyIsRollbackChecked)) {
+  if (view_ && view_->GetIsRollbackAvailable() &&
+      view_->GetIsRollbackChecked()) {
     VLOG(1) << "Hiding rollback view on reset screen";
-    GetContextEditor().SetBoolean(kContextKeyIsRollbackChecked, false);
+    view_->SetIsRollbackChecked(false);
     return;
   }
 
   // Show Rollback if available.
   VLOG(1) << "Requested rollback availability"
-          << context_.GetBoolean(kContextKeyIsRollbackAvailable);
-  if (context_.GetBoolean(kContextKeyIsRollbackAvailable) &&
-      !context_.GetBoolean(kContextKeyIsRollbackChecked)) {
+          << view_->GetIsRollbackAvailable();
+  if (view_->GetIsRollbackAvailable() && !view_->GetIsRollbackChecked()) {
     UMA_HISTOGRAM_ENUMERATION(
         "Reset.ChromeOS.PowerwashDialogShown",
         reset::DIALOG_SHORTCUT_OFFERING_ROLLBACK_AVAILABLE,
         reset::DIALOG_VIEW_TYPE_SIZE);
-    GetContextEditor().SetBoolean(kContextKeyIsRollbackChecked, true);
+    view_->SetIsRollbackChecked(true);
   }
 }
 
 void ResetScreen::OnShowConfirm() {
   reset::DialogViewType dialog_type =
-      context_.GetBoolean(kContextKeyIsRollbackChecked)
+      view_->GetIsRollbackChecked()
           ? reset::DIALOG_SHORTCUT_CONFIRMING_POWERWASH_AND_ROLLBACK
           : reset::DIALOG_SHORTCUT_CONFIRMING_POWERWASH_ONLY;
   UMA_HISTOGRAM_ENUMERATION("Reset.ChromeOS.PowerwashDialogShown", dialog_type,
                             reset::DIALOG_VIEW_TYPE_SIZE);
 
-  GetContextEditor().SetBoolean(kContextKeyIsConfirmational, true);
+  view_->SetIsConfirmational(true);
 }
 
 void ResetScreen::OnConfirmationDismissed() {
-  GetContextEditor().SetBoolean(kContextKeyIsConfirmational, false);
+  view_->SetIsConfirmational(false);
 }
 
 void ResetScreen::ShowHelpArticle(HelpAppLauncher::HelpTopic topic) {
@@ -356,7 +338,7 @@
   if (status.status == UpdateEngineClient::UPDATE_STATUS_ERROR ||
       status.status ==
           UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT) {
-    GetContextEditor().SetInteger(kContextKeyScreenState, STATE_ERROR);
+    view_->SetScreenState(ResetView::State::kError);
     // Show error screen.
     base_screen_delegate_->GetErrorScreen()->SetUIState(
         NetworkError::UI_STATE_ROLLBACK_ERROR);
@@ -377,19 +359,15 @@
   UMA_HISTOGRAM_ENUMERATION("Reset.ChromeOS.PowerwashDialogShown", dialog_type,
                             reset::DIALOG_VIEW_TYPE_SIZE);
 
-  GetContextEditor().SetBoolean(kContextKeyIsRollbackAvailable, can_rollback);
+  view_->SetIsRollbackAvailable(can_rollback);
 }
 
 void ResetScreen::OnTPMFirmwareUpdateAvailableCheck(
     const std::set<tpm_firmware_update::Mode>& modes) {
   bool available = modes.count(tpm_firmware_update::Mode::kPowerwash) > 0;
-  ContextEditor context_editor = GetContextEditor();
-  context_editor.SetBoolean(kContextKeyIsTPMFirmwareUpdateAvailable, available);
-  if (available) {
-    context_editor.SetInteger(
-        kContextKeyTPMFirmwareUpdateMode,
-        static_cast<int>(tpm_firmware_update::Mode::kPowerwash));
-  }
+  view_->SetIsTpmFirmwareUpdateAvailable(available);
+  if (available)
+    view_->SetTpmFirmwareUpdateMode(tpm_firmware_update::Mode::kPowerwash);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/reset_screen.h b/chrome/browser/chromeos/login/screens/reset_screen.h
index 0e6adc0..a962c86 100644
--- a/chrome/browser/chromeos/login/screens/reset_screen.h
+++ b/chrome/browser/chromeos/login/screens/reset_screen.h
@@ -54,13 +54,6 @@
   void OnTPMFirmwareUpdateAvailableCheck(
       const std::set<tpm_firmware_update::Mode>& modes);
 
-  enum State {
-    STATE_RESTART_REQUIRED = 0,
-    STATE_REVERT_PROMISE,
-    STATE_POWERWASH_PROPOSAL,
-    STATE_ERROR
-  };
-
   void OnCancel();
   void OnPowerwash();
   void OnRestart();
diff --git a/chrome/browser/chromeos/login/screens/reset_view.h b/chrome/browser/chromeos/login/screens/reset_view.h
index 22c3dcc..514d651f 100644
--- a/chrome/browser/chromeos/login/screens/reset_view.h
+++ b/chrome/browser/chromeos/login/screens/reset_view.h
@@ -9,6 +9,10 @@
 
 namespace chromeos {
 
+namespace tpm_firmware_update {
+enum class Mode;
+}
+
 class ResetScreen;
 
 // Interface for dependency injection between ResetScreen and its actual
@@ -23,6 +27,29 @@
   virtual void Unbind() = 0;
   virtual void Show() = 0;
   virtual void Hide() = 0;
+
+  enum class State {
+    kRestartRequired = 0,
+    kRevertPromise,
+    kPowerwashProposal,
+    kError,
+  };
+
+  virtual void SetIsRollbackAvailable(bool value) = 0;
+  virtual void SetIsRollbackChecked(bool value) = 0;
+  virtual void SetIsTpmFirmwareUpdateAvailable(bool value) = 0;
+  virtual void SetIsTpmFirmwareUpdateChecked(bool value) = 0;
+  virtual void SetIsTpmFirmwareUpdateEditable(bool value) = 0;
+  virtual void SetTpmFirmwareUpdateMode(tpm_firmware_update::Mode value) = 0;
+  virtual void SetIsConfirmational(bool value) = 0;
+  virtual void SetIsOfficialBuild(bool value) = 0;
+  virtual void SetScreenState(State value) = 0;
+
+  virtual State GetScreenState() = 0;
+  virtual tpm_firmware_update::Mode GetTpmFirmwareUpdateMode() = 0;
+  virtual bool GetIsRollbackAvailable() = 0;
+  virtual bool GetIsRollbackChecked() = 0;
+  virtual bool GetIsTpmFirmwareUpdateChecked() = 0;
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/session/chrome_session_manager.cc b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
index 127d817..734d72c 100644
--- a/chrome/browser/chromeos/login/session/chrome_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
@@ -9,7 +9,6 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/logging.h"
-#include "base/system/sys_info.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part_chromeos.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -242,8 +241,7 @@
     oobe_configuration_->CheckConfiguration();
   }
 
-  if (!base::SysInfo::IsRunningOnChromeOS() &&
-      login_account_id == user_manager::StubAccountId()) {
+  if (login_account_id == user_manager::StubAccountId()) {
     // Start a user session with stub user. This also happens on a dev machine
     // when running Chrome w/o login flow. See PreEarlyInitialization().
     // In these contexts, emulate as if sync has been initialized.
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index d2bc4e9..effddd1e 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -523,14 +523,10 @@
 }
 
 void WizardController::ShowWelcomeScreen() {
-  VLOG(1) << "Showing welcome screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_OOBE_WELCOME);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_WELCOME));
 }
 
 void WizardController::ShowNetworkScreen() {
-  VLOG(1) << "Showing network screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_OOBE_NETWORK);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_NETWORK));
 }
 
@@ -550,14 +546,7 @@
   login_screen_started_ = true;
 }
 
-void WizardController::ShowPreviousScreen() {
-  DCHECK(previous_screen_);
-  SetCurrentScreen(previous_screen_);
-}
-
 void WizardController::ShowEulaScreen() {
-  VLOG(1) << "Showing EULA screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_OOBE_EULA);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_EULA));
 }
 
@@ -570,38 +559,26 @@
 }
 
 void WizardController::ShowDemoModePreferencesScreen() {
-  VLOG(1) << "Showing demo mode preferences screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
 }
 
 void WizardController::ShowDemoModeSetupScreen() {
-  VLOG(1) << "Showing demo mode setup screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_OOBE_DEMO_SETUP);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_DEMO_SETUP));
 }
 
 void WizardController::ShowResetScreen() {
-  VLOG(1) << "Showing reset screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_OOBE_RESET);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_RESET));
 }
 
 void WizardController::ShowKioskEnableScreen() {
-  VLOG(1) << "Showing kiosk enable screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_KIOSK_ENABLE);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_KIOSK_ENABLE));
 }
 
 void WizardController::ShowKioskAutolaunchScreen() {
-  VLOG(1) << "Showing kiosk autolaunch screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_KIOSK_AUTOLAUNCH);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_KIOSK_AUTOLAUNCH));
 }
 
 void WizardController::ShowEnableDebuggingScreen() {
-  VLOG(1) << "Showing enable developer features screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING));
 }
 
@@ -616,15 +593,11 @@
     return;
   }
 
-  VLOG(1) << "Showing Terms of Service screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_TERMS_OF_SERVICE);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_TERMS_OF_SERVICE));
 }
 
 void WizardController::ShowSyncConsentScreen() {
 #if defined(GOOGLE_CHROME_BUILD)
-  VLOG(1) << "Showing Sync Consent screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_SYNC_CONSENT);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_SYNC_CONSENT));
 #else
   OnSyncConsentFinished();
@@ -632,22 +605,15 @@
 }
 
 void WizardController::ShowFingerprintSetupScreen() {
-  VLOG(1) << "Showing Fingerprint Setup screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_FINGERPRINT_SETUP);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_FINGERPRINT_SETUP));
 }
 
 void WizardController::ShowMarketingOptInScreen() {
-  VLOG(1) << "Showing Marketing Opt-In screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_MARKETING_OPT_IN);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_MARKETING_OPT_IN));
 }
 
 void WizardController::ShowArcTermsOfServiceScreen() {
   if (arc::IsArcTermsOfServiceOobeNegotiationNeeded()) {
-    VLOG(1) << "Showing ARC Terms of Service screen.";
-    UpdateStatusAreaVisibilityForScreen(
-        OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE);
     SetCurrentScreen(GetScreen(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE));
     ProfileManager::GetActiveUserProfile()->GetPrefs()->SetBoolean(
         arc::prefs::kArcTermsShownInOobe, true);
@@ -657,26 +623,18 @@
 }
 
 void WizardController::ShowRecommendAppsScreen() {
-  VLOG(1) << "Showing Recommend Apps screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_RECOMMEND_APPS);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_RECOMMEND_APPS));
 }
 
 void WizardController::ShowAppDownloadingScreen() {
-  VLOG(1) << "Showing App Downloading screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_APP_DOWNLOADING);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_APP_DOWNLOADING));
 }
 
 void WizardController::ShowWrongHWIDScreen() {
-  VLOG(1) << "Showing wrong HWID screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_WRONG_HWID);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_WRONG_HWID));
 }
 
 void WizardController::ShowAutoEnrollmentCheckScreen() {
-  VLOG(1) << "Showing Auto-enrollment check screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK);
   AutoEnrollmentCheckScreen* screen =
       AutoEnrollmentCheckScreen::Get(screen_manager());
   if (retry_auto_enrollment_check_)
@@ -686,33 +644,22 @@
 }
 
 void WizardController::ShowArcKioskSplashScreen() {
-  VLOG(1) << "Showing ARC kiosk splash screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_ARC_KIOSK_SPLASH);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_ARC_KIOSK_SPLASH));
 }
 
 void WizardController::ShowHIDDetectionScreen() {
-  VLOG(1) << "Showing HID discovery screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_OOBE_HID_DETECTION);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_HID_DETECTION));
 }
 
 void WizardController::ShowDeviceDisabledScreen() {
-  VLOG(1) << "Showing device disabled screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_DEVICE_DISABLED);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_DEVICE_DISABLED));
 }
 
 void WizardController::ShowEncryptionMigrationScreen() {
-  VLOG(1) << "Showing encryption migration screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_ENCRYPTION_MIGRATION);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_ENCRYPTION_MIGRATION));
 }
 
 void WizardController::ShowSupervisionTransitionScreen() {
-  VLOG(1) << "Showing supervision transition screen.";
-  UpdateStatusAreaVisibilityForScreen(
-      OobeScreen::SCREEN_SUPERVISION_TRANSITION);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_SUPERVISION_TRANSITION));
 }
 
@@ -726,14 +673,10 @@
 }
 
 void WizardController::ShowMultiDeviceSetupScreen() {
-  VLOG(1) << "Showing MultiDevice setup screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_MULTIDEVICE_SETUP);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_MULTIDEVICE_SETUP));
 }
 
 void WizardController::ShowDiscoverScreen() {
-  VLOG(1) << "Showing Discover screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_DISCOVER);
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_DISCOVER));
 }
 
@@ -1278,7 +1221,6 @@
 }
 
 void WizardController::StartOOBEUpdate() {
-  VLOG(1) << "StartOOBEUpdate";
   SetCurrentScreenSmooth(GetScreen(OobeScreen::SCREEN_OOBE_UPDATE), true);
   UpdateScreen::Get(screen_manager())->StartNetworkCheck();
 }
@@ -1543,7 +1485,6 @@
 ///////////////////////////////////////////////////////////////////////////////
 // WizardController, BaseScreenDelegate overrides:
 void WizardController::ShowErrorScreen() {
-  VLOG(1) << "Showing error screen.";
   SetCurrentScreen(GetScreen(OobeScreen::SCREEN_ERROR_MESSAGE));
 }
 
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h
index 8b06156..1e43b3b0 100644
--- a/chrome/browser/chromeos/login/wizard_controller.h
+++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -187,9 +187,6 @@
   // Shows images login screen.
   void ShowLoginScreen(const LoginScreenContext& context);
 
-  // Shows previous screen. Should only be called if previous screen exists.
-  void ShowPreviousScreen();
-
   // Shared actions to be performed on a screen exit.
   // |exit_code| is the screen specific exit code reported by the screen.
   void OnScreenExit(OobeScreen screen, int exit_code);
@@ -227,15 +224,7 @@
   void OnAssistantOptInFlowScreenExit();
   void OnMultiDeviceSetupScreenExit();
   void OnResetScreenExit();
-  void OnHIDDetectionCompleted();
   void OnDeviceModificationCanceled();
-  void OnFingerprintSetupFinished();
-  void OnAppDownloadingFinished();
-  void OnDemoSetupFinished();
-  void OnDemoSetupCanceled();
-  void OnDemoPreferencesContinued();
-  void OnDemoPreferencesCanceled();
-  void OnSupervisionTransitionFinished();
   void OnSupervisionTransitionScreenExit();
   void OnOobeFlowFinished();
 
diff --git a/chrome/browser/devtools/chrome_devtools_session.cc b/chrome/browser/devtools/chrome_devtools_session.cc
index 80388aa3..42b6cee6 100644
--- a/chrome/browser/devtools/chrome_devtools_session.cc
+++ b/chrome/browser/devtools/chrome_devtools_session.cc
@@ -11,6 +11,7 @@
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/devtools_agent_host_client.h"
 #include "content/public/browser/devtools_manager_delegate.h"
+#include "content/public/common/content_switches.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/devtools/protocol/window_manager_handler.h"
@@ -52,6 +53,12 @@
   client_->DispatchProtocolMessage(agent_host_, message->serialize(binary));
 }
 
+static bool EnableInternalDevToolsBinaryProtocol() {
+  static bool enabled = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnableInternalDevToolsBinaryProtocol);
+  return enabled;
+}
+
 void ChromeDevToolsSession::HandleCommand(
     const std::string& method,
     const std::string& message,
@@ -63,9 +70,14 @@
 
   int call_id;
   std::string unused;
+  // We also check for --enable-internal-dev-tools-binary-protocol here,
+  // because if this flag is set, then content::DevToolsSession will
+  // send us binary even if the |client_| did not ask for it.
+  bool binary =
+      client_->UsesBinaryProtocol() || EnableInternalDevToolsBinaryProtocol();
   std::unique_ptr<protocol::DictionaryValue> value =
-      protocol::DictionaryValue::cast(protocol::StringUtil::parseMessage(
-          message, client_->UsesBinaryProtocol()));
+      protocol::DictionaryValue::cast(
+          protocol::StringUtil::parseMessage(message, binary));
   if (!dispatcher_->parseCommand(value.get(), &call_id, &unused))
     return;
   pending_commands_[call_id] = std::move(callback);
diff --git a/chrome/browser/dom_distiller/dom_distiller_service_factory.cc b/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
index 943b5b2..73e3fd3b 100644
--- a/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
+++ b/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
@@ -15,6 +15,7 @@
 #include "components/dom_distiller/core/distiller.h"
 #include "components/dom_distiller/core/dom_distiller_store.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/leveldb_proto/content/proto_database_provider_factory.h"
 #include "components/leveldb_proto/public/proto_database.h"
 #include "components/leveldb_proto/public/proto_database_provider.h"
 #include "content/public/browser/browser_context.h"
@@ -59,14 +60,19 @@
       base::CreateSequencedTaskRunnerWithTraits(
           {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
 
-  auto db = leveldb_proto::ProtoDatabaseProvider::CreateUniqueDB<ArticleEntry>(
-      background_task_runner);
-
   base::FilePath database_dir(
       profile->GetPath().Append(FILE_PATH_LITERAL("Articles")));
 
+  leveldb_proto::ProtoDatabaseProvider* db_provider =
+      leveldb_proto::ProtoDatabaseProviderFactory::GetForBrowserContext(
+          profile);
+
+  auto db = db_provider->GetDB<ArticleEntry>(
+      leveldb_proto::ProtoDbType::DOM_DISTILLER_STORE, database_dir,
+      background_task_runner);
+
   std::unique_ptr<DomDistillerStore> dom_distiller_store(
-      new DomDistillerStore(std::move(db), database_dir));
+      new DomDistillerStore(std::move(db)));
 
   std::unique_ptr<DistillerPageFactory> distiller_page_factory(
       new DistillerPageWebContentsFactory(profile));
diff --git a/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc b/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc
index 331df64..1d2880d 100644
--- a/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc
+++ b/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc
@@ -135,7 +135,7 @@
             std::unique_ptr<DistillerPageFactory>(distiller_page_factory_),
             std::unique_ptr<DistilledPagePrefs>(new DistilledPagePrefs(
                 Profile::FromBrowserContext(context)->GetPrefs()))));
-    fake_db->InitCallback(true);
+    fake_db->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
     fake_db->LoadCallback(true);
     if (expect_distillation_) {
       // There will only be destillation of an article if the database contains
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc
index b3c74da..65051af 100644
--- a/chrome/browser/extensions/extension_apitest.cc
+++ b/chrome/browser/extensions/extension_apitest.cc
@@ -52,7 +52,6 @@
 const char kTestWebSocketPort[] = "testWebSocketPort";
 const char kFtpServerPort[] = "ftpServer.port";
 const char kEmbeddedTestServerPort[] = "testServer.port";
-const char kNativeCrxBindingsEnabled[] = "nativeCrxBindingsEnabled";
 
 }  // namespace
 
@@ -75,8 +74,6 @@
     test_config_->SetInteger(kEmbeddedTestServerPort,
                              embedded_test_server()->port());
   }
-  // TODO(devlin): Remove this.
-  test_config_->SetBoolean(kNativeCrxBindingsEnabled, true);
 
   TestGetConfigFunction::set_test_config_state(test_config_.get());
 }
diff --git a/chrome/browser/extensions/extension_uninstall_dialog.cc b/chrome/browser/extensions/extension_uninstall_dialog.cc
index 4b79106..c17540d 100644
--- a/chrome/browser/extensions/extension_uninstall_dialog.cc
+++ b/chrome/browser/extensions/extension_uninstall_dialog.cc
@@ -98,7 +98,6 @@
 
   extension_ = extension;
   uninstall_reason_ = reason;
-  uninstall_source_ = source;
 
   if (parent() && parent_window_tracker_->WasNativeWindowClosed()) {
     OnDialogClosed(CLOSE_ACTION_CANCELED);
diff --git a/chrome/browser/extensions/extension_uninstall_dialog.h b/chrome/browser/extensions/extension_uninstall_dialog.h
index e7cf0e7..0612e33 100644
--- a/chrome/browser/extensions/extension_uninstall_dialog.h
+++ b/chrome/browser/extensions/extension_uninstall_dialog.h
@@ -119,7 +119,6 @@
       return triggering_extension_.get(); }
   const gfx::ImageSkia& icon() const { return icon_->image_skia(); }
   gfx::NativeWindow parent() { return parent_; }
-  UninstallSource uninstall_source() { return uninstall_source_; }
 
  private:
   // Uninstalls the extension. Returns true on success, and populates |error| on
@@ -173,8 +172,6 @@
 
   UninstallReason uninstall_reason_ = UNINSTALL_REASON_FOR_TESTING;
 
-  UninstallSource uninstall_source_ = UNINSTALL_SOURCE_FOR_TESTING;
-
   ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> observer_;
 
   base::ThreadChecker thread_checker_;
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 78819f12..91affac 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -721,8 +721,8 @@
   },
   {
     "name": "enable-app-data-search",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
+    "owners": [ "jennyz", "kaznacheev" ],
+    "expiry_milestone": 78
   },
   {
     "name": "enable-app-grid-ghost",
@@ -740,11 +740,6 @@
     "expiry_milestone": 74
   },
   {
-    "name": "enable-app-shortcut-search",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
-  },
-  {
     "name": "enable-appcontainer",
     "owners": [ "forshaw", "wfh" ],
     "expiry_milestone": 76
@@ -760,6 +755,11 @@
     "expiry_milestone": 76
   },
   {
+    "name": "enable-assistant-launcher-integration",
+    "owners": [ "croissant-eng" ],
+    "expiry_milestone": 78
+  },
+  {
     "name": "enable-assistant-app-support",
     "owners": [ "croissant-eng" ],
     "expiry_milestone": 76
@@ -1503,8 +1503,8 @@
   },
   {
     "name": "enable-play-store-search",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
+    "owners": [ "jennyz", "kaznacheev" ],
+    "expiry_milestone": 78
   },
   {
     "name": "enable-previews-android-omnibox-ui",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index e4c7bec..6c232da 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3123,11 +3123,6 @@
     "Allow App List search box to autocomplete queries for Google searches and "
     "apps.";
 
-const char kEnableAppShortcutSearchName[] =
-    "Enable app shortcut search in launcher";
-const char kEnableAppShortcutSearchDescription[] =
-    "Enables app shortcut search in launcher";
-
 const char kEnableAppDataSearchName[] = "Enable app data search in launcher";
 const char kEnableAppDataSearchDescription[] =
     "Allow launcher search to access data available through Firebase App "
@@ -3139,14 +3134,20 @@
     "If audio focus is enabled in Chrome then this will delegate audio focus "
     "control in Android apps to Chrome.";
 
-const char kEnableAssistantVoiceMatchName[] = "Enable Assistant Voice Match";
-const char kEnableAssistantVoiceMatchDescription[] =
-    "Enable the Assistant Voice Match feature";
-
 const char kEnableAssistantAppSupportName[] = "Enable Assistant App Support";
 const char kEnableAssistantAppSupportDescription[] =
     "Enable the Assistant App Support feature";
 
+const char kEnableAssistantLauncherIntegrationName[] =
+    "Assistant & Launcher integration";
+const char kEnableAssistantLauncherIntegrationDescription[] =
+    "Combine Launcher search with the power of Assistant to provide the most "
+    "useful answer for each query. Requires Assistant to be enabled.";
+
+const char kEnableAssistantVoiceMatchName[] = "Enable Assistant Voice Match";
+const char kEnableAssistantVoiceMatchDescription[] =
+    "Enable the Assistant Voice Match feature";
+
 const char kEnableChromeOsAccountManagerName[] = "Enable Account Manager";
 const char kEnableChromeOsAccountManagerDescription[] =
     "Enables the Chrome OS Account Manager";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 6efa6473..5577fe28 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1868,21 +1868,21 @@
 extern const char kEnableAppListSearchAutocompleteName[];
 extern const char kEnableAppListSearchAutocompleteDescription[];
 
-extern const char kEnableAppShortcutSearchName[];
-extern const char kEnableAppShortcutSearchDescription[];
-
 extern const char kEnableAppDataSearchName[];
 extern const char kEnableAppDataSearchDescription[];
 
 extern const char kEnableArcUnifiedAudioFocusName[];
 extern const char kEnableArcUnifiedAudioFocusDescription[];
 
-extern const char kEnableAssistantVoiceMatchName[];
-extern const char kEnableAssistantVoiceMatchDescription[];
-
 extern const char kEnableAssistantAppSupportName[];
 extern const char kEnableAssistantAppSupportDescription[];
 
+extern const char kEnableAssistantLauncherIntegrationName[];
+extern const char kEnableAssistantLauncherIntegrationDescription[];
+
+extern const char kEnableAssistantVoiceMatchName[];
+extern const char kEnableAssistantVoiceMatchDescription[];
+
 extern const char kEnableChromeOsAccountManagerName[];
 extern const char kEnableChromeOsAccountManagerDescription[];
 
diff --git a/chrome/browser/lifetime/termination_notification.cc b/chrome/browser/lifetime/termination_notification.cc
index 40d80659..0846a992 100644
--- a/chrome/browser/lifetime/termination_notification.cc
+++ b/chrome/browser/lifetime/termination_notification.cc
@@ -13,7 +13,6 @@
 #include "content/public/browser/notification_service.h"
 
 #if defined(OS_CHROMEOS)
-#include "base/system/sys_info.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power_policy_controller.h"
 #include "chromeos/dbus/session_manager_client.h"
@@ -53,7 +52,8 @@
   if (chromeos::PowerPolicyController::IsInitialized())
     chromeos::PowerPolicyController::Get()->NotifyChromeIsExiting();
 
-  if (base::SysInfo::IsRunningOnChromeOS()) {
+  if (chromeos::DBusThreadManager::IsInitialized() &&
+      !chromeos::DBusThreadManager::Get()->IsUsingFakes()) {
     // If we're on a ChromeOS device, reboot if an update has been applied,
     // or else signal the session manager to log out.
     chromeos::UpdateEngineClient* update_engine_client =
diff --git a/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer.cc
index c0e1bd36..be22091 100644
--- a/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer.cc
@@ -14,40 +14,11 @@
 }
 
 HttpsEngagementPageLoadMetricsObserver::HttpsEngagementPageLoadMetricsObserver(
-    content::BrowserContext* context)
-    : currently_in_foreground_(false) {
+    content::BrowserContext* context) {
   engagement_service_ =
       HttpsEngagementServiceFactory::GetForBrowserContext(context);
 }
 
-page_load_metrics::PageLoadMetricsObserver::ObservePolicy
-HttpsEngagementPageLoadMetricsObserver::OnStart(
-    content::NavigationHandle* navigation_handle,
-    const GURL& currently_committed_url,
-    bool started_in_foreground) {
-  if (started_in_foreground)
-    OnShown();
-  return CONTINUE_OBSERVING;
-}
-
-page_load_metrics::PageLoadMetricsObserver::ObservePolicy
-HttpsEngagementPageLoadMetricsObserver::OnHidden(
-    const page_load_metrics::mojom::PageLoadTiming& timing,
-    const page_load_metrics::PageLoadExtraInfo& extra_info) {
-  if (currently_in_foreground_) {
-    foreground_time_ += base::TimeTicks::Now() - last_time_shown_;
-    currently_in_foreground_ = false;
-  }
-  return CONTINUE_OBSERVING;
-}
-
-page_load_metrics::PageLoadMetricsObserver::ObservePolicy
-HttpsEngagementPageLoadMetricsObserver::OnShown() {
-  last_time_shown_ = base::TimeTicks::Now();
-  currently_in_foreground_ = true;
-  return CONTINUE_OBSERVING;
-}
-
 void HttpsEngagementPageLoadMetricsObserver::OnComplete(
     const page_load_metrics::mojom::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& extra_info) {
@@ -56,23 +27,23 @@
   }
 
   // Don't record anything if the user never saw it.
-  if (!currently_in_foreground_ && foreground_time_.is_zero())
+  base::TimeDelta foreground_time = GetDelegate()->GetForegroundDuration();
+  if (foreground_time.is_zero())
     return;
 
-  if (currently_in_foreground_)
-    OnHidden(timing, extra_info);
-
   if (extra_info.url.SchemeIs(url::kHttpsScheme)) {
-    if (engagement_service_)
-      engagement_service_->RecordTimeOnPage(foreground_time_,
+    if (engagement_service_) {
+      engagement_service_->RecordTimeOnPage(foreground_time,
                                             HttpsEngagementService::HTTPS);
+    }
     UMA_HISTOGRAM_LONG_TIMES_100(internal::kHttpsEngagementHistogram,
-                                 foreground_time_);
+                                 foreground_time);
   } else if (extra_info.url.SchemeIs(url::kHttpScheme)) {
-    if (engagement_service_)
-      engagement_service_->RecordTimeOnPage(foreground_time_,
+    if (engagement_service_) {
+      engagement_service_->RecordTimeOnPage(foreground_time,
                                             HttpsEngagementService::HTTP);
+    }
     UMA_HISTOGRAM_LONG_TIMES_100(internal::kHttpEngagementHistogram,
-                                 foreground_time_);
+                                 foreground_time);
   }
 }
diff --git a/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer.h
index 3c39f585..904a777 100644
--- a/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_page_load_metrics_observer.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_HTTPS_ENGAGEMENT_METRICS_HTTPS_ENGAGEMENT_PAGE_LOAD_METRICS_OBSERVER_H_
 
 #include "base/macros.h"
-#include "base/time/time.h"
 #include "chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_service.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
 #include "url/gurl.h"
@@ -27,21 +26,11 @@
       content::BrowserContext* context);
 
   // page_load_metrics::PageLoadMetricsObserver:
-  ObservePolicy OnStart(content::NavigationHandle* navigation_handle,
-                        const GURL& currently_committed_url,
-                        bool started_in_foreground) override;
-  ObservePolicy OnHidden(
-      const page_load_metrics::mojom::PageLoadTiming& timing,
-      const page_load_metrics::PageLoadExtraInfo& extra_info) override;
-  ObservePolicy OnShown() override;
   void OnComplete(
       const page_load_metrics::mojom::PageLoadTiming& timing,
       const page_load_metrics::PageLoadExtraInfo& extra_info) override;
 
  private:
-  bool currently_in_foreground_;
-  base::TimeDelta foreground_time_;
-  base::TimeTicks last_time_shown_;
   HttpsEngagementService* engagement_service_;
 
   DISALLOW_COPY_AND_ASSIGN(HttpsEngagementPageLoadMetricsObserver);
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_observer_delegate.h b/chrome/browser/page_load_metrics/page_load_metrics_observer_delegate.h
index a577ff8..18be6aa 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_observer_delegate.h
+++ b/chrome/browser/page_load_metrics/page_load_metrics_observer_delegate.h
@@ -19,6 +19,10 @@
   virtual content::WebContents* GetWebContents() const = 0;
   virtual base::TimeTicks GetNavigationStart() const = 0;
   virtual bool DidCommit() const = 0;
+
+  // Get the amount of time the page has been in the foreground.
+  virtual base::TimeDelta GetForegroundDuration() const = 0;
+
   // TODO(crbug/939403): Consider migrating PageLoadExtraInfo data to this API
   // and deprecating that struct.
 };
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.cc b/chrome/browser/page_load_metrics/page_load_tracker.cc
index 65b03af1..0d2a431 100644
--- a/chrome/browser/page_load_metrics/page_load_tracker.cc
+++ b/chrome/browser/page_load_metrics/page_load_tracker.cc
@@ -11,6 +11,7 @@
 
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/time/default_tick_clock.h"
 #include "base/trace_event/trace_event.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_embedder_interface.h"
@@ -174,6 +175,7 @@
       navigation_start_(navigation_handle->NavigationStart()),
       url_(navigation_handle->GetURL()),
       start_url_(navigation_handle->GetURL()),
+      visibility_tracker_(base::DefaultTickClock::GetInstance(), in_foreground),
       did_commit_(false),
       page_end_reason_(END_NONE),
       page_end_user_initiated_info_(UserInitiatedInfo::NotUserInitiated()),
@@ -307,6 +309,7 @@
     background_time_ = base::TimeTicks::Now();
     ClampBrowserTimestampIfInterProcessTimeTickSkew(&background_time_);
   }
+  visibility_tracker_.OnHidden();
   const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
   INVOKE_AND_PRUNE_OBSERVERS(observers_, OnHidden,
                              metrics_update_dispatcher_.timing(), info);
@@ -323,6 +326,7 @@
     ClampBrowserTimestampIfInterProcessTimeTickSkew(&foreground_time_);
   }
 
+  visibility_tracker_.OnShown();
   INVOKE_AND_PRUNE_OBSERVERS(observers_, OnShown);
 }
 
@@ -724,4 +728,8 @@
   return did_commit_;
 }
 
+base::TimeDelta PageLoadTracker::GetForegroundDuration() const {
+  return visibility_tracker_.GetForegroundDuration();
+}
+
 }  // namespace page_load_metrics
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.h b/chrome/browser/page_load_metrics/page_load_tracker.h
index fe65252..1d2966d 100644
--- a/chrome/browser/page_load_metrics/page_load_tracker.h
+++ b/chrome/browser/page_load_metrics/page_load_tracker.h
@@ -14,6 +14,7 @@
 #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_observer_delegate.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.h"
+#include "chrome/browser/scoped_visibility_tracker.h"
 #include "chrome/common/page_load_metrics/page_load_timing.h"
 #include "content/public/browser/global_request_id.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -196,6 +197,7 @@
   content::WebContents* GetWebContents() const override;
   base::TimeTicks GetNavigationStart() const override;
   bool DidCommit() const override;
+  base::TimeDelta GetForegroundDuration() const override;
 
   void Redirect(content::NavigationHandle* navigation_handle);
   void WillProcessNavigationResponse(
@@ -342,6 +344,8 @@
   // The start URL for this page load (before redirects).
   GURL start_url_;
 
+  ScopedVisibilityTracker visibility_tracker_;
+
   // Whether this page load committed.
   bool did_commit_;
 
diff --git a/chrome/browser/performance_manager/browser_child_process_watcher.cc b/chrome/browser/performance_manager/browser_child_process_watcher.cc
index c0a35bf..cb95e85 100644
--- a/chrome/browser/performance_manager/browser_child_process_watcher.cc
+++ b/chrome/browser/performance_manager/browser_child_process_watcher.cc
@@ -7,10 +7,12 @@
 #include <memory>
 #include <utility>
 
+#include "base/bind.h"
 #include "base/process/process.h"
 #include "base/stl_util.h"
+#include "build/build_config.h"
+#include "chrome/browser/performance_manager/graph/process_node_impl.h"
 #include "chrome/browser/performance_manager/performance_manager.h"
-#include "chrome/browser/performance_manager/process_resource_coordinator.h"
 #include "content/public/browser/child_process_data.h"
 #include "content/public/browser/child_process_termination_info.h"
 #include "content/public/common/process_type.h"
@@ -18,22 +20,27 @@
 namespace performance_manager {
 
 BrowserChildProcessWatcher::BrowserChildProcessWatcher()
-    : browser_node_(PerformanceManager::GetInstance()) {
-  browser_node_.OnProcessLaunched(base::Process::Current());
+    : browser_process_node_(
+          PerformanceManager::GetInstance()->CreateProcessNode()) {
+  OnProcessLaunched(base::Process::Current(), browser_process_node_.get());
   BrowserChildProcessObserver::Add(this);
 }
 
 BrowserChildProcessWatcher::~BrowserChildProcessWatcher() {
   BrowserChildProcessObserver::Remove(this);
+
+  PerformanceManager* performance_manager = PerformanceManager::GetInstance();
+  performance_manager->DeleteNode(std::move(browser_process_node_));
+  for (auto& node : gpu_process_nodes_)
+    performance_manager->DeleteNode(std::move(node.second));
 }
 
 void BrowserChildProcessWatcher::BrowserChildProcessLaunchedAndConnected(
     const content::ChildProcessData& data) {
   if (data.process_type == content::PROCESS_TYPE_GPU) {
-    std::unique_ptr<performance_manager::ProcessResourceCoordinator> gpu_node =
-        std::make_unique<ProcessResourceCoordinator>(
-            PerformanceManager::GetInstance());
-    gpu_node->OnProcessLaunched(data.GetProcess());
+    std::unique_ptr<ProcessNodeImpl> gpu_node =
+        PerformanceManager::GetInstance()->CreateProcessNode();
+    OnProcessLaunched(data.GetProcess(), gpu_node.get());
     gpu_process_nodes_[data.id] = std::move(gpu_node);
   }
 }
@@ -41,8 +48,10 @@
 void BrowserChildProcessWatcher::BrowserChildProcessHostDisconnected(
     const content::ChildProcessData& data) {
   if (data.process_type == content::PROCESS_TYPE_GPU) {
-    size_t removed = gpu_process_nodes_.erase(data.id);
-    DCHECK_EQ(1u, removed);
+    auto it = gpu_process_nodes_.find(data.id);
+    DCHECK(it != gpu_process_nodes_.end());
+    PerformanceManager::GetInstance()->DeleteNode(std::move(it->second));
+    gpu_process_nodes_.erase(it);
   }
 }
 
@@ -66,8 +75,37 @@
   // specifically on crash.
   if (base::ContainsKey(gpu_process_nodes_, id)) {
     auto* process_node = gpu_process_nodes_[id].get();
-    process_node->SetProcessExitStatus(exit_code);
+    PerformanceManager* performance_manager = PerformanceManager::GetInstance();
+
+    performance_manager->task_runner()->PostTask(
+        FROM_HERE, base::BindOnce(&ProcessNodeImpl::SetProcessExitStatus,
+                                  base::Unretained(process_node), exit_code));
   }
 }
 
+// static
+void BrowserChildProcessWatcher::OnProcessLaunched(
+    const base::Process& process,
+    ProcessNodeImpl* process_node) {
+  // TODO(siggi): Change this to pass the process into the graph node.
+  const base::ProcessId pid = process.Pid();
+  const base::Time launch_time =
+#if defined(OS_ANDROID)
+      // Process::CreationTime() is not available on Android. Since this method
+      // is called immediately after the process is launched, the process launch
+      // time can be approximated with the current time.
+      base::Time::Now();
+#else
+      process.CreationTime();
+#endif
+
+  PerformanceManager* performance_manager = PerformanceManager::GetInstance();
+  performance_manager->task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&ProcessNodeImpl::SetPID,
+                                base::Unretained(process_node), pid));
+  performance_manager->task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&ProcessNodeImpl::SetLaunchTime,
+                                base::Unretained(process_node), launch_time));
+}
+
 }  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/browser_child_process_watcher.h b/chrome/browser/performance_manager/browser_child_process_watcher.h
index cdb6a6d..d264315 100644
--- a/chrome/browser/performance_manager/browser_child_process_watcher.h
+++ b/chrome/browser/performance_manager/browser_child_process_watcher.h
@@ -10,12 +10,14 @@
 #include "base/compiler_specific.h"
 #include "base/containers/flat_map.h"
 #include "base/macros.h"
-#include "chrome/browser/performance_manager/process_resource_coordinator.h"
+#include "base/process/process.h"
 #include "content/public/browser/browser_child_process_observer.h"
 #include "content/public/common/service_manager_connection.h"
 
 namespace performance_manager {
 
+class ProcessNodeImpl;
+
 // Responsible for maintaining the process nodes for the browser and the GPU
 // process.
 class BrowserChildProcessWatcher : public content::BrowserChildProcessObserver {
@@ -38,15 +40,15 @@
 
   void GPUProcessExited(int id, int exit_code);
 
-  performance_manager::ProcessResourceCoordinator browser_node_;
+  static void OnProcessLaunched(const base::Process& process,
+                                ProcessNodeImpl* process_node);
+
+  std::unique_ptr<ProcessNodeImpl> browser_process_node_;
 
   // Apparently more than one GPU process can be existent at a time, though
   // secondaries are very transient. This map keeps track of all GPU processes
   // by their unique ID from |content::ChildProcessData|.
-  base::flat_map<
-      int,
-      std::unique_ptr<performance_manager::ProcessResourceCoordinator>>
-      gpu_process_nodes_;
+  base::flat_map<int, std::unique_ptr<ProcessNodeImpl>> gpu_process_nodes_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowserChildProcessWatcher);
 };
diff --git a/chrome/browser/performance_manager/chrome_content_browser_client_performance_manager_part.cc b/chrome/browser/performance_manager/chrome_content_browser_client_performance_manager_part.cc
index 67d78edc..a452293 100644
--- a/chrome/browser/performance_manager/chrome_content_browser_client_performance_manager_part.cc
+++ b/chrome/browser/performance_manager/chrome_content_browser_client_performance_manager_part.cc
@@ -7,19 +7,31 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/logging.h"
 #include "base/threading/sequenced_task_runner_handle.h"
+#include "chrome/browser/performance_manager/graph/process_node_impl.h"
+#include "chrome/browser/performance_manager/performance_manager.h"
 #include "chrome/browser/performance_manager/render_process_user_data.h"
+#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
 
 namespace {
 
-void BindProcessPerformanceManager(
+void BindProcessNode(
     content::RenderProcessHost* render_process_host,
     resource_coordinator::mojom::ProcessCoordinationUnitRequest request) {
   performance_manager::RenderProcessUserData* user_data =
       performance_manager::RenderProcessUserData::GetForRenderProcessHost(
           render_process_host);
 
-  user_data->process_resource_coordinator()->AddBinding(std::move(request));
+  performance_manager::PerformanceManager* performance_manager =
+      performance_manager::PerformanceManager::GetInstance();
+  DCHECK(performance_manager);
+
+  performance_manager->task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&performance_manager::ProcessNodeImpl::AddBinding,
+                     base::Unretained(user_data->process_node()),
+                     std::move(request)));
 }
 
 }  // namespace
@@ -35,7 +47,7 @@
         blink::AssociatedInterfaceRegistry* associated_registry,
         content::RenderProcessHost* render_process_host) {
   registry->AddInterface(
-      base::BindRepeating(&BindProcessPerformanceManager,
+      base::BindRepeating(&BindProcessNode,
                           base::Unretained(render_process_host)),
       base::SequencedTaskRunnerHandle::Get());
 
diff --git a/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.cc b/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.cc
index ed3c874d4..89e4ff9 100644
--- a/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.cc
+++ b/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.cc
@@ -36,17 +36,6 @@
   NOTREACHED();
 }
 
-void PageAlmostIdleDecorator::OnFramePropertyChanged(
-    FrameNodeImpl* frame_node,
-    resource_coordinator::mojom::PropertyType property_type,
-    int64_t value) {
-  // Only the network idle state of a frame is of interest.
-  if (property_type ==
-      resource_coordinator::mojom::PropertyType::kNetworkAlmostIdle) {
-    UpdateLoadIdleStateFrame(frame_node);
-  }
-}
-
 void PageAlmostIdleDecorator::OnProcessPropertyChanged(
     ProcessNodeImpl* process_node,
     resource_coordinator::mojom::PropertyType property_type,
@@ -72,6 +61,11 @@
   UpdateLoadIdleStatePage(page_node);
 }
 
+void PageAlmostIdleDecorator::OnNetworkAlmostIdleChanged(
+    FrameNodeImpl* frame_node) {
+  UpdateLoadIdleStateFrame(frame_node);
+}
+
 void PageAlmostIdleDecorator::OnIsLoadingChanged(PageNodeImpl* page_node) {
   UpdateLoadIdleStatePage(page_node);
 }
@@ -227,9 +221,7 @@
   // associated with this page's main frame actually being low. In the case
   // of session restore this is mitigated by having a timeout while waiting for
   // this signal.
-  return main_frame_node->GetPropertyOrDefault(
-             resource_coordinator::mojom::PropertyType::kNetworkAlmostIdle,
-             0u) &&
+  return main_frame_node->network_almost_idle() &&
          process_node->GetPropertyOrDefault(
              resource_coordinator::mojom::PropertyType::
                  kMainThreadTaskLoadIsLow,
diff --git a/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.h b/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.h
index b3213a7..5429d51 100644
--- a/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.h
+++ b/chrome/browser/performance_manager/decorators/page_almost_idle_decorator.h
@@ -31,16 +31,13 @@
 
   // GraphObserver implementation:
   bool ShouldObserve(const NodeBase* coordination_unit) override;
-  void OnFramePropertyChanged(
-      FrameNodeImpl* frame_node,
-      resource_coordinator::mojom::PropertyType property_type,
-      int64_t value) override;
   void OnProcessPropertyChanged(
       ProcessNodeImpl* process_node,
       resource_coordinator::mojom::PropertyType property_type,
       int64_t value) override;
   void OnPageEventReceived(PageNodeImpl* page_node,
                            resource_coordinator::mojom::Event event) override;
+  void OnNetworkAlmostIdleChanged(FrameNodeImpl* frame_node) override;
   void OnIsLoadingChanged(PageNodeImpl* page_node) override;
 
  protected:
diff --git a/chrome/browser/performance_manager/decorators/page_almost_idle_decorator_test_utils.cc b/chrome/browser/performance_manager/decorators/page_almost_idle_decorator_test_utils.cc
index 4d7c2f7..bcbfe7b 100644
--- a/chrome/browser/performance_manager/decorators/page_almost_idle_decorator_test_utils.cc
+++ b/chrome/browser/performance_manager/decorators/page_almost_idle_decorator_test_utils.cc
@@ -82,10 +82,8 @@
       page_node->SetIsLoading(false);
       FALLTHROUGH;
     case PageAlmostIdleData::LoadIdleState::kLoadedNotIdling:
-      if (!frame_node->GetPropertyOrDefault(PropertyType::kNetworkAlmostIdle,
-                                            0)) {
+      if (!frame_node->network_almost_idle())
         frame_node->SetNetworkAlmostIdle(true);
-      }
       if (!process_node->GetPropertyOrDefault(
               PropertyType::kMainThreadTaskLoadIsLow, 0)) {
         process_node->SetMainThreadTaskLoadIsLow(true);
diff --git a/chrome/browser/performance_manager/frame_resource_coordinator.cc b/chrome/browser/performance_manager/frame_resource_coordinator.cc
deleted file mode 100644
index a9d6caea..0000000
--- a/chrome/browser/performance_manager/frame_resource_coordinator.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/performance_manager/frame_resource_coordinator.h"
-
-#include "base/bind.h"
-#include "chrome/browser/performance_manager/process_resource_coordinator.h"
-
-namespace performance_manager {
-
-FrameResourceCoordinator::FrameResourceCoordinator(
-    PerformanceManager* performance_manager)
-    : ResourceCoordinatorInterface(), weak_ptr_factory_(this) {
-  resource_coordinator::CoordinationUnitID new_cu_id(
-      resource_coordinator::CoordinationUnitType::kFrame,
-      resource_coordinator::CoordinationUnitID::RANDOM_ID);
-  ResourceCoordinatorInterface::ConnectToService(performance_manager,
-                                                 new_cu_id);
-}
-
-FrameResourceCoordinator::~FrameResourceCoordinator() = default;
-
-void FrameResourceCoordinator::SetProcess(
-    const ProcessResourceCoordinator& process) {
-  if (!service_ || !process.service())
-    return;
-  process.service()->GetID(
-      base::BindOnce(&FrameResourceCoordinator::SetProcessByID,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void FrameResourceCoordinator::AddChildFrame(
-    const FrameResourceCoordinator& child) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (!service_ || !child.service())
-    return;
-  // We could keep the ID around ourselves, but this hop ensures that the child
-  // has been created on the service-side.
-  child.service()->GetID(
-      base::BindOnce(&FrameResourceCoordinator::AddChildFrameByID,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void FrameResourceCoordinator::RemoveChildFrame(
-    const FrameResourceCoordinator& child) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (!service_ || !child.service())
-    return;
-  child.service()->GetID(
-      base::BindOnce(&FrameResourceCoordinator::RemoveChildFrameByID,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void FrameResourceCoordinator::ConnectToService(
-    resource_coordinator::mojom::CoordinationUnitProviderPtr& provider,
-    const resource_coordinator::CoordinationUnitID& cu_id) {
-  provider->CreateFrameCoordinationUnit(mojo::MakeRequest(&service_), cu_id);
-}
-
-void FrameResourceCoordinator::SetProcessByID(
-    const resource_coordinator::CoordinationUnitID& process_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (service_)
-    service_->SetProcess(process_id);
-}
-
-void FrameResourceCoordinator::AddChildFrameByID(
-    const resource_coordinator::CoordinationUnitID& child_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (service_)
-    service_->AddChildFrame(child_id);
-}
-
-void FrameResourceCoordinator::RemoveChildFrameByID(
-    const resource_coordinator::CoordinationUnitID& child_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (service_)
-    service_->RemoveChildFrame(child_id);
-}
-
-}  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/frame_resource_coordinator.h b/chrome/browser/performance_manager/frame_resource_coordinator.h
deleted file mode 100644
index 3176f7d..0000000
--- a/chrome/browser/performance_manager/frame_resource_coordinator.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_FRAME_RESOURCE_COORDINATOR_H_
-#define CHROME_BROWSER_PERFORMANCE_MANAGER_FRAME_RESOURCE_COORDINATOR_H_
-
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "chrome/browser/performance_manager/resource_coordinator_interface.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
-
-namespace performance_manager {
-
-class ProcessResourceCoordinator;
-
-class FrameResourceCoordinator
-    : public ResourceCoordinatorInterface<
-          resource_coordinator::mojom::FrameCoordinationUnitPtr,
-          resource_coordinator::mojom::FrameCoordinationUnitRequest> {
- public:
-  explicit FrameResourceCoordinator(PerformanceManager* performance_manager);
-  ~FrameResourceCoordinator() override;
-
-  void SetProcess(const ProcessResourceCoordinator& process);
-  void AddChildFrame(const FrameResourceCoordinator& child);
-  void RemoveChildFrame(const FrameResourceCoordinator& child);
-
-  // Closes the connection to the service.
-  void reset() { service_.reset(); }
-
- private:
-  void ConnectToService(
-      resource_coordinator::mojom::CoordinationUnitProviderPtr& provider,
-      const resource_coordinator::CoordinationUnitID& cu_id) override;
-
-  void SetProcessByID(
-      const resource_coordinator::CoordinationUnitID& process_id);
-  void AddChildFrameByID(
-      const resource_coordinator::CoordinationUnitID& child_id);
-  void RemoveChildFrameByID(
-      const resource_coordinator::CoordinationUnitID& child_id);
-
-  THREAD_CHECKER(thread_checker_);
-
-  // The WeakPtrFactory should come last so the weak ptrs are invalidated
-  // before the rest of the member variables.
-  base::WeakPtrFactory<FrameResourceCoordinator> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(FrameResourceCoordinator);
-};
-
-}  // namespace performance_manager
-
-#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_FRAME_RESOURCE_COORDINATOR_H_
diff --git a/chrome/browser/performance_manager/graph/README.md b/chrome/browser/performance_manager/graph/README.md
new file mode 100644
index 0000000..774c9fc
--- /dev/null
+++ b/chrome/browser/performance_manager/graph/README.md
@@ -0,0 +1,17 @@
+# Threading Model
+
+The [graph](graph.h) can only be accessed from a single sequence.
+
+Nodes can be created on any sequence, but as soon as they're added to a graph,
+they can only be used on the graph's sequence, with the exception of the id
+accessor.
+
+# Node Lifetime
+
+With the exception of the system node, which is a singleton, the Graph does not
+own nodes. The user of the graph is responsible for maintaining node ownership.
+Any node that has been added to the graph, must be removed from the graph
+with Graph::DestroyNode (TODO(siggi): rename to RemoveNode) before it's
+deleted.
+All nodes must be removed from the graph before the graph is destroyed.
+
diff --git a/chrome/browser/performance_manager/graph/frame_node_impl.cc b/chrome/browser/performance_manager/graph/frame_node_impl.cc
index 1134a08..c71308d 100644
--- a/chrome/browser/performance_manager/graph/frame_node_impl.cc
+++ b/chrome/browser/performance_manager/graph/frame_node_impl.cc
@@ -20,13 +20,16 @@
   for (size_t i = 0; i < base::size(intervention_policy_); ++i)
     intervention_policy_[i] =
         resource_coordinator::mojom::InterventionPolicy::kUnknown;
+
+  DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
 FrameNodeImpl::~FrameNodeImpl() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (parent_frame_coordination_unit_)
     parent_frame_coordination_unit_->RemoveChildFrame(this);
   if (page_coordination_unit_)
-    page_coordination_unit_->RemoveFrame(this);
+    page_coordination_unit_->RemoveFrameImpl(this);
   if (process_coordination_unit_)
     process_coordination_unit_->RemoveFrame(this);
   for (auto* child_frame : child_frame_coordination_units_)
@@ -56,7 +59,7 @@
     DCHECK(false) << "Cyclic reference in frame coordination units detected!";
     return;
   }
-  if (AddChildFrame(frame_cu)) {
+  if (AddChildFrameImpl(frame_cu)) {
     frame_cu->AddParentFrame(this);
   }
 }
@@ -73,9 +76,10 @@
   }
 }
 
-void FrameNodeImpl::SetNetworkAlmostIdle(bool idle) {
-  SetProperty(resource_coordinator::mojom::PropertyType::kNetworkAlmostIdle,
-              idle);
+void FrameNodeImpl::SetNetworkAlmostIdle(bool network_almost_idle) {
+  SetPropertyAndNotifyObservers(&GraphObserver::OnNetworkAlmostIdleChanged,
+                                network_almost_idle, this,
+                                &network_almost_idle_);
 }
 
 void FrameNodeImpl::SetLifecycleState(
@@ -228,7 +232,7 @@
   parent_frame_coordination_unit_ = parent_frame_cu;
 }
 
-bool FrameNodeImpl::AddChildFrame(FrameNodeImpl* child_frame_cu) {
+bool FrameNodeImpl::AddChildFrameImpl(FrameNodeImpl* child_frame_cu) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return child_frame_coordination_units_.count(child_frame_cu)
              ? false
diff --git a/chrome/browser/performance_manager/graph/frame_node_impl.h b/chrome/browser/performance_manager/graph/frame_node_impl.h
index 28c1add2..2fb4a432 100644
--- a/chrome/browser/performance_manager/graph/frame_node_impl.h
+++ b/chrome/browser/performance_manager/graph/frame_node_impl.h
@@ -58,6 +58,7 @@
     return lifecycle_state_;
   }
   bool has_nonempty_beforeunload() const { return has_nonempty_beforeunload_; }
+  bool network_almost_idle() const { return network_almost_idle_; }
 
   // Returns true if all intervention policies have been set for this frame.
   bool AreAllInterventionPoliciesSet() const;
@@ -89,7 +90,7 @@
   // PageNodeImpl and ProcessNodeImpl respectively to
   // manipulate their relationship.
   void AddParentFrame(FrameNodeImpl* parent_frame_cu);
-  bool AddChildFrame(FrameNodeImpl* child_frame_cu);
+  bool AddChildFrameImpl(FrameNodeImpl* child_frame_cu);
   void RemoveParentFrame(FrameNodeImpl* parent_frame_cu);
   bool RemoveChildFrame(FrameNodeImpl* child_frame_cu);
   void AddPageNode(PageNodeImpl* page_cu);
@@ -105,6 +106,9 @@
   resource_coordinator::mojom::LifecycleState lifecycle_state_ =
       resource_coordinator::mojom::LifecycleState::kRunning;
   bool has_nonempty_beforeunload_ = false;
+  // Network is considered almost idle when there are no more than 2 network
+  // connections.
+  bool network_almost_idle_ = false;
 
   // Intervention policy for this frame. These are communicated from the
   // renderer process and are controlled by origin trials.
diff --git a/chrome/browser/performance_manager/graph/graph.cc b/chrome/browser/performance_manager/graph/graph.cc
index 3af6b38b..cbc90ad 100644
--- a/chrome/browser/performance_manager/graph/graph.cc
+++ b/chrome/browser/performance_manager/graph/graph.cc
@@ -10,15 +10,12 @@
 #include "base/bind_helpers.h"
 #include "base/macros.h"
 #include "chrome/browser/performance_manager/graph/frame_node_impl.h"
-#include "chrome/browser/performance_manager/graph/graph_node_provider_impl.h"
 #include "chrome/browser/performance_manager/graph/node_base.h"
 #include "chrome/browser/performance_manager/graph/page_node_impl.h"
 #include "chrome/browser/performance_manager/graph/process_node_impl.h"
 #include "chrome/browser/performance_manager/graph/system_node_impl.h"
 #include "chrome/browser/performance_manager/observers/coordination_unit_graph_observer.h"
 #include "services/resource_coordinator/public/cpp/coordination_unit_types.h"
-#include "services/service_manager/public/cpp/bind_source_info.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
 
 namespace ukm {
 class UkmEntryBuilder;
@@ -26,10 +23,7 @@
 
 namespace performance_manager {
 
-Graph::Graph()
-    : system_coordination_unit_id_(
-          resource_coordinator::CoordinationUnitType::kSystem,
-          resource_coordinator::CoordinationUnitID::RANDOM_ID) {}
+Graph::Graph() = default;
 
 Graph::~Graph() {
   // Because the graph has ownership of the CUs, and because the process CUs
@@ -47,14 +41,6 @@
   DCHECK_EQ(0u, processes_by_pid_.size());
 }
 
-void Graph::OnStart(service_manager::BinderRegistryWithArgs<
-                    const service_manager::BindSourceInfo&>* registry) {
-  // Create the singleton CoordinationUnitProvider.
-  provider_ = std::make_unique<GraphNodeProviderImpl>(this);
-  registry->AddInterface(base::BindRepeating(
-      &GraphNodeProviderImpl::Bind, base::Unretained(provider_.get())));
-}
-
 void Graph::RegisterObserver(std::unique_ptr<GraphObserver> observer) {
   observer->set_coordination_unit_graph(this);
   observers_.push_back(std::move(observer));
@@ -73,28 +59,17 @@
   coordination_unit->BeforeDestroyed();
 }
 
-FrameNodeImpl* Graph::CreateFrameNode(
-    const resource_coordinator::CoordinationUnitID& id) {
-  return FrameNodeImpl::Create(id, this);
-}
-
-PageNodeImpl* Graph::CreatePageNode(
-    const resource_coordinator::CoordinationUnitID& id) {
-  return PageNodeImpl::Create(id, this);
-}
-
-ProcessNodeImpl* Graph::CreateProcessNode(
-    const resource_coordinator::CoordinationUnitID& id) {
-  return ProcessNodeImpl::Create(id, this);
-}
-
 SystemNodeImpl* Graph::FindOrCreateSystemNode() {
-  NodeBase* system_cu = GetNodeByID(system_coordination_unit_id_);
-  if (system_cu)
-    return SystemNodeImpl::FromNodeBase(system_cu);
+  if (!system_node_) {
+    // Create the singleton SystemCU instance. Ownership is taken by the graph.
+    resource_coordinator::CoordinationUnitID id(
+        resource_coordinator::CoordinationUnitType::kSystem,
+        resource_coordinator::CoordinationUnitID::RANDOM_ID);
+    system_node_ = std::make_unique<SystemNodeImpl>(id, this);
+    AddNewNode(system_node_.get());
+  }
 
-  // Create the singleton SystemCU instance. Ownership is taken by the graph.
-  return SystemNodeImpl::Create(system_coordination_unit_id_, this);
+  return system_node_.get();
 }
 
 NodeBase* Graph::GetNodeByID(
@@ -102,7 +77,7 @@
   const auto& it = coordination_units_.find(cu_id);
   if (it == coordination_units_.end())
     return nullptr;
-  return it->second.get();
+  return it->second;
 }
 
 ProcessNodeImpl* Graph::GetProcessNodeByPid(base::ProcessId pid) {
@@ -142,14 +117,12 @@
   return count;
 }
 
-NodeBase* Graph::AddNewNode(std::unique_ptr<NodeBase> new_cu) {
-  auto it = coordination_units_.emplace(new_cu->id(), std::move(new_cu));
+void Graph::AddNewNode(NodeBase* new_cu) {
+  auto it = coordination_units_.emplace(new_cu->id(), new_cu);
   DCHECK(it.second);  // Inserted successfully
 
-  NodeBase* added_cu = it.first->second.get();
+  NodeBase* added_cu = it.first->second;
   OnNodeCreated(added_cu);
-
-  return added_cu;
 }
 
 void Graph::DestroyNode(NodeBase* cu) {
@@ -188,7 +161,7 @@
   std::vector<CUType*> ret;
   for (const auto& el : coordination_units_) {
     if (el.first.type == type)
-      ret.push_back(CUType::FromNodeBase(el.second.get()));
+      ret.push_back(CUType::FromNodeBase(el.second));
   }
   return ret;
 }
diff --git a/chrome/browser/performance_manager/graph/graph.h b/chrome/browser/performance_manager/graph/graph.h
index 4cacb7d7..18f315ba 100644
--- a/chrome/browser/performance_manager/graph/graph.h
+++ b/chrome/browser/performance_manager/graph/graph.h
@@ -21,17 +21,10 @@
 #include "services/resource_coordinator/public/cpp/coordination_unit_id.h"
 #include "services/resource_coordinator/public/cpp/coordination_unit_types.h"
 
-namespace service_manager {
-template <typename... BinderArgs>
-class BinderRegistryWithArgs;
-struct BindSourceInfo;
-}  // namespace service_manager
-
 namespace performance_manager {
 
 class NodeBase;
 class GraphObserver;
-class GraphNodeProviderImpl;
 class FrameNodeImpl;
 class PageNodeImpl;
 class ProcessNodeImpl;
@@ -51,20 +44,11 @@
   }
   ukm::UkmRecorder* ukm_recorder() const { return ukm_recorder_; }
 
-  void OnStart(service_manager::BinderRegistryWithArgs<
-               const service_manager::BindSourceInfo&>* registry);
   void RegisterObserver(std::unique_ptr<GraphObserver> observer);
   void OnNodeCreated(NodeBase* coordination_unit);
   void OnBeforeNodeDestroyed(NodeBase* coordination_unit);
 
-  FrameNodeImpl* CreateFrameNode(
-      const resource_coordinator::CoordinationUnitID& id);
-  PageNodeImpl* CreatePageNode(
-      const resource_coordinator::CoordinationUnitID& id);
-  ProcessNodeImpl* CreateProcessNode(
-      const resource_coordinator::CoordinationUnitID& id);
   SystemNodeImpl* FindOrCreateSystemNode();
-
   std::vector<ProcessNodeImpl*> GetAllProcessNodes();
   std::vector<FrameNodeImpl*> GetAllFrameNodes();
   std::vector<PageNodeImpl*> GetAllPageNodes();
@@ -77,6 +61,10 @@
     return observers_;
   }
 
+  // Lifetime management functions for node owners.
+  void AddNewNode(NodeBase* new_cu);
+  void DestroyNode(NodeBase* cu);
+
   // A |key| of nullptr counts all instances associated with the |node|. A
   // |node| of null counts all instances associated with the |key|. If both are
   // null then the entire map size is provided.
@@ -84,15 +72,10 @@
                                             const void* key) const;
 
  private:
-  using CUIDMap = std::unordered_map<resource_coordinator::CoordinationUnitID,
-                                     std::unique_ptr<NodeBase>>;
+  using CUIDMap =
+      std::unordered_map<resource_coordinator::CoordinationUnitID, NodeBase*>;
   using ProcessByPidMap = std::unordered_map<base::ProcessId, ProcessNodeImpl*>;
 
-  // Lifetime management functions for NodeBase.
-  friend class NodeBase;
-  NodeBase* AddNewNode(std::unique_ptr<NodeBase> new_cu);
-  void DestroyNode(NodeBase* cu);
-
   // Process PID map for use by ProcessNodeImpl.
   friend class ProcessNodeImpl;
   void BeforeProcessPidChange(ProcessNodeImpl* process,
@@ -101,12 +84,11 @@
   template <typename CUType>
   std::vector<CUType*> GetAllNodesOfType();
 
-  resource_coordinator::CoordinationUnitID system_coordination_unit_id_;
+  std::unique_ptr<SystemNodeImpl> system_node_;
   CUIDMap coordination_units_;
   ProcessByPidMap processes_by_pid_;
   std::vector<std::unique_ptr<GraphObserver>> observers_;
   ukm::UkmRecorder* ukm_recorder_ = nullptr;
-  std::unique_ptr<GraphNodeProviderImpl> provider_;
 
   // User data storage for the graph.
   friend class NodeAttachedData;
diff --git a/chrome/browser/performance_manager/graph/graph_node_provider_impl.cc b/chrome/browser/performance_manager/graph/graph_node_provider_impl.cc
deleted file mode 100644
index b408024..0000000
--- a/chrome/browser/performance_manager/graph/graph_node_provider_impl.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/performance_manager/graph/graph_node_provider_impl.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "chrome/browser/performance_manager/graph/frame_node_impl.h"
-#include "chrome/browser/performance_manager/graph/page_node_impl.h"
-#include "chrome/browser/performance_manager/graph/process_node_impl.h"
-#include "chrome/browser/performance_manager/graph/system_node_impl.h"
-#include "services/service_manager/public/cpp/bind_source_info.h"
-
-namespace performance_manager {
-
-GraphNodeProviderImpl::GraphNodeProviderImpl(Graph* coordination_unit_graph)
-    : coordination_unit_graph_(coordination_unit_graph) {}
-
-GraphNodeProviderImpl::~GraphNodeProviderImpl() = default;
-
-void GraphNodeProviderImpl::OnConnectionError(NodeBase* coordination_unit) {
-  coordination_unit->Destruct();
-}
-
-void GraphNodeProviderImpl::CreateFrameCoordinationUnit(
-    resource_coordinator::mojom::FrameCoordinationUnitRequest request,
-    const resource_coordinator::CoordinationUnitID& id) {
-  FrameNodeImpl* frame_cu = coordination_unit_graph_->CreateFrameNode(id);
-
-  frame_cu->Bind(std::move(request));
-  auto& frame_cu_binding = frame_cu->binding();
-
-  frame_cu_binding.set_connection_error_handler(
-      base::BindOnce(&GraphNodeProviderImpl::OnConnectionError,
-                     base::Unretained(this), frame_cu));
-}
-
-void GraphNodeProviderImpl::CreatePageCoordinationUnit(
-    resource_coordinator::mojom::PageCoordinationUnitRequest request,
-    const resource_coordinator::CoordinationUnitID& id) {
-  PageNodeImpl* page_cu = coordination_unit_graph_->CreatePageNode(id);
-
-  page_cu->Bind(std::move(request));
-  auto& page_cu_binding = page_cu->binding();
-
-  page_cu_binding.set_connection_error_handler(
-      base::BindOnce(&GraphNodeProviderImpl::OnConnectionError,
-                     base::Unretained(this), page_cu));
-}
-
-void GraphNodeProviderImpl::CreateProcessCoordinationUnit(
-    resource_coordinator::mojom::ProcessCoordinationUnitRequest request,
-    const resource_coordinator::CoordinationUnitID& id) {
-  ProcessNodeImpl* process_cu = coordination_unit_graph_->CreateProcessNode(id);
-
-  process_cu->Bind(std::move(request));
-  auto& process_cu_binding = process_cu->binding();
-
-  process_cu_binding.set_connection_error_handler(
-      base::BindOnce(&GraphNodeProviderImpl::OnConnectionError,
-                     base::Unretained(this), process_cu));
-}
-
-void GraphNodeProviderImpl::GetSystemCoordinationUnit(
-    resource_coordinator::mojom::SystemCoordinationUnitRequest request) {
-  // Simply fetch the existing SystemCU and add an additional binding to it.
-  coordination_unit_graph_->FindOrCreateSystemNode()->AddBinding(
-      std::move(request));
-}
-
-void GraphNodeProviderImpl::Bind(
-    resource_coordinator::mojom::CoordinationUnitProviderRequest request,
-    const service_manager::BindSourceInfo& source_info) {
-  bindings_.AddBinding(this, std::move(request));
-}
-
-}  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/graph/graph_node_provider_impl.h b/chrome/browser/performance_manager/graph/graph_node_provider_impl.h
deleted file mode 100644
index 19739ea..0000000
--- a/chrome/browser/performance_manager/graph/graph_node_provider_impl.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_GRAPH_NODE_PROVIDER_IMPL_H_
-#define CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_GRAPH_NODE_PROVIDER_IMPL_H_
-
-#include <memory>
-#include <vector>
-
-#include "chrome/browser/performance_manager/graph/graph.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit_provider.mojom.h"
-
-namespace service_manager {
-struct BindSourceInfo;
-}  // namespace service_manager
-
-namespace performance_manager {
-
-class GraphNodeProviderImpl
-    : public resource_coordinator::mojom::CoordinationUnitProvider {
- public:
-  explicit GraphNodeProviderImpl(Graph* coordination_unit_graph);
-  ~GraphNodeProviderImpl() override;
-
-  void Bind(
-      resource_coordinator::mojom::CoordinationUnitProviderRequest request,
-      const service_manager::BindSourceInfo& source_info);
-
-  void OnConnectionError(NodeBase* coordination_unit);
-
-  // Overridden from resource_coordinator::mojom::CoordinationUnitProvider:
-  void CreateFrameCoordinationUnit(
-      resource_coordinator::mojom::FrameCoordinationUnitRequest request,
-      const resource_coordinator::CoordinationUnitID& id) override;
-  void CreatePageCoordinationUnit(
-      resource_coordinator::mojom::PageCoordinationUnitRequest request,
-      const resource_coordinator::CoordinationUnitID& id) override;
-  void CreateProcessCoordinationUnit(
-      resource_coordinator::mojom::ProcessCoordinationUnitRequest request,
-      const resource_coordinator::CoordinationUnitID& id) override;
-  void GetSystemCoordinationUnit(
-      resource_coordinator::mojom::SystemCoordinationUnitRequest request)
-      override;
-
- private:
-  Graph* coordination_unit_graph_;
-  mojo::BindingSet<resource_coordinator::mojom::CoordinationUnitProvider>
-      bindings_;
-
-  DISALLOW_COPY_AND_ASSIGN(GraphNodeProviderImpl);
-};
-
-}  // namespace performance_manager
-
-#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_GRAPH_NODE_PROVIDER_IMPL_H_
diff --git a/chrome/browser/performance_manager/graph/graph_test_harness.cc b/chrome/browser/performance_manager/graph/graph_test_harness.cc
index 830260c3..3161af5 100644
--- a/chrome/browser/performance_manager/graph/graph_test_harness.cc
+++ b/chrome/browser/performance_manager/graph/graph_test_harness.cc
@@ -11,8 +11,7 @@
 
 GraphTestHarness::GraphTestHarness()
     : task_env_(base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
-                base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED),
-      provider_(&coordination_unit_graph_) {}
+                base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED) {}
 
 GraphTestHarness::~GraphTestHarness() = default;
 
diff --git a/chrome/browser/performance_manager/graph/graph_test_harness.h b/chrome/browser/performance_manager/graph/graph_test_harness.h
index 24cd621..a1b11e8 100644
--- a/chrome/browser/performance_manager/graph/graph_test_harness.h
+++ b/chrome/browser/performance_manager/graph/graph_test_harness.h
@@ -6,12 +6,16 @@
 #define CHROME_BROWSER_PERFORMANCE_MANAGER_GRAPH_GRAPH_TEST_HARNESS_H_
 
 #include <stdint.h>
+#include <memory>
 #include <string>
+#include <utility>
 
 #include "base/test/scoped_task_environment.h"
+#include "chrome/browser/performance_manager/graph/frame_node_impl.h"
 #include "chrome/browser/performance_manager/graph/graph.h"
-#include "chrome/browser/performance_manager/graph/graph_node_provider_impl.h"
 #include "chrome/browser/performance_manager/graph/node_base.h"
+#include "chrome/browser/performance_manager/graph/page_node_impl.h"
+#include "chrome/browser/performance_manager/graph/process_node_impl.h"
 #include "chrome/browser/performance_manager/graph/system_node_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -26,30 +30,65 @@
 template <class NodeClass>
 class TestNodeWrapper {
  public:
+  static TestNodeWrapper<NodeClass> Create(
+      const resource_coordinator::CoordinationUnitID& cu_id,
+      Graph* graph) {
+    std::unique_ptr<NodeClass> node = std::make_unique<NodeClass>(cu_id, graph);
+    graph->AddNewNode(node.get());
+    return TestNodeWrapper<NodeClass>(std::move(node));
+  }
   static TestNodeWrapper<NodeClass> Create(Graph* graph) {
     resource_coordinator::CoordinationUnitID cu_id(
         NodeClass::Type(), resource_coordinator::CoordinationUnitID::RANDOM_ID);
-    return TestNodeWrapper<NodeClass>(NodeClass::Create(cu_id, graph));
+    return Create(cu_id, graph);
   }
 
-  explicit TestNodeWrapper(NodeClass* impl) : impl_(impl) { DCHECK(impl); }
+  explicit TestNodeWrapper(std::unique_ptr<NodeClass> impl)
+      : impl_(std::move(impl)) {
+    DCHECK(impl_.get());
+  }
   ~TestNodeWrapper() { reset(); }
 
-  NodeClass* operator->() const { return impl_; }
+  NodeClass* operator->() const { return impl_.get(); }
 
-  TestNodeWrapper(TestNodeWrapper&& other) : impl_(other.impl_) {}
+  TestNodeWrapper(TestNodeWrapper&& other) : impl_(std::move(other.impl_)) {}
 
-  NodeClass* get() const { return impl_; }
+  NodeClass* get() const { return impl_.get(); }
 
   void reset() {
     if (impl_) {
-      impl_->Destruct();
-      impl_ = nullptr;
+      impl_->graph()->DestroyNode(impl_.get());
+      impl_.reset();
     }
   }
 
  private:
-  NodeClass* impl_;
+  std::unique_ptr<NodeClass> impl_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestNodeWrapper);
+};
+
+// This specialization is necessary because the graph has ownership of the
+// system node as it's a singleton. For the other node types the test wrapper
+// manages the node lifetime.
+template <>
+class TestNodeWrapper<SystemNodeImpl> {
+ public:
+  static TestNodeWrapper<SystemNodeImpl> Create(Graph* graph) {
+    return TestNodeWrapper<SystemNodeImpl>(graph->FindOrCreateSystemNode());
+  }
+
+  explicit TestNodeWrapper(SystemNodeImpl* impl) : impl_(impl) {}
+  TestNodeWrapper(TestNodeWrapper&& other) : impl_(other.impl_) {}
+  ~TestNodeWrapper() { reset(); }
+
+  SystemNodeImpl* operator->() const { return impl_; }
+  SystemNodeImpl* get() const { return impl_; }
+
+  void reset() { impl_ = nullptr; }
+
+ private:
+  SystemNodeImpl* impl_;
 
   DISALLOW_COPY_AND_ASSIGN(TestNodeWrapper);
 };
@@ -62,8 +101,7 @@
   template <class NodeClass>
   TestNodeWrapper<NodeClass> CreateCoordinationUnit(
       resource_coordinator::CoordinationUnitID cu_id) {
-    return TestNodeWrapper<NodeClass>(
-        NodeClass::Create(cu_id, coordination_unit_graph()));
+    return TestNodeWrapper<NodeClass>::Create(cu_id, coordination_unit_graph());
   }
 
   template <class NodeClass>
@@ -84,12 +122,10 @@
  protected:
   base::test::ScopedTaskEnvironment& task_env() { return task_env_; }
   Graph* coordination_unit_graph() { return &coordination_unit_graph_; }
-  GraphNodeProviderImpl* provider() { return &provider_; }
 
  private:
   base::test::ScopedTaskEnvironment task_env_;
   Graph coordination_unit_graph_;
-  GraphNodeProviderImpl provider_;
 };
 
 }  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/graph/graph_unittest.cc b/chrome/browser/performance_manager/graph/graph_unittest.cc
index 4d40133..0eee4bf 100644
--- a/chrome/browser/performance_manager/graph/graph_unittest.cc
+++ b/chrome/browser/performance_manager/graph/graph_unittest.cc
@@ -5,37 +5,13 @@
 #include "chrome/browser/performance_manager/graph/graph.h"
 
 #include "chrome/browser/performance_manager/graph/frame_node_impl.h"
+#include "chrome/browser/performance_manager/graph/graph_test_harness.h"
 #include "chrome/browser/performance_manager/graph/mock_graphs.h"
 #include "chrome/browser/performance_manager/graph/process_node_impl.h"
 #include "chrome/browser/performance_manager/graph/system_node_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace performance_manager {
-namespace {
-
-ProcessNodeImpl* CreateProcessNode(Graph* graph) {
-  return graph->CreateProcessNode(resource_coordinator::CoordinationUnitID(
-      resource_coordinator::CoordinationUnitType::kProcess,
-      resource_coordinator::CoordinationUnitID::RANDOM_ID));
-}
-
-}  // namespace
-
-TEST(GraphTest, DestructionWhileCUSOutstanding) {
-  std::unique_ptr<Graph> graph(new Graph());
-
-  for (size_t i = 0; i < 10; ++i) {
-    ProcessNodeImpl* process = CreateProcessNode(graph.get());
-    EXPECT_NE(nullptr, process);
-
-    process->SetPID(i + 100);
-  }
-
-  EXPECT_NE(nullptr, graph->FindOrCreateSystemNode());
-
-  // This should destroy all the CUs without incident.
-  graph.reset();
-}
 
 TEST(GraphTest, FindOrCreateSystemNode) {
   Graph graph;
@@ -44,27 +20,22 @@
 
   // A second request should return the same instance.
   EXPECT_EQ(system_cu, graph.FindOrCreateSystemNode());
-
-  // Destructing the system CU should be allowed.
-  system_cu->Destruct();
-
-  system_cu = graph.FindOrCreateSystemNode();
-  EXPECT_NE(nullptr, system_cu);
 }
 
 TEST(GraphTest, GetProcessNodeByPid) {
   Graph graph;
 
-  ProcessNodeImpl* process = CreateProcessNode(&graph);
+  TestNodeWrapper<ProcessNodeImpl> process =
+      TestNodeWrapper<ProcessNodeImpl>::Create(&graph);
   EXPECT_EQ(base::kNullProcessId, process->process_id());
 
   static constexpr base::ProcessId kPid = 10;
 
   EXPECT_EQ(nullptr, graph.GetProcessNodeByPid(kPid));
   process->SetPID(kPid);
-  EXPECT_EQ(process, graph.GetProcessNodeByPid(kPid));
+  EXPECT_EQ(process.get(), graph.GetProcessNodeByPid(kPid));
 
-  process->Destruct();
+  process.reset();
 
   EXPECT_EQ(nullptr, graph.GetProcessNodeByPid(12));
 }
@@ -77,20 +48,22 @@
 
   static constexpr base::ProcessId kPid = 10;
 
-  ProcessNodeImpl* process1 = CreateProcessNode(&graph);
-  ProcessNodeImpl* process2 = CreateProcessNode(&graph);
+  TestNodeWrapper<ProcessNodeImpl> process1 =
+      TestNodeWrapper<ProcessNodeImpl>::Create(&graph);
+  TestNodeWrapper<ProcessNodeImpl> process2 =
+      TestNodeWrapper<ProcessNodeImpl>::Create(&graph);
 
   process1->SetPID(kPid);
-  EXPECT_EQ(process1, graph.GetProcessNodeByPid(kPid));
+  EXPECT_EQ(process1.get(), graph.GetProcessNodeByPid(kPid));
 
   // The second registration for the same PID should override the first one.
   process2->SetPID(kPid);
-  EXPECT_EQ(process2, graph.GetProcessNodeByPid(kPid));
+  EXPECT_EQ(process2.get(), graph.GetProcessNodeByPid(kPid));
 
   // The destruction of the first process CU shouldn't clear the PID
   // registration.
-  process1->Destruct();
-  EXPECT_EQ(process2, graph.GetProcessNodeByPid(kPid));
+  process1.reset();
+  EXPECT_EQ(process2.get(), graph.GetProcessNodeByPid(kPid));
 }
 
 TEST(GraphTest, GetAllCUsByType) {
diff --git a/chrome/browser/performance_manager/graph/node_base.cc b/chrome/browser/performance_manager/graph/node_base.cc
index a6ad917..f8a69662f 100644
--- a/chrome/browser/performance_manager/graph/node_base.cc
+++ b/chrome/browser/performance_manager/graph/node_base.cc
@@ -15,20 +15,12 @@
 NodeBase::NodeBase(const resource_coordinator::CoordinationUnitID& id,
                    Graph* graph)
     : graph_(graph), id_(id.type, id.id) {
-  // TODO(siggi): The constructor needs to detach from the sequence once the
-  //     lifetime changes are done.
-  // DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
 NodeBase::~NodeBase() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
-void NodeBase::Destruct() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  graph_->DestroyNode(this);
-}
-
 void NodeBase::BeforeDestroyed() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   for (auto& observer : observers_)
@@ -98,10 +90,4 @@
   OnPropertyChanged(property_type, value);
 }
 
-// static
-NodeBase* NodeBase::PassOwnershipToGraph(std::unique_ptr<NodeBase> new_cu) {
-  auto *graph = new_cu->graph();
-  return graph->AddNewNode(std::move(new_cu));
-}
-
 }  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/graph/node_base.h b/chrome/browser/performance_manager/graph/node_base.h
index 65ba5ccd..819c97d 100644
--- a/chrome/browser/performance_manager/graph/node_base.h
+++ b/chrome/browser/performance_manager/graph/node_base.h
@@ -33,7 +33,6 @@
   NodeBase(const resource_coordinator::CoordinationUnitID& id, Graph* graph);
   virtual ~NodeBase();
 
-  void Destruct();
   void BeforeDestroyed();
   void AddObserver(GraphObserver* observer);
   void RemoveObserver(GraphObserver* observer);
@@ -44,6 +43,7 @@
       const resource_coordinator::mojom::PropertyType property_type,
       int64_t default_value) const;
 
+  // May be called on any thread.
   const resource_coordinator::CoordinationUnitID& id() const { return id_; }
   Graph* graph() const { return graph_; }
 
@@ -61,6 +61,22 @@
   }
 
  protected:
+  // Helper function for setting a property, and notifying observers if the
+  // value has changed.
+  template <typename NodeType,
+            typename PropertyType,
+            typename NotifyFunctionPtr>
+  void SetPropertyAndNotifyObservers(NotifyFunctionPtr notify_function_ptr,
+                                     const PropertyType& value,
+                                     NodeType* node,
+                                     PropertyType* property) {
+    if (*property == value)
+      return;
+    *property = value;
+    for (auto& observer : observers_)
+      ((observer).*(notify_function_ptr))(node);
+  }
+
   virtual void OnEventReceived(resource_coordinator::mojom::Event event);
   virtual void OnPropertyChanged(
       resource_coordinator::mojom::PropertyType property_type,
@@ -70,9 +86,6 @@
   void SetProperty(resource_coordinator::mojom::PropertyType property_type,
                    int64_t value);
 
-  // Passes the ownership of the newly created |new_cu| to its graph.
-  static NodeBase* PassOwnershipToGraph(std::unique_ptr<NodeBase> new_cu);
-
   Graph* const graph_;
   const resource_coordinator::CoordinationUnitID id_;
 
@@ -90,15 +103,6 @@
           class MojoRequestClass>
 class CoordinationUnitInterface : public NodeBase, public MojoInterfaceClass {
  public:
-  static CoordinationUnitClass* Create(
-      const resource_coordinator::CoordinationUnitID& id,
-      Graph* graph) {
-    std::unique_ptr<CoordinationUnitClass> new_cu =
-        std::make_unique<CoordinationUnitClass>(id, graph);
-    return static_cast<CoordinationUnitClass*>(
-        PassOwnershipToGraph(std::move(new_cu)));
-  }
-
   static const CoordinationUnitClass* FromNodeBase(const NodeBase* cu) {
     DCHECK(cu->id().type == CoordinationUnitClass::Type());
     return static_cast<const CoordinationUnitClass*>(cu);
diff --git a/chrome/browser/performance_manager/graph/node_base_unittest.cc b/chrome/browser/performance_manager/graph/node_base_unittest.cc
index 851b797e..555bcca 100644
--- a/chrome/browser/performance_manager/graph/node_base_unittest.cc
+++ b/chrome/browser/performance_manager/graph/node_base_unittest.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/performance_manager/graph/node_base.h"
-#include "chrome/browser/performance_manager/graph/graph_node_provider_impl.h"
 #include "chrome/browser/performance_manager/graph/graph_test_harness.h"
 #include "chrome/browser/performance_manager/graph/mock_graphs.h"
 #include "chrome/browser/performance_manager/graph/page_node_impl.h"
diff --git a/chrome/browser/performance_manager/graph/page_node_impl.cc b/chrome/browser/performance_manager/graph/page_node_impl.cc
index e569af4..4110968 100644
--- a/chrome/browser/performance_manager/graph/page_node_impl.cc
+++ b/chrome/browser/performance_manager/graph/page_node_impl.cc
@@ -35,9 +35,12 @@
     : CoordinationUnitInterface(id, graph),
       visibility_change_time_(ResourceCoordinatorClock::NowTicks()) {
   InvalidateAllInterventionPolicies();
+
+  DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
 PageNodeImpl::~PageNodeImpl() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   for (auto* child_frame : frame_coordination_units_)
     child_frame->RemovePageNode(this);
 }
@@ -49,7 +52,7 @@
   FrameNodeImpl* frame_cu = FrameNodeImpl::GetNodeByID(graph_, cu_id);
   if (!frame_cu)
     return;
-  if (AddFrame(frame_cu))
+  if (AddFrameImpl(frame_cu))
     frame_cu->AddPageNode(this);
 }
 
@@ -60,24 +63,18 @@
   FrameNodeImpl* frame_cu = FrameNodeImpl::GetNodeByID(graph_, cu_id);
   if (!frame_cu)
     return;
-  if (RemoveFrame(frame_cu))
+  if (RemoveFrameImpl(frame_cu))
     frame_cu->RemovePageNode(this);
 }
 
 void PageNodeImpl::SetIsLoading(bool is_loading) {
-  if (is_loading_ == is_loading)
-    return;
-  is_loading_ = is_loading;
-  for (auto& observer : observers())
-    observer.OnIsLoadingChanged(this);
+  SetPropertyAndNotifyObservers(&GraphObserver::OnIsLoadingChanged, is_loading,
+                                this, &is_loading_);
 }
 
 void PageNodeImpl::SetVisibility(bool is_visible) {
-  if (is_visible_ == is_visible)
-    return;
-  is_visible_ = is_visible;
-  for (auto& observer : observers())
-    observer.OnIsVisibleChanged(this);
+  SetPropertyAndNotifyObservers(&GraphObserver::OnIsVisibleChanged, is_visible,
+                                this, &is_visible_);
   // The change time needs to be updated after observers are notified, as they
   // use this to determine time passed since the *previous* visibility state
   // change. They can infer the current state change time themselves via
@@ -267,7 +264,7 @@
     observer.OnPagePropertyChanged(this, property_type, value);
 }
 
-bool PageNodeImpl::AddFrame(FrameNodeImpl* frame_cu) {
+bool PageNodeImpl::AddFrameImpl(FrameNodeImpl* frame_cu) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   const bool inserted = frame_coordination_units_.insert(frame_cu).second;
   if (inserted) {
@@ -281,7 +278,7 @@
   return inserted;
 }
 
-bool PageNodeImpl::RemoveFrame(FrameNodeImpl* frame_cu) {
+bool PageNodeImpl::RemoveFrameImpl(FrameNodeImpl* frame_cu) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   bool removed = frame_coordination_units_.erase(frame_cu) > 0;
   if (removed) {
diff --git a/chrome/browser/performance_manager/graph/page_node_impl.h b/chrome/browser/performance_manager/graph/page_node_impl.h
index 7a3075a7..0963a1d3 100644
--- a/chrome/browser/performance_manager/graph/page_node_impl.h
+++ b/chrome/browser/performance_manager/graph/page_node_impl.h
@@ -143,8 +143,8 @@
       resource_coordinator::mojom::PropertyType property_type,
       int64_t value) override;
 
-  bool AddFrame(FrameNodeImpl* frame_cu);
-  bool RemoveFrame(FrameNodeImpl* frame_cu);
+  bool AddFrameImpl(FrameNodeImpl* frame_cu);
+  bool RemoveFrameImpl(FrameNodeImpl* frame_cu);
 
   // This is called whenever |num_frozen_frames_| changes, or whenever
   // |frame_coordination_units_.size()| changes. It is used to synthesize the
diff --git a/chrome/browser/performance_manager/graph/process_node_impl.cc b/chrome/browser/performance_manager/graph/process_node_impl.cc
index 30626ca66..b6b75d6 100644
--- a/chrome/browser/performance_manager/graph/process_node_impl.cc
+++ b/chrome/browser/performance_manager/graph/process_node_impl.cc
@@ -13,9 +13,12 @@
 ProcessNodeImpl::ProcessNodeImpl(
     const resource_coordinator::CoordinationUnitID& id,
     Graph* graph)
-    : CoordinationUnitInterface(id, graph) {}
+    : CoordinationUnitInterface(id, graph) {
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+}
 
 ProcessNodeImpl::~ProcessNodeImpl() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Make as if we're transitioning to the null PID before we die to clear this
   // instance from the PID map.
   if (process_id_ != base::kNullProcessId)
diff --git a/chrome/browser/performance_manager/graph/system_node_impl.cc b/chrome/browser/performance_manager/graph/system_node_impl.cc
index cf23570..3496179 100644
--- a/chrome/browser/performance_manager/graph/system_node_impl.cc
+++ b/chrome/browser/performance_manager/graph/system_node_impl.cc
@@ -21,7 +21,9 @@
     Graph* graph)
     : CoordinationUnitInterface(id, graph) {}
 
-SystemNodeImpl::~SystemNodeImpl() = default;
+SystemNodeImpl::~SystemNodeImpl() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
 
 void SystemNodeImpl::OnProcessCPUUsageReady() {
   SendEvent(resource_coordinator::mojom::Event::kProcessCPUUsageReady);
diff --git a/chrome/browser/performance_manager/observers/coordination_unit_graph_observer.h b/chrome/browser/performance_manager/observers/coordination_unit_graph_observer.h
index 02d573f..17e00c3 100644
--- a/chrome/browser/performance_manager/observers/coordination_unit_graph_observer.h
+++ b/chrome/browser/performance_manager/observers/coordination_unit_graph_observer.h
@@ -95,6 +95,10 @@
                                      resource_coordinator::mojom::Event event) {
   }
 
+  // FrameNodeImpl notifications.
+  virtual void OnNetworkAlmostIdleChanged(FrameNodeImpl* frame_node) {}
+
+  // PageNodeImpl notifications.
   virtual void OnIsVisibleChanged(PageNodeImpl* page_node) {}
   virtual void OnIsLoadingChanged(PageNodeImpl* page_node) {}
 
diff --git a/chrome/browser/performance_manager/page_resource_coordinator.cc b/chrome/browser/performance_manager/page_resource_coordinator.cc
deleted file mode 100644
index ed014e39..0000000
--- a/chrome/browser/performance_manager/page_resource_coordinator.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/performance_manager/page_resource_coordinator.h"
-#include "base/bind.h"
-
-namespace performance_manager {
-
-PageResourceCoordinator::PageResourceCoordinator(
-    PerformanceManager* performance_manager)
-    : ResourceCoordinatorInterface(), weak_ptr_factory_(this) {
-  resource_coordinator::CoordinationUnitID new_cu_id(
-      resource_coordinator::CoordinationUnitType::kPage,
-      resource_coordinator::CoordinationUnitID::RANDOM_ID);
-  ResourceCoordinatorInterface::ConnectToService(performance_manager,
-                                                 new_cu_id);
-}
-
-PageResourceCoordinator::~PageResourceCoordinator() = default;
-
-void PageResourceCoordinator::SetIsLoading(bool is_loading) {
-  if (!service_)
-    return;
-  service_->SetIsLoading(is_loading);
-}
-
-void PageResourceCoordinator::SetVisibility(bool visible) {
-  if (!service_)
-    return;
-  service_->SetVisibility(visible);
-}
-
-void PageResourceCoordinator::SetUKMSourceId(int64_t ukm_source_id) {
-  if (!service_)
-    return;
-  service_->SetUKMSourceId(ukm_source_id);
-}
-
-void PageResourceCoordinator::OnFaviconUpdated() {
-  if (!service_)
-    return;
-  service_->OnFaviconUpdated();
-}
-
-void PageResourceCoordinator::OnTitleUpdated() {
-  if (!service_)
-    return;
-  service_->OnTitleUpdated();
-}
-
-void PageResourceCoordinator::OnMainFrameNavigationCommitted(
-    base::TimeTicks navigation_committed_time,
-    uint64_t navigation_id,
-    const std::string& url) {
-  if (!service_)
-    return;
-  service_->OnMainFrameNavigationCommitted(navigation_committed_time,
-                                           navigation_id, url);
-}
-
-void PageResourceCoordinator::AddFrame(const FrameResourceCoordinator& frame) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (!service_ || !frame.service())
-    return;
-  // We could keep the ID around ourselves, but this hop ensures that the child
-  // has been created on the service-side.
-  frame.service()->GetID(base::BindOnce(&PageResourceCoordinator::AddFrameByID,
-                                        weak_ptr_factory_.GetWeakPtr()));
-}
-
-void PageResourceCoordinator::RemoveFrame(
-    const FrameResourceCoordinator& frame) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (!service_ || !frame.service())
-    return;
-  frame.service()->GetID(
-      base::BindOnce(&PageResourceCoordinator::RemoveFrameByID,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void PageResourceCoordinator::ConnectToService(
-    resource_coordinator::mojom::CoordinationUnitProviderPtr& provider,
-    const resource_coordinator::CoordinationUnitID& cu_id) {
-  provider->CreatePageCoordinationUnit(mojo::MakeRequest(&service_), cu_id);
-}
-
-void PageResourceCoordinator::AddFrameByID(
-    const resource_coordinator::CoordinationUnitID& cu_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  service_->AddFrame(cu_id);
-}
-
-void PageResourceCoordinator::RemoveFrameByID(
-    const resource_coordinator::CoordinationUnitID& cu_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  service_->RemoveFrame(cu_id);
-}
-
-}  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/page_resource_coordinator.h b/chrome/browser/performance_manager/page_resource_coordinator.h
deleted file mode 100644
index fd82255..0000000
--- a/chrome/browser/performance_manager/page_resource_coordinator.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_PAGE_RESOURCE_COORDINATOR_H_
-#define CHROME_BROWSER_PERFORMANCE_MANAGER_PAGE_RESOURCE_COORDINATOR_H_
-
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "base/time/time.h"
-#include "chrome/browser/performance_manager/frame_resource_coordinator.h"
-#include "chrome/browser/performance_manager/resource_coordinator_interface.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
-
-namespace performance_manager {
-
-class PageResourceCoordinator
-    : public ResourceCoordinatorInterface<
-          resource_coordinator::mojom::PageCoordinationUnitPtr,
-          resource_coordinator::mojom::PageCoordinationUnitRequest> {
- public:
-  explicit PageResourceCoordinator(PerformanceManager* performance_manager);
-  ~PageResourceCoordinator() override;
-
-  void SetIsLoading(bool is_loading);
-  void SetVisibility(bool visible);
-  void SetUKMSourceId(int64_t ukm_source_id);
-  void OnFaviconUpdated();
-  void OnTitleUpdated();
-  void OnMainFrameNavigationCommitted(base::TimeTicks navigation_committed_time,
-                                      uint64_t navigation_id,
-                                      const std::string& url);
-
-  void AddFrame(const FrameResourceCoordinator& frame);
-  void RemoveFrame(const FrameResourceCoordinator& frame);
-
- private:
-  void ConnectToService(
-      resource_coordinator::mojom::CoordinationUnitProviderPtr& provider,
-      const resource_coordinator::CoordinationUnitID& cu_id) override;
-
-  void AddFrameByID(const resource_coordinator::CoordinationUnitID& cu_id);
-  void RemoveFrameByID(const resource_coordinator::CoordinationUnitID& cu_id);
-
-  THREAD_CHECKER(thread_checker_);
-
-  // The WeakPtrFactory should come last so the weak ptrs are invalidated
-  // before the rest of the member variables.
-  base::WeakPtrFactory<PageResourceCoordinator> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(PageResourceCoordinator);
-};
-
-}  // namespace performance_manager
-
-#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_PAGE_RESOURCE_COORDINATOR_H_
diff --git a/chrome/browser/performance_manager/performance_manager.cc b/chrome/browser/performance_manager/performance_manager.cc
index 7460c46..e1523e4 100644
--- a/chrome/browser/performance_manager/performance_manager.cc
+++ b/chrome/browser/performance_manager/performance_manager.cc
@@ -14,6 +14,7 @@
 #include "base/task/task_traits.h"
 #include "build/build_config.h"
 #include "chrome/browser/performance_manager/decorators/page_almost_idle_decorator.h"
+#include "chrome/browser/performance_manager/graph/page_node_impl.h"
 #include "chrome/browser/performance_manager/graph/system_node_impl.h"
 #include "chrome/browser/performance_manager/observers/metrics_collector.h"
 #include "chrome/browser/performance_manager/observers/page_signal_generator_impl.h"
@@ -75,7 +76,19 @@
                      base::Unretained(this), std::move(batch)));
 }
 
-void PerformanceManager::BindInterface(
+std::unique_ptr<FrameNodeImpl> PerformanceManager::CreateFrameNode() {
+  return CreateNodeImpl<FrameNodeImpl>();
+}
+
+std::unique_ptr<PageNodeImpl> PerformanceManager::CreatePageNode() {
+  return CreateNodeImpl<PageNodeImpl>();
+}
+
+std::unique_ptr<ProcessNodeImpl> PerformanceManager::CreateProcessNode() {
+  return CreateNodeImpl<ProcessNodeImpl>();
+}
+
+void PerformanceManager::PostBindInterface(
     const std::string& interface_name,
     mojo::ScopedMessagePipeHandle message_pipe) {
   task_runner_->PostTask(FROM_HERE,
@@ -84,6 +97,30 @@
                                         std::move(message_pipe)));
 }
 
+template <typename NodeType>
+std::unique_ptr<NodeType> PerformanceManager::CreateNodeImpl() {
+  resource_coordinator::CoordinationUnitID id(
+      NodeType::Type(), resource_coordinator::CoordinationUnitID::RANDOM_ID);
+  std::unique_ptr<NodeType> new_node = std::make_unique<NodeType>(id, &graph_);
+  task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&Graph::AddNewNode, base::Unretained(&graph_),
+                                base::Unretained(new_node.get())));
+
+  return new_node;
+}
+
+void PerformanceManager::PostDeleteNode(std::unique_ptr<NodeBase> node) {
+  task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&PerformanceManager::DeleteNodeImpl,
+                                base::Unretained(this), std::move(node)));
+}
+
+void PerformanceManager::DeleteNodeImpl(std::unique_ptr<NodeBase> node) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  graph_.DestroyNode(node.get());
+}
+
 void PerformanceManager::OnStart() {
   // Some tests don't initialize the service manager connection, so this class
   // tolerates its absence for tests.
@@ -125,8 +162,6 @@
     ukm_recorder_ = ukm::MojoUkmRecorder::Create(connector.get());
     graph_.set_ukm_recorder(ukm_recorder_.get());
   }
-
-  graph_.OnStart(&interface_registry_);
 }
 
 void PerformanceManager::BindInterfaceImpl(
diff --git a/chrome/browser/performance_manager/performance_manager.h b/chrome/browser/performance_manager/performance_manager.h
index ea4063c..709cf40 100644
--- a/chrome/browser/performance_manager/performance_manager.h
+++ b/chrome/browser/performance_manager/performance_manager.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/sequence_checker.h"
@@ -27,6 +28,8 @@
 
 namespace performance_manager {
 
+class PageNodeImpl;
+
 // The performance manager is a rendezvous point for binding to performance
 // manager interfaces.
 // TODO(https://crbug.com/910288): Refactor this along with the
@@ -59,14 +62,36 @@
   void DistributeMeasurementBatch(
       resource_coordinator::mojom::ProcessResourceMeasurementBatchPtr batch);
 
+  // Creates a new node of the requested type and adds it to the graph.
+  // May be called from any sequence.
+  std::unique_ptr<FrameNodeImpl> CreateFrameNode();
+  std::unique_ptr<PageNodeImpl> CreatePageNode();
+  std::unique_ptr<ProcessNodeImpl> CreateProcessNode();
+
+  // Destroys a node returned from the creation functions above.
+  // May be called from any sequence.
+  template <typename NodeType>
+  void DeleteNode(std::unique_ptr<NodeType> node);
+
+  // TODO(siggi): Can this be hidden away?
+  scoped_refptr<base::SequencedTaskRunner> task_runner() const {
+    return task_runner_;
+  }
+
  private:
   using InterfaceRegistry = service_manager::BinderRegistryWithArgs<
       const service_manager::BindSourceInfo&>;
 
   PerformanceManager();
 
-  void BindInterface(const std::string& interface_name,
-                     mojo::ScopedMessagePipeHandle message_pipe);
+  void PostBindInterface(const std::string& interface_name,
+                         mojo::ScopedMessagePipeHandle message_pipe);
+
+  template <typename NodeType>
+  std::unique_ptr<NodeType> CreateNodeImpl();
+
+  void PostDeleteNode(std::unique_ptr<NodeBase> node);
+  void DeleteNodeImpl(std::unique_ptr<NodeBase> node);
 
   void OnStart();
   void OnStartImpl(std::unique_ptr<service_manager::Connector> connector);
@@ -102,7 +127,12 @@
 template <typename Interface>
 void PerformanceManager::BindInterface(
     mojo::InterfaceRequest<Interface> request) {
-  BindInterface(Interface::Name_, request.PassMessagePipe());
+  PostBindInterface(Interface::Name_, request.PassMessagePipe());
+}
+
+template <typename NodeType>
+void PerformanceManager::DeleteNode(std::unique_ptr<NodeType> node) {
+  PostDeleteNode(std::move(node));
 }
 
 }  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/performance_manager_tab_helper.cc b/chrome/browser/performance_manager/performance_manager_tab_helper.cc
index c98fb4a..debc45d2 100644
--- a/chrome/browser/performance_manager/performance_manager_tab_helper.cc
+++ b/chrome/browser/performance_manager/performance_manager_tab_helper.cc
@@ -7,8 +7,11 @@
 #include <utility>
 #include <vector>
 
+#include "base/bind.h"
 #include "base/stl_util.h"
-#include "chrome/browser/performance_manager/frame_resource_coordinator.h"
+#include "chrome/browser/performance_manager/graph/frame_node_impl.h"
+#include "chrome/browser/performance_manager/graph/page_node_impl.h"
+#include "chrome/browser/performance_manager/graph/process_node_impl.h"
 #include "chrome/browser/performance_manager/performance_manager.h"
 #include "chrome/browser/performance_manager/render_process_user_data.h"
 #include "content/public/browser/navigation_handle.h"
@@ -26,7 +29,7 @@
   PerformanceManagerTabHelper* helper = FromWebContents(web_contents);
   if (!helper)
     return false;
-  *id = helper->page_resource_coordinator_.id();
+  *id = helper->page_node_->id();
 
   return true;
 }
@@ -41,7 +44,7 @@
     content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents),
       performance_manager_(PerformanceManager::GetInstance()),
-      page_resource_coordinator_(PerformanceManager::GetInstance()) {
+      page_node_(performance_manager_->CreatePageNode()) {
   // Make sure to set the visibility property when we create
   // |page_resource_coordinator_|.
   UpdatePageNodeVisibility(web_contents->GetVisibility());
@@ -68,6 +71,10 @@
 }
 
 PerformanceManagerTabHelper::~PerformanceManagerTabHelper() {
+  performance_manager_->DeleteNode(std::move(page_node_));
+  for (auto& kv : frames_)
+    performance_manager_->DeleteNode(std::move(kv.second));
+
   if (first_ == this)
     first_ = next_;
 
@@ -87,13 +94,16 @@
   // This must not exist in the map yet.
   DCHECK(!base::ContainsKey(frames_, render_frame_host));
 
-  std::unique_ptr<FrameResourceCoordinator> frame =
-      std::make_unique<FrameResourceCoordinator>(performance_manager_);
+  std::unique_ptr<FrameNodeImpl> frame =
+      performance_manager_->CreateFrameNode();
   content::RenderFrameHost* parent = render_frame_host->GetParent();
   if (parent) {
     DCHECK(base::ContainsKey(frames_, parent));
     auto& parent_frame_node = frames_[parent];
-    parent_frame_node->AddChildFrame(*frame.get());
+    performance_manager_->task_runner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&FrameNodeImpl::AddChildFrame,
+                       base::Unretained(parent_frame_node.get()), frame->id()));
   }
 
   RenderProcessUserData* user_data =
@@ -103,24 +113,35 @@
   // is not in play.
   // TODO(siggi): Figure out how to assert on this when the main parts are
   //     registered with the content browser client.
-  if (user_data)
-    frame->SetProcess(*user_data->process_resource_coordinator());
+  if (user_data) {
+    performance_manager_->task_runner()->PostTask(
+        FROM_HERE, base::BindOnce(&FrameNodeImpl::SetProcess,
+                                  base::Unretained(frame.get()),
+                                  user_data->process_node()->id()));
+  }
 
   frames_[render_frame_host] = std::move(frame);
 }
 
 void PerformanceManagerTabHelper::RenderFrameDeleted(
     content::RenderFrameHost* render_frame_host) {
-  DCHECK(base::ContainsKey(frames_, render_frame_host));
-  frames_.erase(render_frame_host);
+  auto it = frames_.find(render_frame_host);
+  DCHECK(it != frames_.end());
+
+  performance_manager_->DeleteNode(std::move(it->second));
+  frames_.erase(it);
 }
 
 void PerformanceManagerTabHelper::DidStartLoading() {
-  page_resource_coordinator_.SetIsLoading(true);
+  performance_manager_->task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&PageNodeImpl::SetIsLoading,
+                                base::Unretained(page_node_.get()), true));
 }
 
 void PerformanceManagerTabHelper::DidStopLoading() {
-  page_resource_coordinator_.SetIsLoading(false);
+  performance_manager_->task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&PageNodeImpl::SetIsLoading,
+                                base::Unretained(page_node_.get()), false));
 }
 
 void PerformanceManagerTabHelper::OnVisibilityChanged(
@@ -149,13 +170,20 @@
   auto it = frames_.find(render_frame_host);
   if (it != frames_.end()) {
     // TODO(siggi): See whether this can be done in RenderFrameCreated.
-    page_resource_coordinator_.AddFrame(*(it->second));
+    performance_manager_->task_runner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&PageNodeImpl::AddFrame,
+                       base::Unretained(page_node_.get()), it->second->id()));
 
     if (navigation_handle->IsInMainFrame()) {
       OnMainFrameNavigation(navigation_handle->GetNavigationId());
-      page_resource_coordinator_.OnMainFrameNavigationCommitted(
-          navigation_committed_time, navigation_handle->GetNavigationId(),
-          navigation_handle->GetURL().spec());
+      performance_manager_->task_runner()->PostTask(
+          FROM_HERE,
+          base::BindOnce(&PageNodeImpl::OnMainFrameNavigationCommitted,
+                         base::Unretained(page_node_.get()),
+                         navigation_committed_time,
+                         navigation_handle->GetNavigationId(),
+                         navigation_handle->GetURL().spec()));
     }
   }
 }
@@ -166,7 +194,9 @@
     first_time_title_set_ = true;
     return;
   }
-  page_resource_coordinator_.OnTitleUpdated();
+  performance_manager_->task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&PageNodeImpl::OnTitleUpdated,
+                                base::Unretained(page_node_.get())));
 }
 
 void PerformanceManagerTabHelper::DidUpdateFaviconURL(
@@ -176,7 +206,9 @@
     first_time_favicon_set_ = true;
     return;
   }
-  page_resource_coordinator_.OnFaviconUpdated();
+  performance_manager_->task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&PageNodeImpl::OnFaviconUpdated,
+                                base::Unretained(page_node_.get())));
 }
 
 void PerformanceManagerTabHelper::OnInterfaceRequestFromFrame(
@@ -189,15 +221,21 @@
 
   auto it = frames_.find(render_frame_host);
   DCHECK(it != frames_.end());
-  it->second->AddBinding(
-      resource_coordinator::mojom::FrameCoordinationUnitRequest(
-          std::move(*interface_pipe)));
+  performance_manager_->task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&FrameNodeImpl::AddBinding,
+                     base::Unretained(it->second.get()),
+                     resource_coordinator::mojom::FrameCoordinationUnitRequest(
+                         std::move(*interface_pipe))));
 }
 
 void PerformanceManagerTabHelper::OnMainFrameNavigation(int64_t navigation_id) {
   ukm_source_id_ =
       ukm::ConvertToSourceId(navigation_id, ukm::SourceIdType::NAVIGATION_ID);
-  page_resource_coordinator_.SetUKMSourceId(ukm_source_id_);
+  performance_manager_->task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&PageNodeImpl::SetUKMSourceId,
+                     base::Unretained(page_node_.get()), ukm_source_id_));
 
   first_time_title_set_ = false;
   first_time_favicon_set_ = false;
@@ -207,7 +245,10 @@
     content::Visibility visibility) {
   // TODO(fdoray): An OCCLUDED tab should not be considered visible.
   const bool is_visible = visibility != content::Visibility::HIDDEN;
-  page_resource_coordinator_.SetVisibility(is_visible);
+  performance_manager_->task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&PageNodeImpl::SetVisibility,
+                     base::Unretained(page_node_.get()), is_visible));
 }
 
 WEB_CONTENTS_USER_DATA_KEY_IMPL(PerformanceManagerTabHelper)
diff --git a/chrome/browser/performance_manager/performance_manager_tab_helper.h b/chrome/browser/performance_manager/performance_manager_tab_helper.h
index 1833612..b4d2861 100644
--- a/chrome/browser/performance_manager/performance_manager_tab_helper.h
+++ b/chrome/browser/performance_manager/performance_manager_tab_helper.h
@@ -11,7 +11,6 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "chrome/browser/performance_manager/page_resource_coordinator.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
@@ -19,8 +18,8 @@
 
 namespace performance_manager {
 
-class FrameResourceCoordinator;
-class PageResourceCoordinator;
+class FrameNodeImpl;
+class PageNodeImpl;
 class PerformanceManager;
 
 // This tab helper maintains a page node, and its associated tree of frame nodes
@@ -42,9 +41,7 @@
 
   ~PerformanceManagerTabHelper() override;
 
-  PageResourceCoordinator* page_resource_coordinator() {
-    return &page_resource_coordinator_;
-  }
+  PageNodeImpl* page_node() { return page_node_.get(); }
 
   // WebContentsObserver overrides.
   void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
@@ -74,8 +71,7 @@
 
   // The performance manager for this process, if any.
   PerformanceManager* const performance_manager_;
-
-  PageResourceCoordinator page_resource_coordinator_;
+  std::unique_ptr<PageNodeImpl> page_node_;
   ukm::SourceId ukm_source_id_ = ukm::kInvalidSourceId;
 
   // Favicon and title are set when a page is loaded, we only want to send
@@ -85,9 +81,8 @@
   bool first_time_favicon_set_ = false;
   bool first_time_title_set_ = false;
 
-  // Maps from RenderFrameHost to the associated RC node.
-  std::map<content::RenderFrameHost*, std::unique_ptr<FrameResourceCoordinator>>
-      frames_;
+  // Maps from RenderFrameHost to the associated PM node.
+  std::map<content::RenderFrameHost*, std::unique_ptr<FrameNodeImpl>> frames_;
 
   // All instances are linked together in a doubly linked list to allow orderly
   // destruction at browser shutdown time.
diff --git a/chrome/browser/performance_manager/performance_manager_unittest.cc b/chrome/browser/performance_manager/performance_manager_unittest.cc
index adca71e..57c5870 100644
--- a/chrome/browser/performance_manager/performance_manager_unittest.cc
+++ b/chrome/browser/performance_manager/performance_manager_unittest.cc
@@ -8,13 +8,9 @@
 
 #include "base/test/bind_test_util.h"
 #include "base/test/scoped_task_environment.h"
-#include "chrome/browser/performance_manager/frame_resource_coordinator.h"
-#include "chrome/browser/performance_manager/page_resource_coordinator.h"
-#include "chrome/browser/performance_manager/process_resource_coordinator.h"
-#include "chrome/browser/performance_manager/system_resource_coordinator.h"
-#include "services/resource_coordinator/public/cpp/coordination_unit_id.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit_provider.mojom.h"
+#include "chrome/browser/performance_manager/graph/frame_node_impl.h"
+#include "chrome/browser/performance_manager/graph/page_node_impl.h"
+#include "chrome/browser/performance_manager/graph/process_node_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace performance_manager {
@@ -42,31 +38,6 @@
     task_environment_.RunUntilIdle();
   }
 
-  // Given a CU, tests that it works by invoking GetID and waiting for the
-  // response. This test will hang (and eventually fail) if the response does
-  // not come back from the remote endpoint.
-  template <typename CoordinationUnitPtrType>
-  void TestCUImpl(CoordinationUnitPtrType cu) {
-    base::RunLoop loop;
-    cu->GetID(base::BindLambdaForTesting(
-        [&loop](const resource_coordinator::CoordinationUnitID& cu_id) {
-          loop.Quit();
-        }));
-    loop.Run();
-  }
-
-  // Variant that works with mojo interface pointers.
-  template <typename CoordinationUnitPtrType>
-  void TestCU(CoordinationUnitPtrType& cu) {
-    TestCUImpl<CoordinationUnitPtrType&>(cu);
-  }
-
-  // Variant that works with pointers to FooResourceCoordinator wrappers.
-  template <typename CoordinationUnitPtrType>
-  void TestCU(CoordinationUnitPtrType* cu) {
-    TestCUImpl<CoordinationUnitPtrType*>(cu);
-  }
-
  protected:
   PerformanceManager* performance_manager() {
     return performance_manager_.get();
@@ -79,50 +50,27 @@
   DISALLOW_COPY_AND_ASSIGN(PerformanceManagerTest);
 };
 
-TEST_F(PerformanceManagerTest, ResourceCoordinatorInstantiate) {
-  // Get the CU provider interface.
-  resource_coordinator::mojom::CoordinationUnitProviderPtr provider;
-  performance_manager()->BindInterface(mojo::MakeRequest(&provider));
+TEST_F(PerformanceManagerTest, InstantiateNodes) {
+  // Create a node of each type.
+  std::unique_ptr<FrameNodeImpl> frame_node =
+      performance_manager()->CreateFrameNode();
+  EXPECT_NE(nullptr, frame_node.get());
 
-  // Create and test a dummy FrameCU.
-  resource_coordinator::CoordinationUnitID frame_id(
-      resource_coordinator::CoordinationUnitType::kFrame,
-      resource_coordinator::CoordinationUnitID::RANDOM_ID);
-  resource_coordinator::mojom::FrameCoordinationUnitPtr frame_cu;
-  provider->CreateFrameCoordinationUnit(mojo::MakeRequest(&frame_cu), frame_id);
-  TestCU(frame_cu);
+  std::unique_ptr<PageNodeImpl> page_node =
+      performance_manager()->CreatePageNode();
+  EXPECT_NE(nullptr, page_node.get());
 
-  // Create and test a dummy PageCU.
-  resource_coordinator::CoordinationUnitID page_id(
-      resource_coordinator::CoordinationUnitType::kPage,
-      resource_coordinator::CoordinationUnitID::RANDOM_ID);
-  resource_coordinator::mojom::PageCoordinationUnitPtr page_cu;
-  provider->CreatePageCoordinationUnit(mojo::MakeRequest(&page_cu), page_id);
-  TestCU(page_cu);
+  std::unique_ptr<ProcessNodeImpl> process_node =
+      performance_manager()->CreateProcessNode();
+  EXPECT_NE(nullptr, process_node.get());
 
-  // Create and test a dummy SystemCU.
-  resource_coordinator::mojom::SystemCoordinationUnitPtr system_cu;
-  provider->GetSystemCoordinationUnit(mojo::MakeRequest(&system_cu));
-  TestCU(system_cu);
-
-  // Create and test a dummy ProcessCU.
-  resource_coordinator::CoordinationUnitID process_id(
-      resource_coordinator::CoordinationUnitType::kProcess,
-      resource_coordinator::CoordinationUnitID::RANDOM_ID);
-  resource_coordinator::mojom::ProcessCoordinationUnitPtr process_cu;
-  provider->CreateProcessCoordinationUnit(mojo::MakeRequest(&process_cu),
-                                          process_id);
-  TestCU(process_cu);
-
-  // Also test the convenience headers for creating and communicating with CUs.
-  FrameResourceCoordinator frame_rc(performance_manager());
-  TestCU(&frame_rc);
-  PageResourceCoordinator page_rc(performance_manager());
-  TestCU(&page_rc);
-  ProcessResourceCoordinator process_rc(performance_manager());
-  TestCU(&process_rc);
-  SystemResourceCoordinator system_rc(performance_manager());
-  TestCU(&system_rc);
+  performance_manager()->DeleteNode(std::move(process_node));
+  performance_manager()->DeleteNode(std::move(page_node));
+  performance_manager()->DeleteNode(std::move(frame_node));
 }
 
+// TODO(siggi): More tests!
+// - Test the WebUI interface.
+// - Test the graph introspector interface.
+
 }  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/process_resource_coordinator.cc b/chrome/browser/performance_manager/process_resource_coordinator.cc
deleted file mode 100644
index f213837..0000000
--- a/chrome/browser/performance_manager/process_resource_coordinator.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/performance_manager/process_resource_coordinator.h"
-
-#include "base/time/time.h"
-#include "build/build_config.h"
-
-namespace performance_manager {
-
-ProcessResourceCoordinator::ProcessResourceCoordinator(
-    PerformanceManager* performance_manager)
-    : ResourceCoordinatorInterface(), weak_ptr_factory_(this) {
-  resource_coordinator::CoordinationUnitID new_cu_id(
-      resource_coordinator::CoordinationUnitType::kProcess,
-      resource_coordinator::CoordinationUnitID::RANDOM_ID);
-  ResourceCoordinatorInterface::ConnectToService(performance_manager,
-                                                 new_cu_id);
-}
-
-ProcessResourceCoordinator::~ProcessResourceCoordinator() = default;
-
-void ProcessResourceCoordinator::OnProcessLaunched(
-    const base::Process& process) {
-  if (!service_)
-    return;
-
-  // TODO(fdoray): Merge ProcessCoordinationUnit::SetPID/SetLaunchTime().
-  service_->SetPID(process.Pid());
-  service_->SetLaunchTime(
-#if defined(OS_ANDROID)
-      // Process::CreationTime() is not available on Android. Since this method
-      // is called immediately after the process is launched, the process launch
-      // time can be approximated with the current time.
-      base::Time::Now()
-#else
-      process.CreationTime()
-#endif
-  );
-}
-
-void ProcessResourceCoordinator::SetCPUUsage(double cpu_usage) {
-  if (!service_)
-    return;
-
-  service_->SetCPUUsage(cpu_usage);
-}
-
-void ProcessResourceCoordinator::SetProcessExitStatus(int32_t exit_status) {
-  if (!service_)
-    return;
-
-  service_->SetProcessExitStatus(exit_status);
-}
-
-void ProcessResourceCoordinator::ConnectToService(
-    resource_coordinator::mojom::CoordinationUnitProviderPtr& provider,
-    const resource_coordinator::CoordinationUnitID& cu_id) {
-  provider->CreateProcessCoordinationUnit(mojo::MakeRequest(&service_), cu_id);
-}
-
-}  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/process_resource_coordinator.h b/chrome/browser/performance_manager/process_resource_coordinator.h
deleted file mode 100644
index fe5475c..0000000
--- a/chrome/browser/performance_manager/process_resource_coordinator.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_PROCESS_RESOURCE_COORDINATOR_H_
-#define CHROME_BROWSER_PERFORMANCE_MANAGER_PROCESS_RESOURCE_COORDINATOR_H_
-
-#include "base/memory/weak_ptr.h"
-#include "base/process/process.h"
-#include "base/threading/thread_checker.h"
-#include "chrome/browser/performance_manager/frame_resource_coordinator.h"
-#include "chrome/browser/performance_manager/resource_coordinator_interface.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
-
-namespace performance_manager {
-
-class ProcessResourceCoordinator
-    : public ResourceCoordinatorInterface<
-          resource_coordinator::mojom::ProcessCoordinationUnitPtr,
-          resource_coordinator::mojom::ProcessCoordinationUnitRequest> {
- public:
-  explicit ProcessResourceCoordinator(PerformanceManager* performance_manager);
-  ~ProcessResourceCoordinator() override;
-
-  // Must be called immediately after the process is launched.
-  void OnProcessLaunched(const base::Process& process);
-
-  void SetCPUUsage(double usage);
-  void SetProcessExitStatus(int32_t exit_status);
-
- private:
-  void ConnectToService(
-      resource_coordinator::mojom::CoordinationUnitProviderPtr& provider,
-      const resource_coordinator::CoordinationUnitID& cu_id) override;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // The WeakPtrFactory should come last so the weak ptrs are invalidated
-  // before the rest of the member variables.
-  base::WeakPtrFactory<ProcessResourceCoordinator> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(ProcessResourceCoordinator);
-};
-
-}  // namespace performance_manager
-
-#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_PROCESS_RESOURCE_COORDINATOR_H_
diff --git a/chrome/browser/performance_manager/render_process_user_data.cc b/chrome/browser/performance_manager/render_process_user_data.cc
index 1ec7eaf4..cb10c81 100644
--- a/chrome/browser/performance_manager/render_process_user_data.cc
+++ b/chrome/browser/performance_manager/render_process_user_data.cc
@@ -7,8 +7,12 @@
 #include <memory>
 #include <utility>
 
+#include "base/bind.h"
 #include "base/command_line.h"
+#include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "build/build_config.h"
+#include "chrome/browser/performance_manager/graph/process_node_impl.h"
 #include "chrome/browser/performance_manager/performance_manager.h"
 #include "content/public/browser/child_process_termination_info.h"
 #include "content/public/browser/render_process_host.h"
@@ -27,8 +31,7 @@
 RenderProcessUserData::RenderProcessUserData(
     content::RenderProcessHost* render_process_host)
     : host_(render_process_host),
-      process_resource_coordinator_(
-          performance_manager::PerformanceManager::GetInstance()) {
+      process_node_(PerformanceManager::GetInstance()->CreateProcessNode()) {
   // The process itself shouldn't have been created at this point.
   DCHECK(!host_->GetProcess().IsValid() ||
          base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -44,6 +47,7 @@
 }
 
 RenderProcessUserData::~RenderProcessUserData() {
+  PerformanceManager::GetInstance()->DeleteNode(std::move(process_node_));
   host_->RemoveObserver(this);
 
   if (first_ == this)
@@ -81,14 +85,38 @@
 
 void RenderProcessUserData::RenderProcessReady(
     content::RenderProcessHost* host) {
-  // TODO(siggi): Rename OnProcessLaunched->OnProcessReady.
-  process_resource_coordinator_.OnProcessLaunched(host->GetProcess());
+  PerformanceManager* performance_manager = PerformanceManager::GetInstance();
+
+  // TODO(siggi): Change this to pass the process into the graph node.
+  const base::ProcessId pid = host->GetProcess().Pid();
+  const base::Time launch_time =
+#if defined(OS_ANDROID)
+      // Process::CreationTime() is not available on Android. Since this
+      // method is called immediately after the process is launched, the
+      // process launch time can be approximated with the current time.
+      base::Time::Now();
+#else
+      host->GetProcess().CreationTime();
+#endif
+
+  performance_manager->task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&ProcessNodeImpl::SetPID,
+                                base::Unretained(process_node_.get()), pid));
+  performance_manager->task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&ProcessNodeImpl::SetLaunchTime,
+                     base::Unretained(process_node_.get()), launch_time));
 }
 
 void RenderProcessUserData::RenderProcessExited(
     content::RenderProcessHost* host,
     const content::ChildProcessTerminationInfo& info) {
-  process_resource_coordinator_.SetProcessExitStatus(info.exit_code);
+  PerformanceManager* performance_manager = PerformanceManager::GetInstance();
+
+  performance_manager->task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&ProcessNodeImpl::SetProcessExitStatus,
+                     base::Unretained(process_node_.get()), info.exit_code));
 }
 
 }  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/render_process_user_data.h b/chrome/browser/performance_manager/render_process_user_data.h
index 5152dcc..18a2554 100644
--- a/chrome/browser/performance_manager/render_process_user_data.h
+++ b/chrome/browser/performance_manager/render_process_user_data.h
@@ -5,9 +5,10 @@
 #ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_RENDER_PROCESS_USER_DATA_H_
 #define CHROME_BROWSER_PERFORMANCE_MANAGER_RENDER_PROCESS_USER_DATA_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "base/supports_user_data.h"
-#include "chrome/browser/performance_manager/process_resource_coordinator.h"
 #include "content/public/browser/render_process_host_observer.h"
 
 namespace content {
@@ -18,6 +19,8 @@
 
 namespace performance_manager {
 
+class ProcessNodeImpl;
+
 // Attached to RenderProcessHost as user data, associates the RenderProcessHost
 // with the Resource Coordinator process node.
 class RenderProcessUserData : public base::SupportsUserData::Data,
@@ -32,10 +35,7 @@
   // Detaches all instances from their RenderProcessHosts and destroys them.
   static void DetachAndDestroyAll();
 
-  performance_manager::ProcessResourceCoordinator*
-  process_resource_coordinator() {
-    return &process_resource_coordinator_;
-  }
+  ProcessNodeImpl* process_node() { return process_node_.get(); }
 
  private:
   explicit RenderProcessUserData(
@@ -56,7 +56,7 @@
 
   content::RenderProcessHost* const host_;
 
-  performance_manager::ProcessResourceCoordinator process_resource_coordinator_;
+  std::unique_ptr<ProcessNodeImpl> process_node_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderProcessUserData);
 };
diff --git a/chrome/browser/performance_manager/resource_coordinator_interface.h b/chrome/browser/performance_manager/resource_coordinator_interface.h
deleted file mode 100644
index 0a182bb..0000000
--- a/chrome/browser/performance_manager/resource_coordinator_interface.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_RESOURCE_COORDINATOR_INTERFACE_H_
-#define CHROME_BROWSER_PERFORMANCE_MANAGER_RESOURCE_COORDINATOR_INTERFACE_H_
-
-#include <stdint.h>
-
-#include "base/component_export.h"
-#include "base/macros.h"
-#include "chrome/browser/performance_manager/performance_manager.h"
-#include "services/resource_coordinator/public/cpp/coordination_unit_id.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit_provider.mojom.h"
-#include "services/resource_coordinator/public/mojom/service_constants.mojom.h"
-
-namespace performance_manager {
-
-template <class CoordinationUnitMojoPtr, class CoordinationUnitMojoRequest>
-class ResourceCoordinatorInterface {
- public:
-  ResourceCoordinatorInterface() = default;
-  virtual ~ResourceCoordinatorInterface() = default;
-
-  void AddBinding(CoordinationUnitMojoRequest request) {
-    if (!service_)
-      return;
-    service_->AddBinding(std::move(request));
-  }
-
-  // Returns the ID. Note that this is meaningless for a singleton CU.
-  resource_coordinator::CoordinationUnitID id() const { return cu_id_; }
-
-  // Returns the remote endpoint interface.
-  const CoordinationUnitMojoPtr& service() const { return service_; }
-
-  // Expose the GetID function for testing.
-  using CoordinationUnitMojo = typename CoordinationUnitMojoPtr::InterfaceType;
-  using GetIDCallback = typename CoordinationUnitMojo::GetIDCallback;
-  void GetID(GetIDCallback callback) {
-    if (!service_)
-      std::move(callback).Run(cu_id_);
-    service_->GetID(std::move(callback));
-  }
-
- protected:
-  virtual void ConnectToService(
-      resource_coordinator::mojom::CoordinationUnitProviderPtr& provider,
-      const resource_coordinator::CoordinationUnitID& cu_id) = 0;
-
-  void ConnectToService(PerformanceManager* performance_manager,
-                        const resource_coordinator::CoordinationUnitID& cu_id) {
-    if (!performance_manager)
-      return;
-    cu_id_ = cu_id;
-    resource_coordinator::mojom::CoordinationUnitProviderPtr provider;
-    performance_manager->BindInterface(mojo::MakeRequest(&provider));
-    ConnectToService(provider, cu_id);
-  }
-
-  CoordinationUnitMojoPtr service_;
-  resource_coordinator::CoordinationUnitID cu_id_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ResourceCoordinatorInterface);
-};
-
-}  // namespace performance_manager
-
-#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_RESOURCE_COORDINATOR_INTERFACE_H_
diff --git a/chrome/browser/performance_manager/system_resource_coordinator.cc b/chrome/browser/performance_manager/system_resource_coordinator.cc
deleted file mode 100644
index eb92375..0000000
--- a/chrome/browser/performance_manager/system_resource_coordinator.cc
+++ /dev/null
@@ -1,34 +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/performance_manager/system_resource_coordinator.h"
-
-namespace performance_manager {
-
-SystemResourceCoordinator::SystemResourceCoordinator(
-    PerformanceManager* performance_manager)
-    : ResourceCoordinatorInterface() {
-  resource_coordinator::CoordinationUnitID new_cu_id(
-      resource_coordinator::CoordinationUnitType::kSystem,
-      resource_coordinator::CoordinationUnitID::RANDOM_ID);
-  ResourceCoordinatorInterface::ConnectToService(performance_manager,
-                                                 new_cu_id);
-}
-
-SystemResourceCoordinator::~SystemResourceCoordinator() = default;
-
-void SystemResourceCoordinator::DistributeMeasurementBatch(
-    resource_coordinator::mojom::ProcessResourceMeasurementBatchPtr batch) {
-  if (!service_)
-    return;
-  service_->DistributeMeasurementBatch(std::move(batch));
-}
-
-void SystemResourceCoordinator::ConnectToService(
-    resource_coordinator::mojom::CoordinationUnitProviderPtr& provider,
-    const resource_coordinator::CoordinationUnitID& cu_id) {
-  provider->GetSystemCoordinationUnit(mojo::MakeRequest(&service_));
-}
-
-}  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/system_resource_coordinator.h b/chrome/browser/performance_manager/system_resource_coordinator.h
deleted file mode 100644
index 672ce8b..0000000
--- a/chrome/browser/performance_manager/system_resource_coordinator.h
+++ /dev/null
@@ -1,34 +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_PERFORMANCE_MANAGER_SYSTEM_RESOURCE_COORDINATOR_H_
-#define CHROME_BROWSER_PERFORMANCE_MANAGER_SYSTEM_RESOURCE_COORDINATOR_H_
-
-#include "chrome/browser/performance_manager/resource_coordinator_interface.h"
-#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
-
-namespace performance_manager {
-
-class SystemResourceCoordinator
-    : public ResourceCoordinatorInterface<
-          resource_coordinator::mojom::SystemCoordinationUnitPtr,
-          resource_coordinator::mojom::SystemCoordinationUnitRequest> {
- public:
-  explicit SystemResourceCoordinator(PerformanceManager* performance_manager);
-  ~SystemResourceCoordinator() override;
-
-  void DistributeMeasurementBatch(
-      resource_coordinator::mojom::ProcessResourceMeasurementBatchPtr batch);
-
- private:
-  void ConnectToService(
-      resource_coordinator::mojom::CoordinationUnitProviderPtr& provider,
-      const resource_coordinator::CoordinationUnitID& cu_id) override;
-
-  DISALLOW_COPY_AND_ASSIGN(SystemResourceCoordinator);
-};
-
-}  // namespace performance_manager
-
-#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_SYSTEM_RESOURCE_COORDINATOR_H_
diff --git a/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc b/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc
index 0205b75..d05f4764 100644
--- a/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc
+++ b/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc
@@ -10,7 +10,6 @@
 #include "chrome/browser/performance_manager/browser_child_process_watcher.h"
 #include "chrome/browser/performance_manager/performance_manager.h"
 #include "chrome/browser/performance_manager/performance_manager_tab_helper.h"
-#include "chrome/browser/performance_manager/process_resource_coordinator.h"
 #include "chrome/browser/performance_manager/render_process_user_data.h"
 #include "chrome/browser/resource_coordinator/page_signal_receiver.h"
 #include "chrome/browser/resource_coordinator/render_process_probe.h"
diff --git a/chrome/browser/resources/app_management/app.html b/chrome/browser/resources/app_management/app.html
index 3b99164..81dbfb2 100644
--- a/chrome/browser/resources/app_management/app.html
+++ b/chrome/browser/resources/app_management/app.html
@@ -28,11 +28,6 @@
         overflow: hidden;
       }
 
-      cr-toolbar {
-        background: var(--md-toolbar-color);
-        min-height: var(--toolbar-height);
-      }
-
       #main-container {
         flex: 1;
         overflow: auto;
diff --git a/chrome/browser/resources/app_management/shared_vars.html b/chrome/browser/resources/app_management/shared_vars.html
index 1d62aba..860c609 100644
--- a/chrome/browser/resources/app_management/shared_vars.html
+++ b/chrome/browser/resources/app_management/shared_vars.html
@@ -20,7 +20,6 @@
     --primary-text-color: rgba(0, 0, 0, 0.87);
     --secondary-font-weight: 400;
     --secondary-text-color: rgba(0, 0, 0, 0.54);
-    --toolbar-height: 56px;
   }
 </style>
 </custom-style>
diff --git a/chrome/browser/resources/bookmarks/bookmarks.html b/chrome/browser/resources/bookmarks/bookmarks.html
index 6b7581da..b91e6202 100644
--- a/chrome/browser/resources/bookmarks/bookmarks.html
+++ b/chrome/browser/resources/bookmarks/bookmarks.html
@@ -19,8 +19,13 @@
       overflow: hidden;
     }
 
-    html.loading {
-      border-top: 56px solid var(--md-toolbar-color);
+    html.loading::before {
+      background-color: var(--md-toolbar-color);
+      border-bottom: var(--md-toolbar-border);
+      box-sizing: border-box;
+      content: '';
+      display: block;
+      height: var(--md-toolbar-height);
     }
   </style>
 </head>
diff --git a/chrome/browser/resources/bookmarks/toolbar.html b/chrome/browser/resources/bookmarks/toolbar.html
index 715f1e9..d6579e9 100644
--- a/chrome/browser/resources/bookmarks/toolbar.html
+++ b/chrome/browser/resources/bookmarks/toolbar.html
@@ -11,7 +11,6 @@
   <template>
     <style include="shared-style">
       :host {
-        background: var(--md-toolbar-color);
         position: relative;
       }
 
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing.css b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing.css
index 59a7eeac..0502cb7 100644
--- a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing.css
+++ b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing.css
@@ -28,6 +28,11 @@
   margin: 0 0 4px 0;
 }
 
+.arc-events-inner-band-last-buffer {
+  display: block;
+  margin: 0 0 12px 0;
+}
+
 .arc-events-top-band {
   display: block;
   margin: 0 0 8px 0;
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.js b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.js
index 17c80a4..d66ab314 100644
--- a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.js
+++ b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.js
@@ -12,65 +12,98 @@
 // Background color for the band with events.
 var bandColor = '#d3d3d3';
 
+// Color that should never appear on UI.
+var unusedColor = '#ff0000';
+
 /**
  * Keep in sync with ArcTracingGraphicsModel::BufferEventType
  * See chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.h.
  * Describes how events should be rendered. |color| specifies color of the
- * event, |idle| indicates if this is the last event in the sequence of
- * events. In case |idle| is true this means that sequence of events is
- * done and relevant component is idle. |name| is used in tooltips.
+ * event, |name| is used in tooltips.
  */
 var eventAttributes = {
   // kBufferQueueDequeueStart
-  100: {color: '#99cc00', idle: false, name: 'app requests buffer'},
+  100: {color: '#99cc00', name: 'app requests buffer'},
   // kBufferQueueDequeueDone
-  101: {color: '#669999', idle: false, name: 'app fills buffer'},
+  101: {color: '#669999', name: 'app fills buffer'},
   // kBufferQueueQueueStart
-  102: {color: '#cccc00', idle: false, name: 'app queues buffer'},
+  102: {color: '#cccc00', name: 'app queues buffer'},
   // kBufferQueueQueueDone
-  103: {color: bandColor, idle: true, name: 'buffer is queued'},
+  103: {color: unusedColor, name: 'buffer is queued'},
   // kBufferQueueAcquire
-  104: {color: '#66ffcc', idle: false, name: 'use buffer'},
+  104: {color: '#66ffcc', name: 'use buffer'},
   // kBufferQueueReleased
-  105: {color: bandColor, idle: true, name: 'buffer released'},
+  105: {color: unusedColor, name: 'buffer released'},
 
   // kExoSurfaceAttach.
-  200: {color: '#99ccff', idle: false, name: 'surface attach'},
+  200: {color: '#99ccff', name: 'surface attach'},
   // kExoProduceResource
-  201: {color: '#cc66ff', idle: false, name: 'produce resource'},
+  201: {color: '#cc66ff', name: 'produce resource'},
   // kExoBound
-  202: {color: '#66ffff', idle: false, name: 'buffer bound'},
+  202: {color: '#66ffff', name: 'buffer bound'},
   // kExoPendingQuery
-  203: {color: '#00ff99', idle: false, name: 'pending query'},
+  203: {color: '#00ff99', name: 'pending query'},
   // kExoReleased
-  204: {color: bandColor, idle: true, name: 'released'},
+  204: {color: unusedColor, name: 'released'},
 
   // kChromeBarrierOrder.
-  300: {color: '#ff9933', idle: false, name: 'barrier order'},
+  300: {color: '#ff9933', name: 'barrier order'},
   // kChromeBarrierFlush
-  301: {color: bandColor, idle: true, name: 'barrier flush'},
+  301: {color: unusedColor, name: 'barrier flush'},
 
   // kVsync
-  400: {color: '#ff3300', idle: false, name: 'vsync'},
+  400: {color: '#ff3300', name: 'vsync'},
   // kSurfaceFlingerInvalidationStart
-  401: {color: '#ff9933', idle: false, name: 'invalidation start'},
+  401: {color: '#ff9933', name: 'invalidation start'},
   // kSurfaceFlingerInvalidationDone
-  402: {color: bandColor, idle: true, name: 'invalidation done'},
+  402: {color: unusedColor, name: 'invalidation done'},
   // kSurfaceFlingerCompositionStart
-  403: {color: '#3399ff', idle: false, name: 'composition start'},
+  403: {color: '#3399ff', name: 'composition start'},
   // kSurfaceFlingerCompositionDone
-  404: {color: bandColor, idle: true, name: 'composition done'},
+  404: {color: unusedColor, name: 'composition done'},
 
   // kChromeOSDraw
-  500: {color: '#3399ff', idle: false, name: 'draw'},
+  500: {color: '#3399ff', name: 'draw'},
   // kChromeOSSwap
-  501: {color: '#cc9900', idle: false, name: 'swap'},
+  501: {color: '#cc9900', name: 'swap'},
   // kChromeOSWaitForAck
-  502: {color: '#ccffff', idle: false, name: 'wait for ack'},
-  // kChromeOSWaitForPresentation
-  503: {color: '#65f441', idle: false, name: 'wait for presentation'},
-  // kChromeOSDrawFinished
-  504: {color: bandColor, idle: true, name: 'done'},
+  502: {color: '#ccffff', name: 'wait for ack'},
+  // kChromeOSPresentationDone
+  503: {color: '#ffbf00', name: 'presentation done'},
+  // kChromeOSSwapDone
+  504: {color: '#65f441', name: 'swap done'},
+};
+
+/**
+ * Defines the map of events that can be treated as the end of event sequence.
+ * Time after such events is considered as idle time until the next event
+ * starts. Key of |endSequenceEvents| is event type as defined in
+ * ArcTracingGraphicsModel::BufferEventType and value is the list of event
+ * types that should follow after the tested event to consider it as end of
+ * sequence. Empty list means that tested event is certainly end of the
+ * sequence.
+ */
+var endSequenceEvents = {
+  // kBufferQueueQueueDone
+  103: [],
+  // kBufferQueueReleased
+  105: [],
+  // kExoReleased
+  204: [],
+  // kChromeBarrierFlush
+  301: [],
+  // kSurfaceFlingerInvalidationDone
+  402: [],
+  // kSurfaceFlingerCompositionDone
+  404: [],
+  // kChromeOSPresentationDone. Chrome does not define exactly which event
+  // is the last. Different
+  // pipelines may produce different sequences. Both event type may indicate
+  // the end of the
+  /// sequence.
+  503: [500 /* kChromeOSDraw */],
+  // kChromeOSSwapDone
+  504: [500 /* kChromeOSDraw */],
 };
 
 /**
@@ -238,7 +271,11 @@
       }
       var nextX = timestampToOffset(event[1]);
       SVG.addRect(this.svg, x, 0, nextX - x, this.height, currentColor);
-      currentColor = eventAttributes[event[0]].color;
+      if (this.isEndOfSequence_(i)) {
+        currentColor = bandColor;
+      } else {
+        currentColor = eventAttributes[event[0]].color;
+      }
       x = nextX;
     }
     SVG.addRect(this.svg, x, 0, this.width - x, this.height, currentColor);
@@ -288,6 +325,27 @@
   }
 
   /**
+   * Returns true if the tested event denotes end of event sequence.
+   *
+   * @param {number} index element index in |this.events|.
+   */
+  isEndOfSequence_(index) {
+    var nextEventTypes = endSequenceEvents[this.events[index][0]];
+    if (!nextEventTypes) {
+      return false;
+    }
+    if (nextEventTypes.length == 0) {
+      return true;
+    }
+    var nextIndex = this.getNextEvent_(index, 1 /* direction */);
+    if (nextIndex < 0) {
+      // No more events after and it is listed as possible end of sequence.
+      return true;
+    }
+    return nextEventTypes.includes(this.events[nextIndex][0]);
+  }
+
+  /**
    * Updates tool tip based on event under the current cursor.
    *
    * @param {Object} event mouse event.
@@ -325,7 +383,7 @@
 
     // In case cursor points to idle event, show its interval. Otherwise
     // show the sequence of non-idle events.
-    if (index < 0 || this.getEventAttributes_(index).idle) {
+    if (index < 0 || this.isEndOfSequence_(index)) {
       var startIdle = index < 0 ? 0 : this.events[index][1];
       var endIdle = index < 0 ? this.duration : this.events[nextIndex][1];
       SVG.addText(
@@ -337,7 +395,7 @@
       // Find the start of the non-idle sequence.
       while (true) {
         var prevIndex = this.getNextEvent_(index, -1 /* direction */);
-        if (prevIndex < 0 || this.getEventAttributes_(prevIndex).idle) {
+        if (prevIndex < 0 || this.isEndOfSequence_(prevIndex)) {
           break;
         }
         index = prevIndex;
@@ -368,12 +426,17 @@
               ' [' + timestempToMsText(eventTimestamp - lastTimestamp) + ' ms]';
         }
         entriesToShow.push(entryToShow);
-        if (attributes.idle) {
+        if (this.isEndOfSequence_(index)) {
           break;
         }
         lastTimestamp = eventTimestamp;
         index = this.getNextEvent_(index, 1 /* direction */);
       }
+
+      // Last element is end of sequence, use bandColor for the icon.
+      if (entriesToShow.length > 0) {
+        entriesToShow[entriesToShow.length - 1].color = bandColor;
+      }
       for (var i = 0; i < entriesToShow.length; ++i) {
         var entryToShow = entriesToShow[i];
         SVG.addText(
@@ -425,7 +488,7 @@
     var view = model.views[i];
     var activityTitleText;
     var icon;
-    if (view.task_id in model.tasks) {
+    if (model.tasks && view.task_id in model.tasks) {
       activityTitleText =
           model.tasks[view.task_id].title + ' - ' + view.activity;
       icon = model.tasks[view.task_id].icon;
@@ -441,7 +504,8 @@
           activityTitle, 'arc-events-inner-band', model.duration, 14);
       exoBand.setEvents(view.buffers[j], 200, 204);
       var chromeBand = new EventBand(
-          activityTitle, 'arc-events-inner-band', model.duration, 14);
+          activityTitle, 'arc-events-inner-band-last-buffer', model.duration,
+          14);
       chromeBand.setEvents(view.buffers[j], 300, 301);
     }
   }
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing_test.extjs
index 3f09d04..9394937e 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing_test.extjs
@@ -257,7 +257,8 @@
   });
 });
 
-TEST_F('ChromeVoxEditingTest', 'RichTextMoveByCharacterAllAttributes', function() {
+// Flakily times out. crbug.com/942241
+TEST_F('ChromeVoxEditingTest', 'DISABLED_RichTextMoveByCharacterAllAttributes', function() {
   var mockFeedback = this.createMockFeedback();
   this.runWithLoadedTree(function() {/*!
     <div role="textbox" contenteditable>
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_hid_detection.js b/chrome/browser/resources/chromeos/login/oobe_screen_hid_detection.js
index c12e79f0c..8dd1d49e 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_hid_detection.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_hid_detection.js
@@ -23,7 +23,7 @@
       'setKeyboardState',
       'setMouseState',
       'setKeyboardPinCode',
-      'setKeyboardEnteredExpected',
+      'setNumKeysEnteredExpected',
       'setNumKeysEnteredPincode',
       'setMouseDeviceName',
       'setKeyboardDeviceName',
@@ -79,7 +79,7 @@
       this.updatePincodeKeysState_();
     },
 
-    setKeyboardEnteredExpected: function(value) {
+    setNumKeysEnteredExpected: function(value) {
       this.keyboardEnteredExpected_ = value;
       this.updatePincodeKeysState_();
     },
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_reset.js b/chrome/browser/resources/chromeos/login/oobe_screen_reset.js
index 63402bf..ed988a2 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_reset.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_reset.js
@@ -9,99 +9,128 @@
 login.createScreen('ResetScreen', 'reset', function() {
   var USER_ACTION_CANCEL_RESET = 'cancel-reset';
   var USER_ACTION_RESET_CONFIRM_DISMISSED = 'reset-confirm-dismissed';
-  var CONTEXT_KEY_ROLLBACK_AVAILABLE = 'rollback-available';
-  var CONTEXT_KEY_ROLLBACK_CHECKED = 'rollback-checked';
-  var CONTEXT_KEY_TPM_FIRMWARE_UPDATE_AVAILABLE =
-      'tpm-firmware-update-available';
-  var CONTEXT_KEY_TPM_FIRMWARE_UPDATE_CHECKED = 'tpm-firmware-update-checked';
-  var CONTEXT_KEY_TPM_FIRMWARE_UPDATE_EDITABLE = 'tpm-firmware-update-editable';
-  var CONTEXT_KEY_IS_OFFICIAL_BUILD = 'is-official-build';
-  var CONTEXT_KEY_IS_CONFIRMATIONAL_VIEW = 'is-confirmational-view';
-  var CONTEXT_KEY_SCREEN_STATE = 'screen-state';
+
+  /* Possible UI states of the reset screen. */
+  const RESET_SCREEN_UI_STATE = {
+    REVERT_PROMISE: 'ui-state-revert-promise',
+    RESTART_REQUIRED: 'ui-state-restart-required',
+    POWERWASH_PROPOSAL: 'ui-state-powerwash-proposal',
+    ROLLBACK_PROPOSAL: 'ui-state-rollback-proposal',
+    ERROR: 'ui-state-error',
+  };
+
+  const RESET_SCREEN_STATE = {
+    RESTART_REQUIRED: 0,
+    REVERT_PROMISE: 1,
+    POWERWASH_PROPOSAL: 2,  // supports 2 ui-states
+    ERROR: 3,
+  };
 
   return {
+    EXTERNAL_API: [
+      'setIsRollbackAvailable',
+      'setIsRollbackChecked',
+      'setIsTpmFirmwareUpdateAvailable',
+      'setIsTpmFirmwareUpdateChecked',
+      'setIsTpmFirmwareUpdateEditable',
+      'setTpmFirmwareUpdateMode',
+      'setIsConfirmational',
+      'setIsOfficialBuild',
+      'setScreenState',
+    ],
 
-    /* Possible UI states of the reset screen. */
-    RESET_SCREEN_UI_STATE: {
-      REVERT_PROMISE: 'ui-state-revert-promise',
-      RESTART_REQUIRED: 'ui-state-restart-required',
-      POWERWASH_PROPOSAL: 'ui-state-powerwash-proposal',
-      ROLLBACK_PROPOSAL: 'ui-state-rollback-proposal',
-      ERROR: 'ui-state-error',
+    /** @type {boolean} */
+    isRollbackAvailable_: false,
+    /** @type {boolean} */
+    isRollbackChecked_: false,
+    /** @type {boolean} */
+    isTpmFirmwareUpdateAvailable_: false,
+    /** @type {boolean} */
+    isTpmFirmwareUpdateChecked_: false,
+    /** @type {boolean} */
+    isTpmFirmwareUpdateEditable_: false,
+    /** @type {RESET_SCREEN_UI_STATE} */
+    tpmFirmwareUpdateMode_: RESET_SCREEN_UI_STATE.REVERT_PROMISE,
+    /** @type {boolean} */
+    isConfirmational_: false,
+    /** @type {boolean} */
+    isOfficialBuild_: false,
+    /** @type {RESET_SCREEN_STATE} */
+    screenState_: RESET_SCREEN_STATE.RESTART_REQUIRED,
+
+    setIsRollbackAvailable: function(rollbackAvailable) {
+      this.isRollbackAvailable_ = rollbackAvailable;
+      this.setRollbackOptionView();
     },
 
-    RESET_SCREEN_STATE: {
-      RESTART_REQUIRED: 0,
-      REVERT_PROMISE: 1,
-      POWERWASH_PROPOSAL: 2,  // supports 2 ui-states
-      ERROR: 3,
+    setIsRollbackChecked: function(rollbackChecked) {
+      this.isRollbackChecked_ = rollbackChecked;
+      this.setRollbackOptionView();
     },
 
+    setIsTpmFirmwareUpdateAvailable: function(value) {
+      this.isTpmFirmwareUpdateAvailable_ = value;
+      this.setTPMFirmwareUpdateView_();
+    },
+
+    setIsTpmFirmwareUpdateChecked: function(value) {
+      this.isTpmFirmwareUpdateChecked_ = value;
+      this.setTPMFirmwareUpdateView_();
+    },
+
+    setIsTpmFirmwareUpdateEditable: function(value) {
+      this.isTpmFirmwareUpdateEditable_ = value;
+      this.setTPMFirmwareUpdateView_();
+    },
+
+    setTpmFirmwareUpdateMode: function(value) {
+      this.tpmFirmwareUpdateMode_ = value;
+    },
+
+    setIsConfirmational: function(isConfirmational) {
+      this.isConfirmational_ = isConfirmational;
+      if (isConfirmational) {
+        if (this.screenState_ != RESET_SCREEN_STATE.POWERWASH_PROPOSAL)
+          return;
+        $('overlay-reset').removeAttribute('hidden');
+        $('reset-confirm-overlay-md').open();
+      } else {
+        $('overlay-reset').setAttribute('hidden', true);
+        $('reset-confirm-overlay-md').close();
+      }
+    },
+
+    setIsOfficialBuild: function(isOfficial) {
+      this.isOfficialBuild_ = isOfficial;
+
+      $('oobe-reset-md').isOfficial_ = isOfficial;
+    },
+
+    setScreenState: function(state) {
+      this.screenState_ = state;
+
+      if (Oobe.getInstance().currentScreen != this) {
+        setTimeout(function() {
+          Oobe.resetSigninUI(false);
+          Oobe.showScreen({id: SCREEN_OOBE_RESET});
+        }, 0);
+      }
+      if (state == RESET_SCREEN_STATE.RESTART_REQUIRED)
+        this.ui_state = RESET_SCREEN_UI_STATE.RESTART_REQUIRED;
+      if (state == RESET_SCREEN_STATE.REVERT_PROMISE)
+        this.ui_state = RESET_SCREEN_UI_STATE.REVERT_PROMISE;
+      else if (state == RESET_SCREEN_STATE.POWERWASH_PROPOSAL)
+        this.ui_state = RESET_SCREEN_UI_STATE.POWERWASH_PROPOSAL;
+      this.setDialogView_();
+      if (state == RESET_SCREEN_STATE.REVERT_PROMISE) {
+        announceAccessibleMessage(
+            loadTimeData.getString('resetRevertSpinnerMessage'));
+      }
+      this.setTPMFirmwareUpdateView_();
+    },
 
     /** @override */
     decorate: function() {
-      var self = this;
-
-      this.context.addObserver(CONTEXT_KEY_SCREEN_STATE, function(state) {
-        if (Oobe.getInstance().currentScreen != this) {
-          setTimeout(function() {
-            Oobe.resetSigninUI(false);
-            Oobe.showScreen({id: SCREEN_OOBE_RESET});
-          }, 0);
-        }
-        if (state == self.RESET_SCREEN_STATE.RESTART_REQUIRED)
-          self.ui_state = self.RESET_SCREEN_UI_STATE.RESTART_REQUIRED;
-        if (state == self.RESET_SCREEN_STATE.REVERT_PROMISE)
-          self.ui_state = self.RESET_SCREEN_UI_STATE.REVERT_PROMISE;
-        else if (state == self.RESET_SCREEN_STATE.POWERWASH_PROPOSAL)
-          self.ui_state = self.RESET_SCREEN_UI_STATE.POWERWASH_PROPOSAL;
-        self.setDialogView_();
-        if (state == self.RESET_SCREEN_STATE.REVERT_PROMISE) {
-          announceAccessibleMessage(
-              loadTimeData.getString('resetRevertSpinnerMessage'));
-        }
-        self.setTPMFirmwareUpdateView_();
-      });
-
-      this.context.addObserver(
-          CONTEXT_KEY_IS_OFFICIAL_BUILD, function(isOfficial) {
-            $('oobe-reset-md').isOfficial_ = isOfficial;
-          });
-      this.context.addObserver(
-          CONTEXT_KEY_ROLLBACK_CHECKED, function(rollbackChecked) {
-            self.setRollbackOptionView();
-          });
-      this.context.addObserver(
-          CONTEXT_KEY_ROLLBACK_AVAILABLE, function(rollbackAvailable) {
-            self.setRollbackOptionView();
-          });
-      this.context.addObserver(
-          CONTEXT_KEY_TPM_FIRMWARE_UPDATE_CHECKED, function() {
-            self.setTPMFirmwareUpdateView_();
-          });
-      this.context.addObserver(
-          CONTEXT_KEY_TPM_FIRMWARE_UPDATE_EDITABLE, function() {
-            self.setTPMFirmwareUpdateView_();
-          });
-      this.context.addObserver(
-          CONTEXT_KEY_TPM_FIRMWARE_UPDATE_AVAILABLE, function() {
-            self.setTPMFirmwareUpdateView_();
-          });
-      this.context.addObserver(
-          CONTEXT_KEY_IS_CONFIRMATIONAL_VIEW, function(is_confirmational) {
-            if (is_confirmational) {
-              if (self.context.get(CONTEXT_KEY_SCREEN_STATE, 0) !=
-                  self.RESET_SCREEN_STATE.POWERWASH_PROPOSAL) {
-                return;
-              }
-              $('overlay-reset').removeAttribute('hidden');
-              $('reset-confirm-overlay-md').open();
-            } else {
-              $('overlay-reset').setAttribute('hidden', true);
-              $('reset-confirm-overlay-md').close();
-            }
-          });
-
       $('oobe-reset-md').screen = this;
     },
 
@@ -124,7 +153,7 @@
      * Cancels the reset and drops the user back to the login screen.
      */
     cancel: function() {
-      if (this.context.get(CONTEXT_KEY_IS_CONFIRMATIONAL_VIEW, false)) {
+      if (this.isConfirmational_) {
         $('reset').send(
             login.Screen.CALLBACK_USER_ACTED,
             USER_ACTION_RESET_CONFIRM_DISMISSED);
@@ -146,47 +175,44 @@
     setDialogView_: function(state) {
       state = this.ui_state;
       this.classList.toggle(
-          'revert-promise-view',
-          state == this.RESET_SCREEN_UI_STATE.REVERT_PROMISE);
+          'revert-promise-view', state == RESET_SCREEN_UI_STATE.REVERT_PROMISE);
       this.classList.toggle(
           'restart-required-view',
-          state == this.RESET_SCREEN_UI_STATE.RESTART_REQUIRED);
+          state == RESET_SCREEN_UI_STATE.RESTART_REQUIRED);
       this.classList.toggle(
           'powerwash-proposal-view',
-          state == this.RESET_SCREEN_UI_STATE.POWERWASH_PROPOSAL);
+          state == RESET_SCREEN_UI_STATE.POWERWASH_PROPOSAL);
       this.classList.toggle(
           'rollback-proposal-view',
-          state == this.RESET_SCREEN_UI_STATE.ROLLBACK_PROPOSAL);
+          state == RESET_SCREEN_UI_STATE.ROLLBACK_PROPOSAL);
       var resetMd = $('oobe-reset-md');
       var resetOverlayMd = $('reset-confirm-overlay-md');
-      if (state == this.RESET_SCREEN_UI_STATE.RESTART_REQUIRED) {
+      if (state == RESET_SCREEN_UI_STATE.RESTART_REQUIRED) {
         resetMd.uiState_ = 'restart-required-view';
       }
-      if (state == this.RESET_SCREEN_UI_STATE.POWERWASH_PROPOSAL) {
+      if (state == RESET_SCREEN_UI_STATE.POWERWASH_PROPOSAL) {
         resetMd.uiState_ = 'powerwash-proposal-view';
         resetOverlayMd.isPowerwashView_ = true;
       }
-      if (state == this.RESET_SCREEN_UI_STATE.ROLLBACK_PROPOSAL) {
+      if (state == RESET_SCREEN_UI_STATE.ROLLBACK_PROPOSAL) {
         resetMd.uiState_ = 'rollback-proposal-view';
         resetOverlayMd.isPowerwashView_ = false;
       }
-      if (state == this.RESET_SCREEN_UI_STATE.REVERT_PROMISE) {
+      if (state == RESET_SCREEN_UI_STATE.REVERT_PROMISE) {
         resetMd.uiState_ = 'revert-promise-view';
       }
     },
 
     setRollbackOptionView: function() {
-      if (this.context.get(CONTEXT_KEY_IS_CONFIRMATIONAL_VIEW, false))
+      if (this.isConfirmational_)
         return;
-      if (this.context.get(CONTEXT_KEY_SCREEN_STATE) !=
-          this.RESET_SCREEN_STATE.POWERWASH_PROPOSAL)
+      if (this.screenState_ != RESET_SCREEN_STATE.POWERWASH_PROPOSAL)
         return;
 
-      if (this.context.get(CONTEXT_KEY_ROLLBACK_AVAILABLE, false) &&
-          this.context.get(CONTEXT_KEY_ROLLBACK_CHECKED, false)) {
-        this.ui_state = this.RESET_SCREEN_UI_STATE.ROLLBACK_PROPOSAL;
+      if (this.isRollbackAvailable_ && this.isRollbackChecked_) {
+        this.ui_state = RESET_SCREEN_UI_STATE.ROLLBACK_PROPOSAL;
       } else {
-        this.ui_state = this.RESET_SCREEN_UI_STATE.POWERWASH_PROPOSAL;
+        this.ui_state = RESET_SCREEN_UI_STATE.POWERWASH_PROPOSAL;
       }
       this.setDialogView_();
       this.setTPMFirmwareUpdateView_();
@@ -194,17 +220,16 @@
 
     setTPMFirmwareUpdateView_: function() {
       $('oobe-reset-md').tpmFirmwareUpdateAvailable_ =
-          this.ui_state == this.RESET_SCREEN_UI_STATE.POWERWASH_PROPOSAL &&
-          this.context.get(CONTEXT_KEY_TPM_FIRMWARE_UPDATE_AVAILABLE);
+          this.ui_state == RESET_SCREEN_UI_STATE.POWERWASH_PROPOSAL &&
+          this.isTpmFirmwareUpdateAvailable_;
       $('oobe-reset-md').tpmFirmwareUpdateChecked_ =
-          this.context.get(CONTEXT_KEY_TPM_FIRMWARE_UPDATE_CHECKED);
+          this.isTpmFirmwareUpdateChecked_;
       $('oobe-reset-md').tpmFirmwareUpdateEditable_ =
-          this.context.get(CONTEXT_KEY_TPM_FIRMWARE_UPDATE_EDITABLE);
+          this.isTpmFirmwareUpdateEditable_;
     },
 
     onTPMFirmwareUpdateChanged_: function(value) {
-      this.context.set(CONTEXT_KEY_TPM_FIRMWARE_UPDATE_CHECKED, value);
-      this.commitContextChanges();
+      chrome.send('ResetScreen.setTpmFirmwareUpdateChecked', [value]);
     }
   };
 });
diff --git a/chrome/browser/resources/downloads/downloads.html b/chrome/browser/resources/downloads/downloads.html
index 2397587..dcb81ef 100644
--- a/chrome/browser/resources/downloads/downloads.html
+++ b/chrome/browser/resources/downloads/downloads.html
@@ -12,8 +12,13 @@
       touch-action: manipulation;
     }
 
-    html.loading {
-      border-top: 56px solid var(--md-toolbar-color);
+    html.loading::before {
+      background-color: var(--md-toolbar-color);
+      border-bottom: var(--md-toolbar-border);
+      box-sizing: border-box;
+      content: '';
+      display: block;
+      height: var(--md-toolbar-height);
     }
 
     html:not(.loading),
diff --git a/chrome/browser/resources/downloads/toolbar.html b/chrome/browser/resources/downloads/toolbar.html
index f9b804f..80fc546b 100644
--- a/chrome/browser/resources/downloads/toolbar.html
+++ b/chrome/browser/resources/downloads/toolbar.html
@@ -19,7 +19,6 @@
     <style include="cr-hidden-style">
       :host {
         align-items: center;
-        background: var(--md-toolbar-color);
         display: flex;
         min-height: 56px;
       }
diff --git a/chrome/browser/resources/history/app.html b/chrome/browser/resources/history/app.html
index 8579929..736edaf 100644
--- a/chrome/browser/resources/history/app.html
+++ b/chrome/browser/resources/history/app.html
@@ -28,10 +28,6 @@
         overflow: hidden;
       }
 
-      history-toolbar {
-        background: var(--md-toolbar-color);
-      }
-
       /* Sizing this with flex causes slow load performance, see
        * crbug.com/618153. TODO(dbeam): is this still an issue? */
       #main-container {
diff --git a/chrome/browser/resources/history/history.html b/chrome/browser/resources/history/history.html
index ae99c88..18214b51 100644
--- a/chrome/browser/resources/history/history.html
+++ b/chrome/browser/resources/history/history.html
@@ -55,8 +55,10 @@
     #loading-toolbar {
       align-items: center;
       background: var(--md-toolbar-color);
+      border-bottom: var(--md-toolbar-border);
+      box-sizing: border-box;
       color: #fff;
-      height: 56px;
+      height: var(--md-toolbar-height);
       letter-spacing: .25px;
       padding-inline-start: 24px;
     }
diff --git a/chrome/browser/resources/management/management.html b/chrome/browser/resources/management/management.html
index bec6e5cb..b682e7d 100644
--- a/chrome/browser/resources/management/management.html
+++ b/chrome/browser/resources/management/management.html
@@ -10,14 +10,18 @@
   <link rel="import" href="chrome://resources/html/cr.html">
   <style>
     html {
-      --toolbar-height: 56px;
       background: var(--md-background-color);
       height: 100%;
       overflow: hidden;
     }
 
-    html.loading {
-      border-top: var(--toolbar-height) solid var(--md-toolbar-color);
+    html.loading::before {
+      background-color: var(--md-toolbar-color);
+      border-bottom: var(--md-toolbar-border);
+      box-sizing: border-box;
+      content: '';
+      display: block;
+      height: var(--md-toolbar-height);
     }
 
     body {
diff --git a/chrome/browser/resources/management/management_ui.html b/chrome/browser/resources/management/management_ui.html
index f80437b..3403e31d 100644
--- a/chrome/browser/resources/management/management_ui.html
+++ b/chrome/browser/resources/management/management_ui.html
@@ -26,7 +26,6 @@
       }
 
       cr-toolbar {
-        background-color: var(--md-toolbar-color);
         flex-shrink: 0;
       }
 
diff --git a/chrome/browser/resources/md_extensions/extensions.html b/chrome/browser/resources/md_extensions/extensions.html
index 42461d4e4..088cee5c 100644
--- a/chrome/browser/resources/md_extensions/extensions.html
+++ b/chrome/browser/resources/md_extensions/extensions.html
@@ -24,7 +24,7 @@
 
     html.loading::before {
       background: var(--md-toolbar-color);
-      height: 56px;
+      height: var(--md-toolbar-height);
     }
 
     /* Mimics the developer mode toolbar until the real one loads. Note:
@@ -39,9 +39,9 @@
       background: none;
     }
 
-    html[dark].loading.in-dev-mode::before,
+    html[dark].loading::before,
     html[dark].loading.in-dev-mode body::before {
-      border-bottom: 1px solid rgba(255, 255, 255, .1);
+      border-bottom: var(--md-toolbar-border);
     }
 
     html,
diff --git a/chrome/browser/resources/md_extensions/toolbar.html b/chrome/browser/resources/md_extensions/toolbar.html
index 5e3eec9f..6f3b663 100644
--- a/chrome/browser/resources/md_extensions/toolbar.html
+++ b/chrome/browser/resources/md_extensions/toolbar.html
@@ -27,17 +27,6 @@
         --padding-top-bottom: 10px;
       }
 
-      cr-toolbar {
-        background: var(--md-toolbar-color);
-        border-bottom: var(--border-bottom-height) solid transparent;
-        box-sizing: border-box;
-        transition: border-bottom-color var(--drawer-transition);
-      }
-
-      :host-context([dark]):host([in-dev-mode]) cr-toolbar {
-        border-bottom-color: var(--cr-separator-color);
-      }
-
       /* This toggle needs special styling because it's on blue background. */
       :host-context(html:not([dark])) cr-toolbar cr-toggle {
         --cr-toggle-checked-bar-color: var(--google-grey-refresh-100);
diff --git a/chrome/browser/resources/ntp4/guest_tab.html b/chrome/browser/resources/ntp4/guest_tab.html
index a89226c..1807bfc1 100644
--- a/chrome/browser/resources/ntp4/guest_tab.html
+++ b/chrome/browser/resources/ntp4/guest_tab.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html dir="$i18n{textdirection}" lang="$i18n{language}">
+<html dir="$i18n{textdirection}" lang="$i18n{language}" $i18n{dark}>
 <head>
 <meta charset="utf-8">
 <title>$i18n{title}</title>
diff --git a/chrome/browser/resources/ntp4/incognito_and_guest_tab.css b/chrome/browser/resources/ntp4/incognito_and_guest_tab.css
index ef6f279..d6d9d77 100644
--- a/chrome/browser/resources/ntp4/incognito_and_guest_tab.css
+++ b/chrome/browser/resources/ntp4/incognito_and_guest_tab.css
@@ -9,6 +9,11 @@
   font-size: 85%;
 }
 
+[dark] {
+  background: rgb(50, 54, 57);
+  color: rgb(232, 234, 237);  /* --google-grey-200 */
+}
+
 h1 {
   font-size: 200%;
   font-weight: 400;
@@ -29,8 +34,6 @@
   text-decoration: underline;
 }
 
-/* 'Learn More' button styled like a Material Design text button.
- * TODO(edwardjung): Switch styled links to actual text buttons. */
 .learn-more-button {
   color: rgb(66, 133, 244);
   display: inline-block;
@@ -39,7 +42,10 @@
   margin-top: 1.98em;
   padding: 10.5px 12px;
   text-decoration: none;
-  text-transform: uppercase;
+}
+
+[dark] :-webkit-any(a, .learn-more-button) {
+  color: rgb(138, 180, 248);  /* --google-blue-refresh-300 */
 }
 
 .content {
diff --git a/chrome/browser/resources/print_preview/data/destination.js b/chrome/browser/resources/print_preview/data/destination.js
index e9893ba..be818a8 100644
--- a/chrome/browser/resources/print_preview/data/destination.js
+++ b/chrome/browser/resources/print_preview/data/destination.js
@@ -4,6 +4,19 @@
 
 cr.exportPath('print_preview');
 
+/** @enum {number} */
+print_preview.DestinationState = {
+  INIT: 0,
+  SELECTED: 1,
+  SET: 2,
+  UPDATED: 3,
+  INVALID: 4,
+  UNSUPPORTED: 5,
+  // <if expr="chromeos">
+  NO_DESTINATIONS: 6,
+  // </if>
+};
+
 /**
  * Enumeration of the types of destinations.
  * @enum {string}
diff --git a/chrome/browser/resources/print_preview/data/destination_store.js b/chrome/browser/resources/print_preview/data/destination_store.js
index b71dfafb..b4aebff 100644
--- a/chrome/browser/resources/print_preview/data/destination_store.js
+++ b/chrome/browser/resources/print_preview/data/destination_store.js
@@ -14,6 +14,18 @@
   DONE: 'done'
 };
 
+/**
+ * Enumeration of possible destination errors.
+ * @enum {number}
+ */
+print_preview.DestinationErrorType = {
+  INVALID: 0,
+  UNSUPPORTED: 1,
+  // <if expr="chromeos">
+  NO_DESTINATIONS: 2,
+  // </if>
+};
+
 cr.define('print_preview', function() {
   'use strict';
   /**
@@ -1042,15 +1054,19 @@
 
     /**
      * Sends SELECTED_DESTINATION_CAPABILITIES_READY event if the destination
-     * is supported, or SELECTED_DESTINATION_UNSUPPORTED otherwise.
+     * is supported, or ERROR otherwise of with error type UNSUPPORTED.
      * @private
      */
     sendSelectedDestinationUpdateEvent_() {
-      this.dispatchEvent(new CustomEvent(
-          this.selectedDestination_.shouldShowInvalidCertificateError ?
-              DestinationStore.EventType.SELECTED_DESTINATION_UNSUPPORTED :
-              DestinationStore.EventType
-                  .SELECTED_DESTINATION_CAPABILITIES_READY));
+      if (this.selectedDestination_.shouldShowInvalidCertificateError) {
+        this.dispatchEvent(new CustomEvent(
+            DestinationStore.EventType.ERROR,
+            {detail: print_preview.DestinationErrorType.UNSUPPORTED}));
+      } else {
+        this.dispatchEvent(
+            new CustomEvent(DestinationStore.EventType
+                                .SELECTED_DESTINATION_CAPABILITIES_READY));
+      }
     }
 
     /**
@@ -1243,7 +1259,8 @@
       if (this.selectedDestination_ &&
           this.selectedDestination_.id == destinationId) {
         this.dispatchEvent(new CustomEvent(
-            DestinationStore.EventType.SELECTED_DESTINATION_INVALID));
+            DestinationStore.EventType.ERROR,
+            {detail: print_preview.DestinationErrorType.INVALID}));
       }
       if (this.autoSelectMatchingDestination_ &&
           this.autoSelectMatchingDestination_.matchIdAndOrigin(
@@ -1282,7 +1299,7 @@
 
     /**
      * Checks if the search is done and no printers are found. If so, fires a
-     * DestinationStore.EventType.NO_DESTINATIONS_FOUND event.
+     * DestinationStore.EventType.ERROR event with error type NO_DESTINATIONS.
      * @private
      */
     sendNoPrinterEventIfNeeded_() {
@@ -1296,10 +1313,12 @@
           !this.selectFirstDestination_) {
         return;
       }
-
+      // <if expr="chromeos">
       this.selectFirstDestination_ = false;
-      this.dispatchEvent(
-          new CustomEvent(DestinationStore.EventType.NO_DESTINATIONS_FOUND));
+      this.dispatchEvent(new CustomEvent(
+          DestinationStore.EventType.ERROR,
+          {detail: print_preview.DestinationErrorType.NO_DESTINATIONS}));
+      // </if>
     }
 
     /**
@@ -1398,14 +1417,9 @@
     DESTINATIONS_INSERTED:
         'print_preview.DestinationStore.DESTINATIONS_INSERTED',
     DESTINATIONS_RESET: 'print_preview.DestinationStore.DESTINATIONS_RESET',
-    NO_DESTINATIONS_FOUND:
-        'print_preview.DestinationStore.NO_DESTINATIONS_FOUND',
+    ERROR: 'print_preview.DestinationStore.ERROR',
     SELECTED_DESTINATION_CAPABILITIES_READY: 'print_preview.DestinationStore' +
         '.SELECTED_DESTINATION_CAPABILITIES_READY',
-    SELECTED_DESTINATION_INVALID:
-        'print_preview.DestinationStore.SELECTED_DESTINATION_INVALID',
-    SELECTED_DESTINATION_UNSUPPORTED:
-        'print_preview.DestinationStore.SELECTED_DESTINATION_UNSUPPORTED',
   };
 
   /**
diff --git a/chrome/browser/resources/print_preview/data/user_info.js b/chrome/browser/resources/print_preview/data/user_info.js
index 14d9d8cf..9f454f53 100644
--- a/chrome/browser/resources/print_preview/data/user_info.js
+++ b/chrome/browser/resources/print_preview/data/user_info.js
@@ -34,12 +34,6 @@
       value: '',
     },
 
-    /** @type {?cloudprint.CloudPrintInterface} */
-    cloudPrintInterface: {
-      type: Object,
-      observer: 'onCloudPrintInterfaceSet_',
-    },
-
     /** @type {?print_preview.DestinationStore} */
     destinationStore: Object,
 
@@ -59,14 +53,10 @@
   /** @private {!EventTracker} */
   tracker_: new EventTracker(),
 
-  /** @private */
-  onCloudPrintInterfaceSet_: function() {
-    if (!this.cloudPrintInterface) {
-      return;
-    }
-
+  /** @param {!cloudprint.CloudPrintInterface} cloudPrintInterface */
+  setCloudPrintInterface: function(cloudPrintInterface) {
     this.tracker_.add(
-        assert(this.cloudPrintInterface).getEventTarget(),
+        cloudPrintInterface.getEventTarget(),
         cloudprint.CloudPrintInterfaceEventType.UPDATE_USERS,
         this.updateUsers_.bind(this));
   },
diff --git a/chrome/browser/resources/print_preview/new/BUILD.gn b/chrome/browser/resources/print_preview/new/BUILD.gn
index 249d328..56c953d3 100644
--- a/chrome/browser/resources/print_preview/new/BUILD.gn
+++ b/chrome/browser/resources/print_preview/new/BUILD.gn
@@ -68,11 +68,8 @@
     "..:metrics",
     "..:native_layer",
     "../data:destination",
-    "../data:destination_store",
     "../data:document_info",
-    "../data:invitation_store",
     "../data:measurement_system",
-    "../data:user_info",
     "//ui/webui/resources/cr_elements:cr_container_shadow_behavior",
     "//ui/webui/resources/js:event_tracker",
     "//ui/webui/resources/js:util",
@@ -96,13 +93,15 @@
   deps = [
     ":destination_dialog",
     ":destination_select",
-    ":state",
+    ":settings_behavior",
+    "..:cloud_print_interface",
     "../data:destination",
     "../data:destination_store",
     "../data:invitation_store",
     "../data:user_info",
     "//ui/webui/resources/cr_elements/cr_lazy_render:cr_lazy_render",
     "//ui/webui/resources/js:i18n_behavior",
+    "//ui/webui/resources/js:web_ui_listener_behavior",
   ]
 }
 
diff --git a/chrome/browser/resources/print_preview/new/app.html b/chrome/browser/resources/print_preview/new/app.html
index 9a705ce..63987328 100644
--- a/chrome/browser/resources/print_preview/new/app.html
+++ b/chrome/browser/resources/print_preview/new/app.html
@@ -14,11 +14,8 @@
 <link rel="import" href="../metrics.html">
 <link rel="import" href="../native_layer.html">
 <link rel="import" href="../data/destination.html">
-<link rel="import" href="../data/destination_store.html">
-<link rel="import" href="../data/invitation_store.html">
 <link rel="import" href="../data/document_info.html">
 <link rel="import" href="../data/measurement_system.html">
-<link rel="import" href="../data/user_info.html">
 <link rel="import" href="print_preview_shared_css.html">
 <link rel="import" href="strings.html">
 <link rel="import" href="settings_behavior.html">
@@ -81,17 +78,11 @@
     </style>
     <print-preview-state id="state" state="{{state}}"></print-preview-state>
     <print-preview-model id="model" settings="{{settings}}"
-        controls-managed="{{controlsManaged_}}" destination="{{destination_}}"
+        controls-managed="{{controlsManaged_}}" destination="[[destination_]]"
         document-settings="[[documentSettings_]]"
         margins="[[margins_]]" page-size="[[pageSize_]]"
-        recent-destinations="{{recentDestinations_}}"
         on-save-sticky-settings="onSaveStickySettings_">
     </print-preview-model>
-    <print-preview-user-info id="userInfo" active-user="{{activeUser_}}"
-        users="{{users_}}" cloud-print-interface="[[cloudPrintInterface_]]"
-        destination-store="[[destinationStore_]]"
-        invitation-store="[[invitationStore_]]">
-    </print-preview-user-info>
     <print-preview-document-info id="documentInfo"
         document-settings="{{documentSettings_}}" margins="{{margins_}}"
         page-size="{{pageSize_}}">
@@ -104,17 +95,11 @@
       </print-preview-header>
       <div id="container">
         <print-preview-destination-settings id="destinationSettings"
-            cloud-print-state="[[cloudPrintState_]]"
-            destination="[[destination_]]"
-            destination-store="[[destinationStore_]]"
-            invitation-store="[[invitationStore_]]"
+            destination="{{destination_}}" settings="{{settings}}"
+            destination-state="{{destinationState_}}"
             app-kiosk-mode="[[isInAppKioskMode_]]"
-            cloud-print-state="[[cloudPrintState_]]"
-            disabled="[[controlsDisabled_]]" state="[[state]]"
-            recent-destinations="[[recentDestinations_]]"
-            active-user="[[activeUser_]]" users="[[users_]]"
-            available class="settings-section"
-            on-account-change="onAccountChange_">
+            disabled="[[controlsDisabled_]]"
+            available class="settings-section">
         </print-preview-destination-settings>
         <print-preview-pages-settings settings="{{settings}}"
             page-count="[[documentSettings_.pageCount]]"
diff --git a/chrome/browser/resources/print_preview/new/app.js b/chrome/browser/resources/print_preview/new/app.js
index cc3f07e..d6f4d98b 100644
--- a/chrome/browser/resources/print_preview/new/app.js
+++ b/chrome/browser/resources/print_preview/new/app.js
@@ -26,10 +26,7 @@
      * controls.
      * @type {!Object}
      */
-    settings: {
-      type: Object,
-      notify: true,
-    },
+    settings: Object,
 
     /** @type {!print_preview_new.State} */
     state: {
@@ -37,22 +34,9 @@
       observer: 'onStateChanged_',
     },
 
-    /** @private {string} */
-    activeUser_: {
-      type: String,
-      observer: 'onActiveUserChanged_',
-    },
-
-    /** @private {!print_preview.CloudPrintState} */
-    cloudPrintState_: {
-      type: Number,
-      value: print_preview.CloudPrintState.DISABLED,
-    },
-
     /** @private {boolean} */
     controlsDisabled_: {
       type: Boolean,
-      notify: true,
       computed: 'computeControlsDisabled_(state)',
     },
 
@@ -60,17 +44,12 @@
     controlsManaged_: Boolean,
 
     /** @private {print_preview.Destination} */
-    destination_: {
-      type: Object,
-      notify: true,
-      value: null,
-    },
+    destination_: Object,
 
-    /** @private {?print_preview.DestinationStore} */
-    destinationStore_: {
-      type: Object,
-      notify: true,
-      value: null,
+    /** @private {!print_preview.DestinationState} */
+    destinationState_: {
+      type: Number,
+      observer: 'onDestinationStateChange_',
     },
 
     /** @private {print_preview.DocumentSettings} */
@@ -88,28 +67,18 @@
     /** @private {string} */
     errorMessage_: {
       type: String,
-      notify: true,
       value: '',
     },
 
-    /** @private {?print_preview.InvitationStore} */
-    invitationStore_: {
-      type: Object,
-      notify: true,
-      value: null,
-    },
-
     /** @private {boolean} */
     isInAppKioskMode_: {
       type: Boolean,
-      notify: true,
       value: false,
     },
 
     /** @private {?print_preview.MeasurementSystem} */
     measurementSystem_: {
       type: Object,
-      notify: true,
       value: null,
     },
 
@@ -119,23 +88,15 @@
       observer: 'onPreviewAreaStateChanged_',
     },
 
-    /** @private {!Array<print_preview.RecentDestination>} */
-    recentDestinations_: {
-      type: Array,
-      notify: true,
-    },
-
     /** @private {boolean} */
     settingsExpandedByUser_: {
       type: Boolean,
-      notify: true,
       value: false,
     },
 
     /** @private {boolean} */
     shouldShowMoreSettings_: {
       type: Boolean,
-      notify: true,
       computed: 'computeShouldShowMoreSettings_(settings.pages.available, ' +
           'settings.copies.available, settings.layout.available, ' +
           'settings.color.available, settings.mediaSize.available, ' +
@@ -143,9 +104,6 @@
           'settings.pagesPerSheet.available, settings.scaling.available, ' +
           'settings.otherOptions.available, settings.vendorItems.available)',
     },
-
-    /** @private {!Array<string>} */
-    users_: Array,
   },
 
   listeners: {
@@ -166,6 +124,9 @@
   cancelled_: false,
 
   /** @private {boolean} */
+  printRequested_: false,
+
+  /** @private {boolean} */
   showSystemDialogBeforePrint_: false,
 
   /** @private {boolean} */
@@ -190,35 +151,8 @@
     this.addWebUIListener('print-failed', this.onPrintFailed_.bind(this));
     this.addWebUIListener(
         'print-preset-options', this.onPrintPresetOptions_.bind(this));
-    this.destinationStore_ =
-        new print_preview.DestinationStore(this.addWebUIListener.bind(this));
-    this.invitationStore_ = new print_preview.InvitationStore();
     this.tracker_.add(window, 'keydown', this.onKeyDown_.bind(this));
     this.$.previewArea.setPluginKeyEventCallback(this.onKeyDown_.bind(this));
-    this.tracker_.add(
-        this.destinationStore_,
-        print_preview.DestinationStore.EventType.DESTINATION_SELECT,
-        this.onDestinationSelect_.bind(this));
-    // <if expr="chromeos">
-    this.tracker_.add(
-        this.destinationStore_,
-        print_preview.DestinationStore.EventType.NO_DESTINATIONS_FOUND,
-        this.onNoDestinationsFound_.bind(this));
-    // </if>
-    this.tracker_.add(
-        this.destinationStore_,
-        print_preview.DestinationStore.EventType
-            .SELECTED_DESTINATION_CAPABILITIES_READY,
-        this.onDestinationUpdated_.bind(this));
-    this.tracker_.add(
-        this.destinationStore_,
-        print_preview.DestinationStore.EventType
-            .SELECTED_DESTINATION_UNSUPPORTED,
-        this.onInvalidPrinter_.bind(this));
-    this.tracker_.add(
-        this.destinationStore_,
-        print_preview.DestinationStore.EventType.SELECTED_DESTINATION_INVALID,
-        this.onInvalidPrinter_.bind(this));
     this.nativeLayer_.getInitialSettings().then(
         this.onInitialSettingsSet_.bind(this));
   },
@@ -352,11 +286,10 @@
         settings.thousandsDelimeter, settings.decimalDelimeter,
         settings.unitType);
     this.setSetting('selectionOnly', settings.shouldPrintSelectionOnly);
-    this.destinationStore_.init(
-        settings.isInAppKioskMode, settings.printerName,
-        settings.serializedDefaultDestinationSelectionRulesStr,
-        this.recentDestinations_);
     this.isInAppKioskMode_ = settings.isInAppKioskMode;
+    this.$.destinationSettings.initDestinationStore(
+        settings.printerName,
+        settings.serializedDefaultDestinationSelectionRulesStr);
     this.isInKioskAutoPrintMode_ = settings.isInKioskAutoPrintMode;
 
     // This is only visible in the task manager.
@@ -385,59 +318,58 @@
         assert(this.cloudPrintInterface_).getEventTarget(),
         cloudprint.CloudPrintInterfaceEventType.SUBMIT_DONE,
         this.close_.bind(this));
-
-    [cloudprint.CloudPrintInterfaceEventType.SEARCH_FAILED,
-     cloudprint.CloudPrintInterfaceEventType.PRINTER_FAILED,
-    ].forEach(eventType => {
-      this.tracker_.add(
-          assert(this.cloudPrintInterface_).getEventTarget(), eventType,
-          this.checkCloudPrintStatus_.bind(this));
-    });
     this.tracker_.add(
         assert(this.cloudPrintInterface_).getEventTarget(),
         cloudprint.CloudPrintInterfaceEventType.SUBMIT_FAILED,
         this.onCloudPrintError_.bind(this));
-
-    this.destinationStore_.setCloudPrintInterface(this.cloudPrintInterface_);
-    this.invitationStore_.setCloudPrintInterface(this.cloudPrintInterface_);
-    assert(this.cloudPrintState_ === print_preview.CloudPrintState.DISABLED);
-    this.cloudPrintState_ = print_preview.CloudPrintState.ENABLED;
+    this.$.destinationSettings.setCloudPrintInterface(
+        this.cloudPrintInterface_);
   },
 
   /** @private */
-  onDestinationSelect_: function() {
-    // If the plugin does not exist do not attempt to load the preview.
-    if (this.state == print_preview_new.State.FATAL_ERROR) {
-      return;
-    }
+  onDestinationStateChange_: function(e) {
+    switch (this.destinationState_) {
+      case print_preview.DestinationState.SELECTED:
+        // If the plugin does not exist do not attempt to load the preview.
+        if (this.state !== print_preview_new.State.FATAL_ERROR) {
+          this.$.state.transitTo(print_preview_new.State.NOT_READY);
+        }
+        break;
+      case print_preview.DestinationState.UPDATED:
+        if (!this.$.model.initialized()) {
+          this.$.model.applyStickySettings();
+        }
 
-    this.$.state.transitTo(print_preview_new.State.NOT_READY);
-    this.destination_ = this.destinationStore_.selectedDestination;
-  },
+        // <if expr="chromeos">
+        this.$.model.applyDestinationSpecificPolicies();
+        // </if>
 
-  /** @private */
-  onDestinationUpdated_: function() {
-    // Notify observers, since destination_ ==
-    // destinationStore_.selectedDestination and this event indicates
-    // destinationStore_.selectedDestination.capabilities has been updated.
-    this.notifyPath('destination_.capabilities');
-
-    if (!this.$.model.initialized()) {
-      this.$.model.applyStickySettings();
-    }
-
-    // <if expr="chromeos">
-    if (this.destination_) {
-      this.$.model.applyDestinationSpecificPolicies();
-    }
-    // </if>
-
-    if (this.state == print_preview_new.State.NOT_READY ||
-        this.state == print_preview_new.State.INVALID_PRINTER) {
-      this.$.state.transitTo(print_preview_new.State.READY);
-      if (this.isInKioskAutoPrintMode_) {
-        this.onPrintRequested_();
-      }
+        if (this.state == print_preview_new.State.NOT_READY ||
+            this.state == print_preview_new.State.INVALID_PRINTER) {
+          this.$.state.transitTo(print_preview_new.State.READY);
+          if (this.isInKioskAutoPrintMode_ || this.printRequested_) {
+            this.onPrintRequested_();
+            // Reset in case printing fails.
+            this.printRequested_ = false;
+          }
+        }
+        break;
+      case print_preview.DestinationState.INVALID:
+        this.previewState_ =
+            print_preview_new.PreviewAreaState.INVALID_SETTINGS;
+        break;
+      case print_preview.DestinationState.UNSUPPORTED:
+        this.previewState_ =
+            print_preview_new.PreviewAreaState.UNSUPPORTED_CLOUD_PRINTER;
+        break;
+      // <if expr="chromeos">
+      case print_preview.DestinationState.NO_DESTINATIONS:
+        this.$.state.transitTo(print_preview_new.State.INVALID_PRINTER);
+        this.$.previewArea.setNoDestinationsFound();
+        break;
+      // </if>
+      default:
+        break;
     }
   },
 
@@ -471,7 +403,7 @@
                 print_preview.Metrics.PrintSettingsUiBucket
                     .PRINT_WITH_SETTINGS_COLLAPSED);
       }
-      const destination = assert(this.destinationStore_.selectedDestination);
+      const destination = assert(this.destination_);
       const whenPrintDone =
           this.nativeLayer_.print(this.$.model.createPrintTicket(
               destination, this.openPdfInPreview_,
@@ -494,6 +426,10 @@
 
   /** @private */
   onPrintRequested_: function() {
+    if (this.state === print_preview_new.State.NOT_READY) {
+      this.printRequested_ = true;
+      return;
+    }
     this.$.state.transitTo(
         this.$.previewArea.previewLoaded() ? print_preview_new.State.PRINTING :
                                              print_preview_new.State.HIDDEN);
@@ -529,7 +465,7 @@
   onPrintToCloud_: function(data) {
     assert(
         this.cloudPrintInterface_ != null, 'Google Cloud Print is not enabled');
-    const destination = assert(this.destinationStore_.selectedDestination);
+    const destination = assert(this.destination_);
     this.cloudPrintInterface_.submit(
         destination, this.$.model.createCloudJobTicket(destination),
         this.documentSettings_.title, data);
@@ -571,17 +507,6 @@
   },
 
   /** @private */
-  onInvalidPrinter_: function() {
-    this.previewState_ =
-        print_preview_new.PreviewAreaState.UNSUPPORTED_CLOUD_PRINTER;
-  },
-
-  /** @private */
-  onInvalidPrinterCapabilities_: function() {
-    this.previewState_ = print_preview_new.PreviewAreaState.INVALID_SETTINGS;
-  },
-
-  /** @private */
   onPreviewAreaStateChanged_: function() {
     switch (this.previewState_) {
       case print_preview_new.PreviewAreaState.PREVIEW_FAILED:
@@ -606,25 +531,6 @@
   },
 
   /**
-   * Updates the cloud print status to NOT_SIGNED_IN if there is an
-   * authentication error.
-   * @param {!CustomEvent<!cloudprint.CloudPrintInterfaceErrorEventDetail>}
-   *     event Contains the error status
-   * @private
-   */
-  checkCloudPrintStatus_: function(event) {
-    if (event.detail.status != 403 || this.isInAppKioskMode_) {
-      return;
-    }
-
-    // Should not have sent a message to Cloud Print if cloud print is
-    // disabled.
-    assert(this.cloudPrintState_ !== print_preview.CloudPrintState.DISABLED);
-    this.cloudPrintState_ = print_preview.CloudPrintState.NOT_SIGNED_IN;
-    console.warn('Google Cloud Print Error: HTTP status 403');
-  },
-
-  /**
    * Called when there was an error communicating with Google Cloud print.
    * Displays an error message in the print header.
    * @param {!CustomEvent<!cloudprint.CloudPrintInterfaceErrorEventDetail>}
@@ -632,10 +538,9 @@
    * @private
    */
   onCloudPrintError_: function(event) {
-    this.checkCloudPrintStatus_(event);
     if (event.detail.status == 0 ||
         (event.detail.status == 403 && !this.isInAppKioskMode_)) {
-      return;  // No internet connectivity or handled by checkCloudPrintStatus_.
+      return;  // No internet connectivity or not signed in.
     }
     this.errorMessage_ = event.detail.message;
     this.$.state.transitTo(print_preview_new.State.FATAL_ERROR);
@@ -712,37 +617,9 @@
     this.$.documentInfo.inFlightRequestId = e.detail;
   },
 
-  // <if expr="chromeos">
-  /** @private */
-  onNoDestinationsFound_: function() {
-    this.$.state.transitTo(print_preview_new.State.INVALID_PRINTER);
-    this.$.previewArea.setNoDestinationsFound();
-    this.$.destinationSettings.noDestinationsFound = true;
-  },
-  // </if>
-
   /** @private */
   close_: function() {
     this.$.state.transitTo(print_preview_new.State.CLOSING);
   },
-
-  /**
-   * @param {!CustomEvent<string>} e Event containing the new active user
-   *     account.
-   * @private
-   */
-  onAccountChange_: function(e) {
-    this.$.userInfo.updateActiveUser(e.detail);
-  },
-
-  /** @private */
-  onActiveUserChanged_: function() {
-    if (!this.activeUser_) {
-      return;
-    }
-
-    assert(this.cloudPrintState_ !== print_preview.CloudPrintState.DISABLED);
-    this.cloudPrintState_ = print_preview.CloudPrintState.SIGNED_IN;
-  },
 });
 })();
diff --git a/chrome/browser/resources/print_preview/new/destination_dialog.js b/chrome/browser/resources/print_preview/new/destination_dialog.js
index 2aae2bd2..db2ba5f 100644
--- a/chrome/browser/resources/print_preview/new/destination_dialog.js
+++ b/chrome/browser/resources/print_preview/new/destination_dialog.js
@@ -177,7 +177,7 @@
                         .DESTINATION_CLOSED_UNCHANGED :
                     print_preview.Metrics.DestinationSearchBucket
                         .DESTINATION_CLOSED_CHANGED);
-    if (cancelled && this.currentDestinationAccount &&
+    if (this.currentDestinationAccount &&
         this.currentDestinationAccount !== this.activeUser) {
       this.fire('account-change', this.currentDestinationAccount);
     }
diff --git a/chrome/browser/resources/print_preview/new/destination_select.html b/chrome/browser/resources/print_preview/new/destination_select.html
index 84fc622..a50baa6 100644
--- a/chrome/browser/resources/print_preview/new/destination_select.html
+++ b/chrome/browser/resources/print_preview/new/destination_select.html
@@ -37,7 +37,7 @@
     </style>
     <select class="md-select" aria-label$="[[i18n(destinationLabel)]]"
         style="background-image:
-            [[getIconImage_(destination.icon, noDestinationsFound)]],
+            [[getIconImage_(destination.icon, destinationState)]],
             url(chrome://resources/images/arrow_down.svg);"
         disabled$="[[disabled]]"
         value="{{selectedValue::change}}">
@@ -51,10 +51,13 @@
           hidden$="[[!showGoogleDrive_]]">
         $i18n{printToGoogleDrive}
       </option>
-      <option value="noDestinations" hidden$="[[!noDestinationsFound]]"
-          selected$="[[noDestinationsFound]]">
+<if expr="chromeos">
+      <option value="noDestinations"
+          hidden$="[[!showNoDestinations_(destinationState)]]"
+          selected$="[[showNoDestinations_(destinationState)]]">
         $i18n{noDestinationsMessage}
       </option>
+</if>
       <option value="seeMore" aria-label$="[[i18n(seeMoreDestinationsLabel)]]">
         $i18n{seeMore}
       </option>
diff --git a/chrome/browser/resources/print_preview/new/destination_select.js b/chrome/browser/resources/print_preview/new/destination_select.js
index 5e02797e..8b81491 100644
--- a/chrome/browser/resources/print_preview/new/destination_select.js
+++ b/chrome/browser/resources/print_preview/new/destination_select.js
@@ -18,9 +18,10 @@
     /** @type {!print_preview.Destination} */
     destination: Object,
 
-    disabled: Boolean,
+    /** @type {!print_preview.DestinationState} */
+    destinationState: Number,
 
-    noDestinationsFound: Boolean,
+    disabled: Boolean,
 
     /** @type {!Array<!print_preview.Destination>} */
     recentDestinationList: Array,
@@ -81,8 +82,14 @@
       return '';
     }
 
-    const iconSetAndIcon =
-        this.noDestinationsFound ? ['cr', 'error'] : icon.split(':');
+    let iconSetAndIcon = null;
+    // <if expr="chromeos">
+    if (this.destinationState ===
+        print_preview.DestinationState.NO_DESTINATIONS) {
+      iconSetAndIcon = ['cr', 'error'];
+    }
+    // </if>
+    iconSetAndIcon = iconSetAndIcon || icon.split(':');
     const iconset = /** @type {Polymer.IronIconsetSvg} */ (
         this.meta_.byKey(iconSetAndIcon[0]));
     const serializer = new XMLSerializer();
@@ -97,4 +104,12 @@
   onProcessSelectChange: function(value) {
     this.fire('selected-option-change', value);
   },
+
+  // <if expr="chromeos">
+  /** @private */
+  showNoDestinations_: function() {
+    return this.destinationState ===
+        print_preview.DestinationState.NO_DESTINATIONS;
+  },
+  // </if>
 });
diff --git a/chrome/browser/resources/print_preview/new/destination_settings.html b/chrome/browser/resources/print_preview/new/destination_settings.html
index 9e1553a..a1133fb 100644
--- a/chrome/browser/resources/print_preview/new/destination_settings.html
+++ b/chrome/browser/resources/print_preview/new/destination_settings.html
@@ -5,6 +5,8 @@
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/event_tracker.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
+<link rel="import" href="../cloud_print_interface.html">
 <link rel="import" href="../data/destination.html">
 <link rel="import" href="../data/destination_store.html">
 <link rel="import" href="../data/invitation_store.html">
@@ -13,8 +15,8 @@
 <link rel="import" href="destination_select.html">
 <link rel="import" href="print_preview_shared_css.html">
 <link rel="import" href="throbber_css.html">
+<link rel="import" href="settings_behavior.html">
 <link rel="import" href="settings_section.html">
-<link rel="import" href="state.html">
 <link rel="import" href="strings.html">
 
 <dom-module id="print-preview-destination-settings">
@@ -45,6 +47,10 @@
         min-height: 0;
       }
     </style>
+    <print-preview-user-info id="userInfo" active-user="{{activeUser_}}"
+        users="{{users_}}" destination-store="[[destinationStore_]]"
+        invitation-store="[[invitationStore_]]">
+    </print-preview-user-info>
     <print-preview-settings-section>
       <span slot="title">$i18n{destinationLabel}</span>
       <div slot="controls">
@@ -53,13 +59,12 @@
         </div>
         <print-preview-destination-select id="destinationSelect"
             hidden$="[[!shouldHideSpinner_]]"
-            active-user="[[activeUser]]"
+            active-user="[[activeUser_]]"
             app-kiosk-mode="[[appKioskMode]]"
-            cloud-print-state="[[cloudPrintState]]"
+            cloud-print-state="[[cloudPrintState_]]"
             destination="[[destination]]"
-            disabled="[[shouldDisableDropdown_(destinationStore, disabled,
-                                               shouldHideSpinner_, state)]]"
-            no-destinations-found="[[noDestinationsFound]]"
+            destination-state="[[destinationState]]"
+            disabled="[[shouldDisableDropdown_(destinationState, disabled)]]"
             recent-destination-list="[[recentDestinationList_]]"
             on-selected-option-change="onSelectedDestinationOptionChange_">
         </print-preview-destination-select>
@@ -75,13 +80,13 @@
     <cr-lazy-render id="destinationDialog">
       <template>
         <print-preview-destination-dialog
-            cloud-print-state="[[cloudPrintState]]"
-            destination-store="[[destinationStore]]"
-            invitation-store="[[invitationStore]]"
+            cloud-print-state="[[cloudPrintState_]]"
+            destination-store="[[destinationStore_]]"
+            invitation-store="[[invitationStore_]]"
             recent-destination-list="[[recentDestinationList_]]"
-            active-user="[[activeUser]]" users="[[users]]"
+            active-user="[[activeUser_]]" users="[[users_]]"
             current-destination-account="[[destination.account]]"
-            on-close="onDialogClose_">
+            on-account-change="onAccountChange_" on-close="onDialogClose_">
         </print-preview-destination-dialog>
       </template>
     </cr-lazy-render>
diff --git a/chrome/browser/resources/print_preview/new/destination_settings.js b/chrome/browser/resources/print_preview/new/destination_settings.js
index 195bb8e..4a415a68 100644
--- a/chrome/browser/resources/print_preview/new/destination_settings.js
+++ b/chrome/browser/resources/print_preview/new/destination_settings.js
@@ -2,52 +2,64 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+(function() {
+'use strict';
+
+/** @type {number} Number of recent destinations to save. */
+const NUM_PERSISTED_DESTINATIONS = 3;
+
 Polymer({
   is: 'print-preview-destination-settings',
 
-  behaviors: [I18nBehavior],
+  behaviors: [
+    I18nBehavior,
+    SettingsBehavior,
+    WebUIListenerBehavior,
+  ],
 
   properties: {
-    activeUser: String,
-
     appKioskMode: Boolean,
 
-    /** @type {!print_preview.CloudPrintState} */
-    cloudPrintState: {
-      type: Number,
-      observer: 'onCloudPrintStateChanged_',
-    },
-
-    /** @type {!print_preview.Destination} */
+    /** @type {?print_preview.Destination} */
     destination: {
       type: Object,
-      observer: 'onDestinationSet_',
+      notify: true,
+      value: null,
     },
 
-    /** @type {?print_preview.DestinationStore} */
-    destinationStore: {
-      type: Object,
-      observer: 'onDestinationStoreSet_',
+    /** @type {!print_preview.DestinationState} */
+    destinationState: {
+      type: Number,
+      notify: true,
+      value: print_preview.DestinationState.INIT,
+      observer: 'updateDestinationSelect_',
     },
 
     disabled: Boolean,
 
-    /** @type {?print_preview.InvitationStore} */
-    invitationStore: Object,
-
-    noDestinationsFound: {
-      type: Boolean,
-      value: false,
+    /** @private {string} */
+    activeUser_: {
+      type: String,
+      observer: 'onActiveUserChanged_',
     },
 
-    /** @type {!Array<!print_preview.RecentDestination>} */
-    recentDestinations: Array,
+    /** @private {!print_preview.CloudPrintState} */
+    cloudPrintState_: {
+      type: Number,
+      value: print_preview.CloudPrintState.DISABLED,
+    },
 
-    /** @type {!print_preview_new.State} */
-    state: Number,
+    /** @private {?print_preview.DestinationStore} */
+    destinationStore_: {
+      type: Object,
+      value: null,
+    },
 
-    /** @type {!Array<string>} */
-    users: Array,
+    /** @private {?print_preview.InvitationStore} */
+    invitationStore_: {
+      type: Object,
+      value: null,
+    },
 
     /** @private {!Array<!print_preview.Destination>} */
     recentDestinationList_: Array,
@@ -55,8 +67,7 @@
     /** @private */
     shouldHideSpinner_: {
       type: Boolean,
-      computed: 'computeShouldHideSpinner_(' +
-          'destination, noDestinationsFound, cloudPrintState)',
+      computed: 'computeShouldHideSpinner_(destinationState)',
     },
 
     /** @private {string} */
@@ -64,33 +75,172 @@
       type: String,
       computed: 'computeStatusText_(destination)',
     },
-  },
 
-  observers: [
-    'updateRecentDestinationList_(' +
-        'recentDestinations.*, activeUser, destinationStore)',
-    'updateDestinationSelect_(' +
-        'destination, noDestinationsFound, cloudPrintState)',
-  ],
+    /** @private {!Array<string>} */
+    users_: Array,
+  },
 
   /** @private {!EventTracker} */
   tracker_: new EventTracker(),
 
-  /** @private */
-  onDestinationStoreSet_: function() {
-    if (!this.destinationStore) {
-      return;
-    }
-
+  /** @override */
+  attached: function() {
+    this.destinationStore_ =
+        new print_preview.DestinationStore(this.addWebUIListener.bind(this));
+    this.invitationStore_ = new print_preview.InvitationStore();
+    this.tracker_.add(
+        this.destinationStore_,
+        print_preview.DestinationStore.EventType.DESTINATION_SELECT,
+        this.onDestinationSelect_.bind(this));
+    this.tracker_.add(
+        this.destinationStore_,
+        print_preview.DestinationStore.EventType
+            .SELECTED_DESTINATION_CAPABILITIES_READY,
+        this.onDestinationCapabilitiesReady_.bind(this));
+    this.tracker_.add(
+        this.destinationStore_, print_preview.DestinationStore.EventType.ERROR,
+        this.onDestinationError_.bind(this));
     // Need to update the recent list when the destination store inserts
     // destinations, in case any recent destinations have been added to the
     // store. At startup, recent destinations can be in the sticky settings,
     // but they should not be displayed in the dropdown until they have been
     // fetched by the DestinationStore, to ensure that they still exist.
     this.tracker_.add(
-        assert(this.destinationStore),
+        assert(this.destinationStore_),
         print_preview.DestinationStore.EventType.DESTINATIONS_INSERTED,
-        this.updateRecentDestinationList_.bind(this));
+        this.updateDropdownDestinations_.bind(this));
+  },
+
+  /** @param {!cloudprint.CloudPrintInterface} cloudPrintInterface */
+  setCloudPrintInterface: function(cloudPrintInterface) {
+    [cloudprint.CloudPrintInterfaceEventType.SEARCH_FAILED,
+     cloudprint.CloudPrintInterfaceEventType.PRINTER_FAILED,
+    ].forEach(eventType => {
+      this.tracker_.add(
+          cloudPrintInterface.getEventTarget(), eventType,
+          this.checkCloudPrintStatus_.bind(this));
+    });
+    this.$.userInfo.setCloudPrintInterface(cloudPrintInterface);
+    this.destinationStore_.setCloudPrintInterface(cloudPrintInterface);
+    this.invitationStore_.setCloudPrintInterface(cloudPrintInterface);
+    assert(this.cloudPrintState_ === print_preview.CloudPrintState.DISABLED);
+    this.cloudPrintState_ = print_preview.CloudPrintState.ENABLED;
+  },
+
+  /**
+   * @param {string} defaultPrinter The system default printer ID.
+   * @param {string} serializedDefaultDestinationRulesStr String with rules for
+   *     selecting a default destination.
+   */
+  initDestinationStore: function(
+      defaultPrinter, serializedDefaultDestinationRulesStr) {
+    this.destinationStore_.init(
+        this.appKioskMode, defaultPrinter, serializedDefaultDestinationRulesStr,
+        /** @type {!Array<print_preview.RecentDestination>} */
+        (this.getSettingValue('recentDestinations')));
+  },
+
+  /** @private */
+  onActiveUserChanged_: function() {
+    if (!this.activeUser_) {
+      return;
+    }
+
+    assert(this.cloudPrintState_ !== print_preview.CloudPrintState.DISABLED);
+    this.cloudPrintState_ = print_preview.CloudPrintState.SIGNED_IN;
+
+    // Load docs, in case the user was not signed in previously and signed in
+    // from the destinations dialog.
+    this.destinationStore_.startLoadCookieDestination(
+        print_preview.Destination.GooglePromotedId.DOCS);
+
+    // Load any recent cloud destinations for the dropdown.
+    const recentDestinations = this.getSettingValue('recentDestinations');
+    recentDestinations.forEach(destination => {
+      if (destination.origin === print_preview.DestinationOrigin.COOKIES &&
+          (destination.account === this.activeUser_ ||
+           destination.account === '')) {
+        this.destinationStore_.startLoadCookieDestination(destination.id);
+      }
+    });
+
+    if (this.destinationState === print_preview.DestinationState.SELECTED &&
+        this.destination.origin === print_preview.DestinationOrigin.COOKIES) {
+      this.destinationState = this.destination.capabilities ?
+          print_preview.DestinationState.UPDATED :
+          print_preview.DestinationState.SET;
+    }
+    this.updateDropdownDestinations_();
+  },
+
+  /** @private */
+  onDestinationSelect_: function() {
+    this.destinationState = print_preview.DestinationState.SELECTED;
+    this.destination = this.destinationStore_.selectedDestination;
+    this.updateRecentDestinations_();
+    if (this.cloudPrintState_ === print_preview.CloudPrintState.ENABLED) {
+      // Only try to load the docs destination for now. If this request
+      // succeeds, it will trigger a transition to SIGNED_IN, and we can
+      // load the remaining destinations. Otherwise, it will transition to
+      // NOT_SIGNED_IN, so we will not do this more than once.
+      this.destinationStore_.startLoadCookieDestination(
+          print_preview.Destination.GooglePromotedId.DOCS);
+    }
+    if (this.cloudPrintState_ === print_preview.CloudPrintState.SIGNED_IN ||
+        this.destination.origin !== print_preview.DestinationOrigin.COOKIES) {
+      this.destinationState = print_preview.DestinationState.SET;
+    }
+  },
+
+  /** @private */
+  onDestinationCapabilitiesReady_: function() {
+    this.notifyPath('destination.capabilities');
+    if (this.destinationState === print_preview.DestinationState.SET) {
+      this.destinationState = print_preview.DestinationState.UPDATED;
+    }
+    this.updateRecentDestinations_();
+  },
+
+  /**
+   * @param {!CustomEvent<!print_preview.DestinationErrorType>} e
+   * @private
+   */
+  onDestinationError_: function(e) {
+    switch (e.detail) {
+      case print_preview.DestinationErrorType.INVALID:
+        this.destinationState = print_preview.DestinationState.INVALID;
+        break;
+      case print_preview.DestinationErrorType.UNSUPPORTED:
+        this.destinationState = print_preview.DestinationState.UNSUPPORTED;
+        break;
+      // <if expr="chromeos">
+      case print_preview.DestinationErrorType.NO_DESTINATIONS:
+        this.noDestinationsFound_ = true;
+        this.destinationState = print_preview.DestinationState.NO_DESTINATIONS;
+        break;
+      // </if>
+      default:
+        break;
+    }
+  },
+
+  /**
+   * Updates the cloud print status to NOT_SIGNED_IN if there is an
+   * authentication error.
+   * @param {!CustomEvent<!cloudprint.CloudPrintInterfaceErrorEventDetail>}
+   *     event Contains the error status
+   * @private
+   */
+  checkCloudPrintStatus_: function(event) {
+    if (event.detail.status != 403 || this.appKioskMode) {
+      return;
+    }
+
+    // Should not have sent a message to Cloud Print if cloud print is
+    // disabled.
+    assert(this.cloudPrintState_ !== print_preview.CloudPrintState.DISABLED);
+    this.cloudPrintState_ = print_preview.CloudPrintState.NOT_SIGNED_IN;
+    console.warn('Google Cloud Print Error: HTTP status 403');
   },
 
   /**
@@ -104,32 +254,60 @@
   },
 
   /** @private */
-  updateRecentDestinationList_: function() {
-    if (!this.recentDestinations || !this.destinationStore) {
+  updateRecentDestinations_: function() {
+    if (!this.destination) {
       return;
     }
 
-    const recentDestinations = [];
-    let update = false;
-    const existingKeys = this.recentDestinationList_ ?
-        this.recentDestinationList_.map(listItem => listItem.key) :
-        [];
-    this.recentDestinations.forEach(recentDestination => {
+    // Determine if this destination is already in the recent destinations,
+    // and where in the array it is located.
+    const newDestination =
+        print_preview.makeRecentDestination(assert(this.destination));
+    const recentDestinations = this.getSettingValue('recentDestinations');
+    let indexFound = recentDestinations.findIndex(function(recent) {
+      return (
+          newDestination.id == recent.id &&
+          newDestination.origin == recent.origin);
+    });
+
+    // No change
+    if (indexFound == 0 &&
+        recentDestinations[0].capabilities == newDestination.capabilities) {
+      return;
+    }
+    const isNew = indexFound == -1;
+
+    // Shift the array so that the nth most recent destination is located at
+    // index n.
+    if (isNew && recentDestinations.length == NUM_PERSISTED_DESTINATIONS) {
+      indexFound = NUM_PERSISTED_DESTINATIONS - 1;
+    }
+    if (indexFound != -1) {
+      this.setSettingSplice('recentDestinations', indexFound, 1, null);
+    }
+
+    // Add the most recent destination
+    this.setSettingSplice('recentDestinations', 0, 0, newDestination);
+    if (!this.destinationIsDriveOrPdf_(newDestination) && isNew) {
+      this.updateDropdownDestinations_();
+    }
+  },
+
+  /** @private */
+  updateDropdownDestinations_: function() {
+    const recentDestinations = this.getSettingValue('recentDestinations');
+
+    const dropdownDestinations = [];
+    recentDestinations.forEach(recentDestination => {
       const key = print_preview.createRecentDestinationKey(recentDestination);
-      const destination = this.destinationStore.getDestinationByKey(key);
+      const destination = this.destinationStore_.getDestinationByKey(key);
       if (destination && !this.destinationIsDriveOrPdf_(recentDestination) &&
-          (!destination.account || destination.account == this.activeUser)) {
-        recentDestinations.push(destination);
-        update = update || !existingKeys.includes(key);
+          (!destination.account || destination.account == this.activeUser_)) {
+        dropdownDestinations.push(destination);
       }
     });
 
-    // Only update the list if new destinations have been added to it.
-    // Re-ordering the dropdown items every time the selected item changes is
-    // a bad experience for keyboard users.
-    if (update) {
-      this.recentDestinationList_ = recentDestinations;
-    }
+    this.recentDestinationList_ = dropdownDestinations;
   },
 
   /**
@@ -137,54 +315,24 @@
    * @private
    */
   shouldDisableDropdown_: function() {
-    return !this.destinationStore || this.noDestinationsFound ||
-        !this.shouldHideSpinner_ ||
-        (this.disabled && this.state != print_preview_new.State.NOT_READY &&
-         this.state != print_preview_new.State.INVALID_PRINTER);
-  },
-
-  /** @private */
-  onCloudPrintStateChanged_: function() {
-    if (this.cloudPrintState !== print_preview.CloudPrintState.SIGNED_IN) {
-      return;
+    // <if expr="chromeos">
+    if (this.destinationState ===
+        print_preview.DestinationState.NO_DESTINATIONS) {
+      return true;
     }
+    // </if>
 
-    // Load docs, in case the user was not signed in previously and signed in
-    // from the destinations dialog.
-    this.destinationStore.startLoadCookieDestination(
-        print_preview.Destination.GooglePromotedId.DOCS);
-
-    // Load any recent cloud destinations for the dropdown.
-    this.recentDestinations.forEach(destination => {
-      if (destination.origin === print_preview.DestinationOrigin.COOKIES &&
-          (destination.account === this.activeUser ||
-           destination.account === '')) {
-        this.destinationStore.startLoadCookieDestination(destination.id);
-      }
-    });
-  },
-
-  /** @private */
-  onDestinationSet_: function() {
-    if (this.cloudPrintState === print_preview.CloudPrintState.ENABLED) {
-      // Only try to load the docs destination for now. If this request
-      // succeeds, it will trigger a transition to SIGNED_IN, and we can
-      // load the remaining destinations. Otherwise, it will transition to
-      // NOT_SIGNED_IN, so we will not do this more than once.
-      this.destinationStore.startLoadCookieDestination(
-          print_preview.Destination.GooglePromotedId.DOCS);
-    }
+    return this.destinationState === print_preview.DestinationState.INIT ||
+        this.destinationState === print_preview.DestinationState.SELECTED ||
+        (this.disabled &&
+         (this.destinationState === print_preview.DestinationState.SET ||
+          this.destinationState === print_preview.DestinationState.UPDATED));
   },
 
   /** @private */
   computeShouldHideSpinner_: function() {
-    if (this.noDestinationsFound) {
-      return true;
-    }
-
-    return !!this.destination &&
-        (this.destination.origin !== print_preview.DestinationOrigin.COOKIES ||
-         this.cloudPrintState === print_preview.CloudPrintState.SIGNED_IN);
+    return this.destinationState !== print_preview.DestinationState.INIT &&
+        this.destinationState !== print_preview.DestinationState.SELECTED;
   },
 
   /**
@@ -209,16 +357,25 @@
   onSelectedDestinationOptionChange_: function(e) {
     const value = e.detail;
     if (value === 'seeMore') {
-      this.destinationStore.startLoadAllDestinations();
-      if (this.activeUser) {
-        this.invitationStore.startLoadingInvitations(this.activeUser);
+      this.destinationStore_.startLoadAllDestinations();
+      if (this.activeUser_) {
+        this.invitationStore_.startLoadingInvitations(this.activeUser_);
       }
       this.$.destinationDialog.get().show();
     } else {
-      this.destinationStore.selectDestinationByKey(value);
+      this.destinationStore_.selectDestinationByKey(value);
     }
   },
 
+  /**
+   * @param {!CustomEvent<string>} e Event containing the new active user
+   *     account.
+   * @private
+   */
+  onAccountChange_: function(e) {
+    this.$.userInfo.updateActiveUser(e.detail);
+  },
+
   /** @private */
   onDialogClose_: function() {
     // Reset the select value if the user dismissed the dialog without
@@ -229,10 +386,15 @@
 
   /** @private */
   updateDestinationSelect_: function() {
-    if (!this.destination ||
-        (this.destination.origin === print_preview.DestinationOrigin.COOKIES &&
-         this.cloudPrintState !== print_preview.CloudPrintState.SIGNED_IN) ||
-        this.noDestinationsFound) {
+    // <if expr="chromeos">
+    if (this.destinationState ===
+        print_preview.DestinationState.NO_DESTINATIONS) {
+      return;
+    }
+    // </if>
+
+    if (this.destinationState === print_preview.DestinationState.INIT ||
+        this.destinationState === print_preview.DestinationState.SELECTED) {
       return;
     }
 
@@ -249,3 +411,4 @@
     }
   },
 });
+})();
diff --git a/chrome/browser/resources/print_preview/new/model.js b/chrome/browser/resources/print_preview/new/model.js
index ecb1461..3dc1f34 100644
--- a/chrome/browser/resources/print_preview/new/model.js
+++ b/chrome/browser/resources/print_preview/new/model.js
@@ -69,15 +69,13 @@
 (function() {
 'use strict';
 
-/** @type {number} Number of recent destinations to save. */
-const NUM_DESTINATIONS = 3;
-
 /**
  * Sticky setting names. Alphabetical except for fitToPage, which must be set
  * after scaling in updateFromStickySettings().
  * @type {!Array<string>}
  */
 const STICKY_SETTING_NAMES = [
+  'recentDestinations',
   'collate',
   'color',
   'cssBackground',
@@ -300,6 +298,14 @@
             setByPolicy: false,
             key: '',
           },
+          recentDestinations: {
+            value: [],
+            unavailableValue: [],
+            valid: true,
+            available: true,
+            setByPolicy: false,
+            key: 'recentDestinations',
+          },
         };
         // <if expr="chromeos">
         value.pin = {
@@ -322,10 +328,7 @@
     },
 
     /** @type {print_preview.Destination} */
-    destination: {
-      type: Object,
-      notify: true,
-    },
+    destination: Object,
 
     /** @type {!print_preview.DocumentSettings} */
     documentSettings: Object,
@@ -335,15 +338,6 @@
 
     /** @type {!print_preview.Size} */
     pageSize: Object,
-
-    /** @type {!Array<!print_preview.RecentDestination>} */
-    recentDestinations: {
-      type: Array,
-      notify: true,
-      value: function() {
-        return [];
-      },
-    },
   },
 
   observers: [
@@ -354,7 +348,6 @@
     'updateHeaderFooterAvailable_(' +
         'margins, settings.margins.value, ' +
         'settings.customMargins.value, settings.mediaSize.value)',
-    'updateRecentDestinations_(destination, destination.capabilities)',
     'stickySettingsChanged_(' +
         'settings.collate.value, settings.layout.value, settings.color.value,' +
         'settings.mediaSize.value, settings.margins.value, ' +
@@ -362,7 +355,7 @@
         'settings.fitToPage.value, settings.customScaling.value, ' +
         'settings.scaling.value, settings.duplex.value, ' +
         'settings.headerFooter.value, settings.cssBackground.value, ' +
-        'settings.vendorItems.value)',
+        'settings.vendorItems.value, settings.recentDestinations.value.*)',
     'stickySettingsChanged_(settings.pin.value)',
   ],
 
@@ -678,53 +671,13 @@
     }
   },
 
-  /** @private */
-  updateRecentDestinations_: function() {
-    if (!this.initialized_ || !this.destination) {
-      return;
-    }
-
-    // Determine if this destination is already in the recent destinations,
-    // and where in the array it is located.
-    const newDestination =
-        print_preview.makeRecentDestination(assert(this.destination));
-    let indexFound = this.recentDestinations.findIndex(function(recent) {
-      return (
-          newDestination.id == recent.id &&
-          newDestination.origin == recent.origin);
-    });
-
-    // No change
-    if (indexFound == 0 &&
-        this.recentDestinations[0].capabilities ==
-            newDestination.capabilities) {
-      return;
-    }
-
-    // Shift the array so that the nth most recent destination is located at
-    // index n.
-    if (indexFound == -1 &&
-        this.recentDestinations.length == NUM_DESTINATIONS) {
-      indexFound = NUM_DESTINATIONS - 1;
-    }
-    if (indexFound != -1) {
-      this.recentDestinations.splice(indexFound, 1);
-    }
-
-    // Add the most recent destination
-    this.splice('recentDestinations', 0, 0, newDestination);
-
-    // Persist sticky settings.
-    this.stickySettingsChanged_();
-  },
-
   /**
    * Caches the sticky settings and sets up the recent destinations. Sticky
    * settings will be applied when destinaton capabilities have been retrieved.
    * @param {?string} savedSettingsStr The sticky settings from native layer
    */
   setStickySettings: function(savedSettingsStr) {
-    assert(!this.stickySettings_ && this.recentDestinations.length == 0);
+    assert(!this.stickySettings_);
 
     if (!savedSettingsStr) {
       return;
@@ -746,7 +699,9 @@
     if (!Array.isArray(recentDestinations)) {
       recentDestinations = [recentDestinations];
     }
-    this.recentDestinations = recentDestinations;
+    // Initialize recent destinations early so that the destination store can
+    // start trying to fetch them.
+    this.setSetting('recentDestinations', recentDestinations);
 
     this.stickySettings_ = savedSettings;
   },
@@ -797,7 +752,6 @@
     this.initialized_ = true;
     this.updateManaged_();
     this.stickySettings_ = null;
-    this.updateRecentDestinations_();
     this.stickySettingsChanged_();
   },
 
@@ -865,7 +819,6 @@
 
     const serialization = {
       version: 2,
-      recentDestinations: this.recentDestinations,
     };
 
     STICKY_SETTING_NAMES.forEach(settingName => {
diff --git a/chrome/browser/resources/print_preview/new/settings_behavior.js b/chrome/browser/resources/print_preview/new/settings_behavior.js
index 7e1784e..791cab15 100644
--- a/chrome/browser/resources/print_preview/new/settings_behavior.js
+++ b/chrome/browser/resources/print_preview/new/settings_behavior.js
@@ -88,6 +88,24 @@
 
   /**
    * @param {string} settingName Name of the setting to set
+   * @param {number} start
+   * @param {number} end
+   * @param {*} newValue The value to add (if any).
+   */
+  setSettingSplice: function(settingName, start, end, newValue) {
+    const setting = this.getSetting(settingName);
+    if (setting.setByPolicy) {
+      return;
+    }
+    if (newValue) {
+      this.splice(`settings.${settingName}.value`, start, end, newValue);
+    } else {
+      this.splice(`settings.${settingName}.value`, start, end);
+    }
+  },
+
+  /**
+   * @param {string} settingName Name of the setting to set
    * @param {boolean} valid Whether the setting value is currently valid.
    */
   setSettingValid: function(settingName, valid) {
diff --git a/chrome/browser/resources/print_preview/print_preview_resources.grd b/chrome/browser/resources/print_preview/print_preview_resources.grd
index 1f94fee1..ea4d5db 100644
--- a/chrome/browser/resources/print_preview/print_preview_resources.grd
+++ b/chrome/browser/resources/print_preview/print_preview_resources.grd
@@ -223,16 +223,19 @@
                  type="chrome_html" />
       <structure name="IDR_PRINT_PREVIEW_NEW_DESTINATION_SELECT_HTML"
                  file="new/destination_select.html"
-                 type="chrome_html" />
+                 type="chrome_html"
+                 preprocess="true" />
       <structure name="IDR_PRINT_PREVIEW_NEW_DESTINATION_SELECT_JS"
                  file="new/destination_select.js"
-                 type="chrome_html" />
+                 type="chrome_html"
+                 preprocess="true" />
       <structure name="IDR_PRINT_PREVIEW_NEW_DESTINATION_SETTINGS_HTML"
                  file="new/destination_settings.html"
                  type="chrome_html" />
       <structure name="IDR_PRINT_PREVIEW_NEW_DESTINATION_SETTINGS_JS"
                  file="new/destination_settings.js"
-                 type="chrome_html" />
+                 type="chrome_html"
+                 preprocess="true" />
       <structure name="IDR_PRINT_PREVIEW_NEW_PAGES_SETTINGS_HTML"
                  file="new/pages_settings.html"
                  type="chrome_html" />
diff --git a/chrome/browser/resources/settings/settings.html b/chrome/browser/resources/settings/settings.html
index 60fc7482..c99aed2 100644
--- a/chrome/browser/resources/settings/settings.html
+++ b/chrome/browser/resources/settings/settings.html
@@ -16,8 +16,13 @@
       touch-action: manipulation;
     }
 
-    html.loading {
-      border-top: 56px solid var(--md-toolbar-color);
+    html.loading::before {
+      background-color: var(--md-toolbar-color);
+      border-bottom: var(--md-toolbar-border);
+      box-sizing: border-box;
+      content: '';
+      display: block;
+      height: var(--md-toolbar-height);
     }
   </style>
 </head>
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chrome/browser/resources/settings/settings_ui/settings_ui.html
index 519cbc5..372b651 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.html
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -38,7 +38,6 @@
 
       cr-toolbar {
         @apply --layout-center;
-        background-color: var(--md-toolbar-color);
         min-height: 56px;
         z-index: 2;
       }
diff --git a/chrome/browser/ui/blocked_content/scoped_visibility_tracker.cc b/chrome/browser/scoped_visibility_tracker.cc
similarity index 85%
rename from chrome/browser/ui/blocked_content/scoped_visibility_tracker.cc
rename to chrome/browser/scoped_visibility_tracker.cc
index 64ca553..91288767 100644
--- a/chrome/browser/ui/blocked_content/scoped_visibility_tracker.cc
+++ b/chrome/browser/scoped_visibility_tracker.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/blocked_content/scoped_visibility_tracker.h"
+#include "chrome/browser/scoped_visibility_tracker.h"
 
 #include <utility>
 
@@ -27,8 +27,9 @@
   Update(false /* in_foreground */);
 }
 
-base::TimeDelta ScopedVisibilityTracker::GetForegroundDuration() {
-  Update(currently_in_foreground_);
+base::TimeDelta ScopedVisibilityTracker::GetForegroundDuration() const {
+  if (currently_in_foreground_)
+    return foreground_duration_ + (tick_clock_->NowTicks() - last_time_shown_);
   return foreground_duration_;
 }
 
diff --git a/chrome/browser/ui/blocked_content/scoped_visibility_tracker.h b/chrome/browser/scoped_visibility_tracker.h
similarity index 77%
rename from chrome/browser/ui/blocked_content/scoped_visibility_tracker.h
rename to chrome/browser/scoped_visibility_tracker.h
index a84efac2..203222a 100644
--- a/chrome/browser/ui/blocked_content/scoped_visibility_tracker.h
+++ b/chrome/browser/scoped_visibility_tracker.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_BLOCKED_CONTENT_SCOPED_VISIBILITY_TRACKER_H_
-#define CHROME_BROWSER_UI_BLOCKED_CONTENT_SCOPED_VISIBILITY_TRACKER_H_
+#ifndef CHROME_BROWSER_SCOPED_VISIBILITY_TRACKER_H_
+#define CHROME_BROWSER_SCOPED_VISIBILITY_TRACKER_H_
 
 #include <memory>
 
@@ -25,7 +25,7 @@
   void OnShown();
   void OnHidden();
 
-  base::TimeDelta GetForegroundDuration();
+  base::TimeDelta GetForegroundDuration() const;
 
  private:
   void Update(bool in_foreground);
@@ -39,4 +39,4 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedVisibilityTracker);
 };
 
-#endif  // CHROME_BROWSER_UI_BLOCKED_CONTENT_SCOPED_VISIBILITY_TRACKER_H_
+#endif  // CHROME_BROWSER_SCOPED_VISIBILITY_TRACKER_H_
diff --git a/chrome/browser/ui/blocked_content/scoped_visibility_tracker_unittest.cc b/chrome/browser/scoped_visibility_tracker_unittest.cc
similarity index 97%
rename from chrome/browser/ui/blocked_content/scoped_visibility_tracker_unittest.cc
rename to chrome/browser/scoped_visibility_tracker_unittest.cc
index 4ca157cc..910b5b202 100644
--- a/chrome/browser/ui/blocked_content/scoped_visibility_tracker_unittest.cc
+++ b/chrome/browser/scoped_visibility_tracker_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/blocked_content/scoped_visibility_tracker.h"
+#include "chrome/browser/scoped_visibility_tracker.h"
 
 #include <utility>
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 48db711..6d146e9f 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -85,8 +85,6 @@
     "blocked_content/popup_tracker.h",
     "blocked_content/safe_browsing_triggered_popup_blocker.cc",
     "blocked_content/safe_browsing_triggered_popup_blocker.h",
-    "blocked_content/scoped_visibility_tracker.cc",
-    "blocked_content/scoped_visibility_tracker.h",
     "blocked_content/tab_under_navigation_throttle.cc",
     "blocked_content/tab_under_navigation_throttle.h",
     "blocked_content/url_list_manager.cc",
@@ -1046,6 +1044,8 @@
       "tabs/tab_strip_model_order_controller.h",
       "tabs/tab_strip_model_stats_recorder.cc",
       "tabs/tab_strip_model_stats_recorder.h",
+      "tabs/tab_style.cc",
+      "tabs/tab_style.h",
       "tabs/tab_switch_event_latency_recorder.cc",
       "tabs/tab_switch_event_latency_recorder.h",
       "tabs/tab_utils.cc",
@@ -2828,8 +2828,8 @@
       "views/tabs/tab_strip_controller.h",
       "views/tabs/tab_strip_layout.cc",
       "views/tabs/tab_strip_layout.h",
-      "views/tabs/tab_style.cc",
-      "views/tabs/tab_style.h",
+      "views/tabs/tab_style_views.cc",
+      "views/tabs/tab_style_views.h",
       "views/tabs/window_finder.h",
       "views/task_manager_view.cc",
       "views/task_manager_view.h",
diff --git a/chrome/browser/ui/app_list/internal_app/internal_app_icon_loader.cc b/chrome/browser/ui/app_list/internal_app/internal_app_icon_loader.cc
index 3c4786b..facddb09 100644
--- a/chrome/browser/ui/app_list/internal_app/internal_app_icon_loader.cc
+++ b/chrome/browser/ui/app_list/internal_app/internal_app_icon_loader.cc
@@ -10,8 +10,7 @@
 InternalAppIconLoader::InternalAppIconLoader(Profile* profile,
                                              int resource_size_in_dip,
                                              AppIconLoaderDelegate* delegate)
-    : AppIconLoader(profile, resource_size_in_dip, delegate),
-      resource_size_in_dip_(resource_size_in_dip) {}
+    : AppIconLoader(profile, resource_size_in_dip, delegate) {}
 
 InternalAppIconLoader::~InternalAppIconLoader() = default;
 
@@ -27,7 +26,7 @@
 
   std::unique_ptr<gfx::ImageSkia> image_skia =
       std::make_unique<gfx::ImageSkia>(app_list::GetIconForResourceId(
-          app_list::GetIconResourceIdByAppId(app_id), resource_size_in_dip_));
+          app_list::GetIconResourceIdByAppId(app_id), icon_size_in_dip()));
   image_skia->EnsureRepsForSupportedScales();
   icon_map_[app_id] = std::move(image_skia);
   UpdateImage(app_id);
diff --git a/chrome/browser/ui/app_list/internal_app/internal_app_icon_loader.h b/chrome/browser/ui/app_list/internal_app/internal_app_icon_loader.h
index 2974fbf..601ed07 100644
--- a/chrome/browser/ui/app_list/internal_app/internal_app_icon_loader.h
+++ b/chrome/browser/ui/app_list/internal_app/internal_app_icon_loader.h
@@ -32,9 +32,6 @@
  private:
   using AppIDToIconMap = std::map<std::string, std::unique_ptr<gfx::ImageSkia>>;
 
-  // The preferred icon size.
-  int resource_size_in_dip_;
-
   // Maps from internal app id to icon.
   AppIDToIconMap icon_map_;
 
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc
index 6be929a..e2c8120 100644
--- a/chrome/browser/ui/app_list/search/search_controller_factory.cc
+++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -149,8 +149,7 @@
         std::make_unique<SettingsShortcutProvider>(profile));
   }
 
-  if (app_list_features::IsAppShortcutSearchEnabled() &&
-      arc::IsArcAllowedForProfile(profile)) {
+  if (arc::IsArcAllowedForProfile(profile)) {
     size_t app_shortcut_group_id =
         controller->AddGroup(kMaxAppShortcutResults, 1.0, kBoostOfApps);
     controller->AddProvider(
diff --git a/chrome/browser/ui/ash/assistant/device_actions.cc b/chrome/browser/ui/ash/assistant/device_actions.cc
index 388f037..b52eea7 100644
--- a/chrome/browser/ui/ash/assistant/device_actions.cc
+++ b/chrome/browser/ui/ash/assistant/device_actions.cc
@@ -139,6 +139,9 @@
   arc::mojom::ActivityNamePtr activity = arc::mojom::ActivityName::New();
   activity->package_name = package_name;
   auto intent = arc::mojom::IntentInfo::New();
+  if (!app_info->action.empty())
+    intent->action = app_info->action;
+
   if (!app_info->intent.empty()) {
     intent->data = app_info->intent;
   } else {
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
index 3f2f7c5..8441002 100644
--- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
@@ -344,6 +344,10 @@
                                       TabStripModel::CLOSE_USER_GESTURE);
       }
     } else {
+      // These extra checks should gather info for http://crbug.com/937088
+      CHECK(browser);
+      CHECK(browser->window());
+      CHECK(browser->window()->GetNativeWindow());
       multi_user_util::MoveWindowToCurrentDesktop(
           browser->window()->GetNativeWindow());
       if (tab_index != kNoTab && tab_strip->ContainsIndex(tab_index))
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_client_impl.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_client_impl.cc
index cab8688..cf57767c 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_client_impl.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_client_impl.cc
@@ -397,17 +397,21 @@
   it->second->set_show_for_user(account_id);
 
   const AccountId& owner = GetWindowOwner(window);
-  if (owner.is_valid()) {
+  // Browser windows don't use kAvatarIconKey. See
+  // BrowserNonClientFrameViewAsh::UpdateProfileIcons().
+  if (owner.is_valid() && !chrome::FindBrowserWithWindow(window)) {
     const user_manager::User* const window_owner =
         user_manager::UserManager::IsInitialized()
             ? user_manager::UserManager::Get()->FindUser(owner)
             : nullptr;
+    aura::Window* property_window =
+        features::IsUsingWindowService() ? window->GetRootWindow() : window;
     if (window_owner && teleported) {
-      window->SetProperty(
+      property_window->SetProperty(
           aura::client::kAvatarIconKey,
           new gfx::ImageSkia(GetAvatarImageForUser(window_owner)));
     } else {
-      window->ClearProperty(aura::client::kAvatarIconKey);
+      property_window->ClearProperty(aura::client::kAvatarIconKey);
     }
   }
 
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_client_impl_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_client_impl_unittest.cc
index 2e49ff4..95db1711 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_client_impl_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_client_impl_unittest.cc
@@ -1458,17 +1458,24 @@
 
   SwitchActiveUser(user1);
 
-  // Window #0 has no kAvatarIconKey property before teloporting.
-  EXPECT_FALSE(window(0)->GetProperty(aura::client::kAvatarIconKey));
+  // This ternary doesn't make a lot of sense because the windows in this
+  // AshTest aren't created via the window service, but it's necessary to mirror
+  // the code in MultiUserWindowManagerClientImpl, where the content window's
+  // root window is the Ash host window.
+  aura::Window* property_window =
+      features::IsUsingWindowService() ? window(0)->GetRootWindow() : window(0);
+
+  // Window #0 has no kAvatarIconKey property before teleporting.
+  EXPECT_FALSE(property_window->GetProperty(aura::client::kAvatarIconKey));
 
   // Teleport window #0 to user2 and kAvatarIconKey property is present.
   multi_user_window_manager_client()->ShowWindowForUser(window(0), user2);
-  EXPECT_TRUE(window(0)->GetProperty(aura::client::kAvatarIconKey));
+  EXPECT_TRUE(property_window->GetProperty(aura::client::kAvatarIconKey));
 
-  // Teloport window #0 back to its owner (user1) and kAvatarIconKey property is
+  // Teleport window #0 back to its owner (user1) and kAvatarIconKey property is
   // gone.
   multi_user_window_manager_client()->ShowWindowForUser(window(0), user1);
-  EXPECT_FALSE(window(0)->GetProperty(aura::client::kAvatarIconKey));
+  EXPECT_FALSE(property_window->GetProperty(aura::client::kAvatarIconKey));
 }
 
 // Tests that the window order is preserved when switching between users. Also
diff --git a/chrome/browser/ui/ash/tab_scrubber.cc b/chrome/browser/ui/ash/tab_scrubber.cc
index e094bc73..cd25197b 100644
--- a/chrome/browser/ui/ash/tab_scrubber.cc
+++ b/chrome/browser/ui/ash/tab_scrubber.cc
@@ -19,7 +19,7 @@
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
-#include "chrome/browser/ui/views/tabs/tab_style.h"
+#include "chrome/browser/ui/views/tabs/tab_style_views.h"
 #include "ui/events/event.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/gesture_detection/gesture_configuration.h"
@@ -239,7 +239,7 @@
     TabStrip* tab_strip = browser_view->tabstrip();
     if (activate && highlighted_tab_ != -1) {
       Tab* tab = tab_strip->tab_at(highlighted_tab_);
-      tab->tab_style()->HideHover(GlowHoverController::HideStyle::kImmediate);
+      tab->tab_style()->HideHover(TabStyle::HideHoverStyle::kImmediate);
       int distance = std::abs(highlighted_tab_ -
                               browser_->tab_strip_model()->active_index());
       UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.ScrubDistance", distance, 1, 20, 21);
@@ -318,13 +318,12 @@
 
   if (highlighted_tab_ != -1) {
     Tab* tab = tab_strip_->tab_at(highlighted_tab_);
-    tab->tab_style()->HideHover(GlowHoverController::HideStyle::kImmediate);
+    tab->tab_style()->HideHover(TabStyle::HideHoverStyle::kImmediate);
   }
 
   if (new_index != browser_->tab_strip_model()->active_index()) {
     highlighted_tab_ = new_index;
-    new_tab->tab_style()->ShowHover(
-        GlowHoverController::ShowStyle::kPronounced);
+    new_tab->tab_style()->ShowHover(TabStyle::ShowHoverStyle::kPronounced);
   } else {
     highlighted_tab_ = -1;
   }
diff --git a/chrome/browser/ui/blocked_content/popup_opener_tab_helper.cc b/chrome/browser/ui/blocked_content/popup_opener_tab_helper.cc
index 7da001c..2732a5e 100644
--- a/chrome/browser/ui/blocked_content/popup_opener_tab_helper.cc
+++ b/chrome/browser/ui/blocked_content/popup_opener_tab_helper.cc
@@ -10,7 +10,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/tick_clock.h"
-#include "chrome/browser/ui/blocked_content/scoped_visibility_tracker.h"
+#include "chrome/browser/scoped_visibility_tracker.h"
 #include "chrome/browser/ui/blocked_content/tab_under_navigation_throttle.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/ui/blocked_content/popup_tracker.h b/chrome/browser/ui/blocked_content/popup_tracker.h
index 34fb180..fe9d011 100644
--- a/chrome/browser/ui/blocked_content/popup_tracker.h
+++ b/chrome/browser/ui/blocked_content/popup_tracker.h
@@ -8,7 +8,7 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "base/time/time.h"
-#include "chrome/browser/ui/blocked_content/scoped_visibility_tracker.h"
+#include "chrome/browser/scoped_visibility_tracker.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 3356cc5..1956d260 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -2544,39 +2544,25 @@
 }
 
 namespace {
-class JSBooleanResultGetter {
- public:
-  JSBooleanResultGetter() = default;
-  void OnJsExecutionDone(base::Closure callback, base::Value value) {
-    js_result_.reset(value.DeepCopy());
-    callback.Run();
-  }
-  bool GetResult() const {
-    bool res;
-    CHECK(js_result_);
-    CHECK(js_result_->GetAsBoolean(&res));
-    return res;
-  }
-
- private:
-  std::unique_ptr<base::Value> js_result_;
-  DISALLOW_COPY_AND_ASSIGN(JSBooleanResultGetter);
-};
 
 void CheckDisplayModeMQ(const base::string16& display_mode,
                         content::WebContents* web_contents) {
   base::string16 function =
       ASCIIToUTF16("(function() {return window.matchMedia('(display-mode: ") +
       display_mode + ASCIIToUTF16(")').matches;})();");
-  JSBooleanResultGetter js_result_getter;
-  // Execute the JS to run the tests, and wait until it has finished.
+  bool js_result = false;
   base::RunLoop run_loop;
   web_contents->GetMainFrame()->ExecuteJavaScriptForTests(
-      function, base::BindOnce(&JSBooleanResultGetter::OnJsExecutionDone,
-                               base::Unretained(&js_result_getter),
-                               run_loop.QuitClosure()));
+      function, base::BindOnce(
+                    [](base::OnceClosure quit_closure, bool* out_result,
+                       base::Value value) {
+                      DCHECK(value.is_bool());
+                      *out_result = value.GetBool();
+                      std::move(quit_closure).Run();
+                    },
+                    run_loop.QuitClosure(), &js_result));
   run_loop.Run();
-  EXPECT_TRUE(js_result_getter.GetResult());
+  EXPECT_TRUE(js_result);
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/libgtkui/gtk_ui.cc b/chrome/browser/ui/libgtkui/gtk_ui.cc
index e1c55b8..8733e118 100644
--- a/chrome/browser/ui/libgtkui/gtk_ui.cc
+++ b/chrome/browser/ui/libgtkui/gtk_ui.cc
@@ -489,8 +489,8 @@
   return native_theme_;
 }
 
-void GtkUi::SetNativeThemeOverride(const NativeThemeGetter& callback) {
-  native_theme_overrider_ = callback;
+void GtkUi::SetNativeThemeOverride(NativeThemeGetter callback) {
+  native_theme_overrider_ = std::move(callback);
 }
 
 bool GtkUi::GetDefaultUsesSystemTheme() const {
diff --git a/chrome/browser/ui/libgtkui/gtk_ui.h b/chrome/browser/ui/libgtkui/gtk_ui.h
index 6bdb8bc7..68797e82 100644
--- a/chrome/browser/ui/libgtkui/gtk_ui.h
+++ b/chrome/browser/ui/libgtkui/gtk_ui.h
@@ -36,9 +36,6 @@
   GtkUi();
   ~GtkUi() override;
 
-  typedef base::Callback<ui::NativeTheme*(aura::Window* window)>
-      NativeThemeGetter;
-
   // Setters used by SettingsProvider:
   void SetWindowButtonOrdering(
       const std::vector<views::FrameButton>& leading_buttons,
@@ -82,7 +79,7 @@
   SkColor GetInactiveSelectionFgColor() const override;
   base::TimeDelta GetCursorBlinkInterval() const override;
   ui::NativeTheme* GetNativeTheme(aura::Window* window) const override;
-  void SetNativeThemeOverride(const NativeThemeGetter& callback) override;
+  void SetNativeThemeOverride(NativeThemeGetter callback) override;
   bool GetDefaultUsesSystemTheme() const override;
   void SetDownloadCount(int count) const override;
   void SetProgressFraction(float percentage) const override;
diff --git a/chrome/browser/ui/libgtkui/select_file_dialog_impl_gtk.cc b/chrome/browser/ui/libgtkui/select_file_dialog_impl_gtk.cc
index 1986b41..8360333 100644
--- a/chrome/browser/ui/libgtkui/select_file_dialog_impl_gtk.cc
+++ b/chrome/browser/ui/libgtkui/select_file_dialog_impl_gtk.cc
@@ -17,6 +17,7 @@
 #include <vector>
 
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -64,8 +65,9 @@
 
 // Runs DesktopWindowTreeHostX11::EnableEventListening() when the file-picker
 // is closed.
-void OnFilePickerDestroy(base::Closure* callback) {
-  callback->Run();
+void OnFilePickerDestroy(base::OnceClosure* callback_raw) {
+  std::unique_ptr<base::OnceClosure> callback = base::WrapUnique(callback_raw);
+  std::move(*callback).Run();
 }
 
 }  // namespace
@@ -190,10 +192,11 @@
       // been captured and by turning off event listening, it is never
       // released. So we manually ensure there is no current capture.
       host->ReleaseCapture();
-      std::unique_ptr<base::Closure> callback =
-          views::DesktopWindowTreeHostX11::GetHostForXID(
-              host->GetAcceleratedWidget())
-              ->DisableEventListening();
+      std::unique_ptr<base::OnceClosure> callback =
+          std::make_unique<base::OnceClosure>(
+              views::DesktopWindowTreeHostX11::GetHostForXID(
+                  host->GetAcceleratedWidget())
+                  ->DisableEventListening());
       // OnFilePickerDestroy() is called when |dialog| destroyed, which allows
       // to invoke the callback function to re-enable event handling on the
       // owning window.
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 2b54235..e0259dc 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -1614,8 +1614,17 @@
   if (!triggered_by_other_operation &&
       (selection.active_tab_changed() || selection.selection_changed())) {
     if (selection.active_tab_changed()) {
-      tab_switch_event_latency_recorder_.OnWillChangeActiveTab(
-          base::TimeTicks::Now());
+      auto now = base::TimeTicks::Now();
+      if (selection.new_contents &&
+          selection.new_contents->GetRenderWidgetHostView()) {
+        auto input_event_timestamp =
+            tab_switch_event_latency_recorder_.input_event_timestamp();
+        // input_event_timestamp may be null in some cases, e.g. in tests.
+        selection.new_contents->GetRenderWidgetHostView()
+            ->SetLastTabChangeStartTime(
+                !input_event_timestamp.is_null() ? input_event_timestamp : now);
+      }
+      tab_switch_event_latency_recorder_.OnWillChangeActiveTab(now);
     }
     TabStripModelChange change;
     auto visibility_tracker = InstallRenderWigetVisibilityTracker(selection);
diff --git a/chrome/browser/ui/tabs/tab_style.cc b/chrome/browser/ui/tabs/tab_style.cc
new file mode 100644
index 0000000..00e4e8a
--- /dev/null
+++ b/chrome/browser/ui/tabs/tab_style.cc
@@ -0,0 +1,75 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/tabs/tab_style.h"
+
+#include "ui/base/material_design/material_design_controller.h"
+#include "ui/views/layout/layout_provider.h"
+
+namespace {
+
+// Thickness in DIPs of the separator painted on the left and right edges of
+// the tab.
+constexpr int kSeparatorThickness = 1;
+
+// Returns the height of the separator between tabs.
+int GetSeparatorHeight() {
+  return ui::MaterialDesignController::touch_ui() ? 24 : 20;
+}
+
+}  // namespace
+
+TabStyle::~TabStyle() = default;
+
+// static
+int TabStyle::GetStandardWidth() {
+  // The standard tab width is 240 DIP including both separators.
+  constexpr int kTabWidth = 240;
+  // The overlap includes one separator, so subtract it here.
+  return kTabWidth + GetTabOverlap() - kSeparatorThickness;
+}
+
+// static
+int TabStyle::GetPinnedWidth() {
+  constexpr int kTabPinnedContentWidth = 23;
+  return kTabPinnedContentWidth + GetContentsHorizontalInsetSize() * 2;
+}
+
+// static
+int TabStyle::GetTabOverlap() {
+  return GetCornerRadius() * 2 + kSeparatorThickness;
+}
+
+// static
+int TabStyle::GetDragHandleExtension(int height) {
+  return (height - GetSeparatorHeight()) / 2 - 1;
+}
+
+// static
+gfx::Insets TabStyle::GetTabInternalPadding() {
+  return gfx::Insets(0, GetCornerRadius());
+}
+
+// static
+gfx::Size TabStyle::GetSeparatorSize() {
+  return gfx::Size(kSeparatorThickness, GetSeparatorHeight());
+}
+
+// static
+gfx::Size TabStyle::GetPreviewImageSize() {
+  constexpr float kTabHoverCardPreviewImageAspectRatio = 16.0f / 9.0f;
+  const int width = GetStandardWidth();
+  return gfx::Size(width, width / kTabHoverCardPreviewImageAspectRatio);
+}
+
+// static
+int TabStyle::GetCornerRadius() {
+  return views::LayoutProvider::Get()->GetCornerRadiusMetric(
+      views::EMPHASIS_HIGH);
+}
+
+// static
+int TabStyle::GetContentsHorizontalInsetSize() {
+  return GetCornerRadius() * 2;
+}
diff --git a/chrome/browser/ui/views/tabs/tab_style.h b/chrome/browser/ui/tabs/tab_style.h
similarity index 76%
rename from chrome/browser/ui/views/tabs/tab_style.h
rename to chrome/browser/ui/tabs/tab_style.h
index 7393cfd..ed9b943 100644
--- a/chrome/browser/ui/views/tabs/tab_style.h
+++ b/chrome/browser/ui/tabs/tab_style.h
@@ -1,24 +1,23 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_STYLE_H_
-#define CHROME_BROWSER_UI_VIEWS_TABS_TAB_STYLE_H_
-
-#include <memory>
+#ifndef CHROME_BROWSER_UI_TABS_TAB_STYLE_H_
+#define CHROME_BROWSER_UI_TABS_TAB_STYLE_H_
 
 #include "base/macros.h"
-#include "chrome/browser/ui/views/tabs/glow_hover_controller.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size.h"
 
 namespace gfx {
 class Canvas;
 }
 
 class SkPath;
-class Tab;
 
-// Holds all of the logic for rendering tabs, including preferred sizes, paths,
+// Holds the basic logic for rendering tabs, including preferred sizes, paths,
 // etc.
 class TabStyle {
  public:
@@ -54,6 +53,13 @@
     kDips
   };
 
+  enum class ShowHoverStyle { kSubtle, kPronounced };
+
+  enum class HideHoverStyle {
+    kGradual,    // The hover should fade out.
+    kImmediate,  // The hover should cut off, with no fade out.
+  };
+
   // If we want to draw vertical separators between tabs, these are the leading
   // and trailing separator stroke rectangles.
   struct SeparatorBounds {
@@ -79,15 +85,6 @@
     SkColor button_background_pressed_color;
   };
 
-  // Creates an appropriate TabStyle instance for a particular tab.
-  // Caller is responsibly for the TabStyle object's lifespan and should delete
-  // it when finished.
-  //
-  // We've implemented this as a factory function so that when we're playing
-  // with new variatons on tab shapes we can have a few possible implementations
-  // and switch them in one place.
-  static std::unique_ptr<TabStyle> CreateForTab(Tab* tab);
-
   virtual ~TabStyle();
 
   // Gets the specific |path_type| associated with the specific |tab|.
@@ -117,18 +114,10 @@
   virtual void SetHoverLocation(const gfx::Point& location) = 0;
 
   // Shows the hover animation.
-  virtual void ShowHover(GlowHoverController::ShowStyle style) = 0;
+  virtual void ShowHover(ShowHoverStyle style) = 0;
 
   // Hides the hover animation.
-  virtual void HideHover(GlowHoverController::HideStyle style) = 0;
-
-  // Returns the minimum possible width of a selected Tab. Selected tabs must
-  // always show a close button, and thus have a larger minimum size than
-  // unselected tabs.
-  static int GetMinimumActiveWidth();
-
-  // Returns the minimum possible width of a single unselected Tab.
-  static int GetMinimumInactiveWidth();
+  virtual void HideHover(HideHoverStyle style) = 0;
 
   // Returns the preferred width of a single Tab, assuming space is
   // available.
@@ -140,26 +129,36 @@
   // Returns the overlap between adjacent tabs.
   static int GetTabOverlap();
 
-  // Returns, for a tab of height |height|, how far the window top drag handle
-  // can extend down into inactive tabs or the new tab button. This behavior
-  // is not used in all cases.
-  static int GetDragHandleExtension(int height);
-
   // Get the space only partially occupied by a tab that we should
   // consider to be padding rather than part of the body of the tab for
   // interaction purposes.
   static gfx::Insets GetTabInternalPadding();
 
   // Gets the size of the separator drawn between tabs, if any.
-  // TODO(dfried): Move any logic that needs this inside tab_style.cc.
   static gfx::Size GetSeparatorSize();
 
+  // Returns, for a tab of height |height|, how far the window top drag handle
+  // can extend down into inactive tabs or the new tab button. This behavior
+  // is not used in all cases.
+  static int GetDragHandleExtension(int height);
+
+  // Gets the preferred size for tab previews, which could be screencaps, hero
+  // or og:image images, etc.
+  static gfx::Size GetPreviewImageSize();
+
  protected:
   // Avoid implicitly-deleted constructor.
   TabStyle() = default;
 
+  // Returns the radius of the outer corners of the tab shape.
+  static int GetCornerRadius();
+
+  // Returns how far from the leading and trailing edges of a tab the contents
+  // should actually be laid out.
+  static int GetContentsHorizontalInsetSize();
+
  private:
   DISALLOW_COPY_AND_ASSIGN(TabStyle);
 };
 
-#endif  // CHROME_BROWSER_UI_VIEWS_TABS_TAB_STYLE_H_
+#endif  // CHROME_BROWSER_UI_TABS_TAB_STYLE_H_
diff --git a/chrome/browser/ui/tabs/tab_switch_event_latency_recorder.h b/chrome/browser/ui/tabs/tab_switch_event_latency_recorder.h
index c60f9a8..483171a 100644
--- a/chrome/browser/ui/tabs/tab_switch_event_latency_recorder.h
+++ b/chrome/browser/ui/tabs/tab_switch_event_latency_recorder.h
@@ -30,6 +30,10 @@
   // this do nothing.
   void OnWillChangeActiveTab(const base::TimeTicks change_time);
 
+  base::TimeTicks input_event_timestamp() const {
+    return input_event_timestamp_;
+  }
+
  private:
   base::TimeTicks input_event_timestamp_ = base::TimeTicks();
   base::Optional<EventType> event_type_ = base::nullopt;
diff --git a/chrome/browser/ui/thumbnails/OWNERS b/chrome/browser/ui/thumbnails/OWNERS
index 4c6e5bc..3a92f21 100644
--- a/chrome/browser/ui/thumbnails/OWNERS
+++ b/chrome/browser/ui/thumbnails/OWNERS
@@ -1 +1,2 @@
+dfried@chromium.org
 pbos@chromium.org
diff --git a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc
index 36faa4d1..da2df27 100644
--- a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc
+++ b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc
@@ -118,17 +118,28 @@
   return !profile || !search::IsInstantNTPURL(url, profile);
 }
 
-void ChromeLocationBarModelDelegate::GetSecurityInfo(
-    security_state::SecurityInfo* result) const {
+security_state::SecurityLevel ChromeLocationBarModelDelegate::GetSecurityLevel()
+    const {
   content::WebContents* web_contents = GetActiveWebContents();
   // If there is no active WebContents (which can happen during toolbar
   // initialization), assume no security style.
   if (!web_contents) {
-    *result = security_state::SecurityInfo();
-    return;
+    return security_state::NONE;
   }
   auto* helper = SecurityStateTabHelper::FromWebContents(web_contents);
-  helper->GetSecurityInfo(result);
+  return helper->GetSecurityLevel();
+}
+
+std::unique_ptr<security_state::VisibleSecurityState>
+ChromeLocationBarModelDelegate::GetVisibleSecurityState() const {
+  content::WebContents* web_contents = GetActiveWebContents();
+  // If there is no active WebContents (which can happen during toolbar
+  // initialization), assume no security info.
+  if (!web_contents) {
+    return std::make_unique<security_state::VisibleSecurityState>();
+  }
+  auto* helper = SecurityStateTabHelper::FromWebContents(web_contents);
+  return helper->GetVisibleSecurityState();
 }
 
 scoped_refptr<net::X509Certificate>
diff --git a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h
index 26d74e9..cbe5562 100644
--- a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h
+++ b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h
@@ -41,7 +41,9 @@
       const GURL& url,
       const base::string16& formatted_url) const override;
   bool GetURL(GURL* url) const override;
-  void GetSecurityInfo(security_state::SecurityInfo* result) const override;
+  security_state::SecurityLevel GetSecurityLevel() const override;
+  std::unique_ptr<security_state::VisibleSecurityState>
+  GetVisibleSecurityState() const override;
   scoped_refptr<net::X509Certificate> GetCertificate() const override;
   const gfx::VectorIcon* GetVectorIconOverride() const override;
   bool IsOfflinePage() const override;
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
index faae780..79c24d7 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
@@ -69,7 +69,7 @@
 
 void ChromeBrowserMainExtraPartsViewsLinux::PreEarlyInitialization() {
   views::LinuxUI* gtk_ui = BuildGtkUi();
-  gtk_ui->SetNativeThemeOverride(base::Bind(&GetNativeThemeForWindow));
+  gtk_ui->SetNativeThemeOverride(base::BindRepeating(&GetNativeThemeForWindow));
   views::LinuxUI::SetInstance(gtk_ui);
 }
 
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_list_view.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_list_view.cc
index 54ff176..62770522 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_list_view.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_list_view.cc
@@ -90,8 +90,6 @@
 DesktopMediaSourceView* DesktopMediaListView::GetSelection() {
   for (int i = 0; i < child_count(); ++i) {
     DesktopMediaSourceView* source_view = GetChild(i);
-    DCHECK_EQ(source_view->GetClassName(),
-              DesktopMediaSourceView::kDesktopMediaSourceViewClassName);
     if (source_view->is_selected())
       return source_view;
   }
@@ -144,19 +142,18 @@
   if (position_increment == 0)
     return false;
 
-  DesktopMediaSourceView* selected = GetSelection();
-  DesktopMediaSourceView* new_selected = nullptr;
+  views::View* selected = GetSelection();
+  views::View* new_selected = nullptr;
 
   if (selected) {
     int index = GetIndexOf(selected);
     int new_index = index + position_increment;
     new_index = std::min(new_index, child_count() - 1);
     new_index = std::max(new_index, 0);
-    if (index != new_index) {
-      new_selected = GetChild(new_index);
-    }
+    if (index != new_index)
+      new_selected = child_at(new_index);
   } else if (has_children()) {
-    new_selected = GetChild(0);
+    new_selected = child_at(0);
   }
 
   if (new_selected)
@@ -214,8 +211,6 @@
 void DesktopMediaListView::OnSourceRemoved(DesktopMediaList* list, int index) {
   DesktopMediaSourceView* view = GetChild(index);
   DCHECK(view);
-  DCHECK_EQ(view->GetClassName(),
-            DesktopMediaSourceView::kDesktopMediaSourceViewClassName);
 
   bool was_selected = view->is_selected();
   RemoveChildView(view);
@@ -237,7 +232,7 @@
 void DesktopMediaListView::OnSourceMoved(DesktopMediaList* list,
                                          int old_index,
                                          int new_index) {
-  ReorderChildView(GetChild(old_index), new_index);
+  ReorderChildView(child_at(old_index), new_index);
   PreferredSizeChanged();
 }
 
@@ -272,7 +267,10 @@
 }
 
 DesktopMediaSourceView* DesktopMediaListView::GetChild(int index) {
-  return static_cast<DesktopMediaSourceView*>(child_at(index));
+  views::View* child = child_at(index);
+  DCHECK_EQ(DesktopMediaSourceView::kDesktopMediaSourceViewClassName,
+            child->GetClassName());
+  return static_cast<DesktopMediaSourceView*>(child);
 }
 
 void DesktopMediaListView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
diff --git a/chrome/browser/ui/views/download/download_shelf_context_menu_view.cc b/chrome/browser/ui/views/download/download_shelf_context_menu_view.cc
index fbfb896b..47d2295 100644
--- a/chrome/browser/ui/views/download/download_shelf_context_menu_view.cc
+++ b/chrome/browser/ui/views/download/download_shelf_context_menu_view.cc
@@ -32,8 +32,8 @@
   menu_runner_.reset(new views::MenuRunner(
       menu_model,
       views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU,
-      base::Bind(&DownloadShelfContextMenuView::OnMenuClosed,
-                 base::Unretained(this), on_menu_closed_callback)));
+      base::BindRepeating(&DownloadShelfContextMenuView::OnMenuClosed,
+                          base::Unretained(this), on_menu_closed_callback)));
 
   // The menu's alignment is determined based on the UI layout.
   views::MenuAnchorPosition position;
diff --git a/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc
index 2660599..884e8f4 100644
--- a/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view.cc
@@ -36,30 +36,8 @@
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/dialog_delegate.h"
 
-#if defined(OS_CHROMEOS)
-#include "ash/public/cpp/shell_window_ids.h"
-#include "chrome/browser/ui/ash/ash_util.h"
-#endif
-
 namespace {
 
-#if defined(OS_CHROMEOS)
-views::Widget* CreateChromeOSAppListParentedDialog(
-    views::DialogDelegateView* delegate_view) {
-  views::Widget* widget = new views::Widget;
-  views::Widget::InitParams params =
-      views::DialogDelegate::GetDialogWidgetInitParams(
-          delegate_view, nullptr /* context */, nullptr /* parent */,
-          gfx::Rect() /* bounds */);
-
-  ash_util::SetupWidgetInitParamsForContainer(
-      &params, ash::kShellWindowId_AppListContainer);
-
-  widget->Init(params);
-  return widget;
-}
-#endif
-
 ToolbarActionView* GetExtensionAnchorView(const std::string& extension_id,
                                           gfx::NativeWindow window) {
   BrowserView* browser_view =
@@ -169,14 +147,6 @@
   if (anchor_view) {
     views::BubbleDialogDelegateView::CreateBubble(view_)->Show();
   } else {
-#if defined(OS_CHROMEOS)
-    // On ChromeOS, the uninstall dialog can be created from the App List, so we
-    // need to attach the AppList window as the parent window.
-    if (uninstall_source() == extensions::UNINSTALL_SOURCE_APP_LIST) {
-      CreateChromeOSAppListParentedDialog(view_)->Show();
-      return;
-    }
-#endif
     constrained_window::CreateBrowserModalDialogViews(view_, parent())->Show();
   }
 }
diff --git a/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view_browsertest.cc b/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view_browsertest.cc
index 598e8e74..10c6c9b 100644
--- a/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extension_uninstall_dialog_view_browsertest.cc
@@ -27,15 +27,6 @@
 #include "extensions/common/extension_urls.h"
 #include "extensions/common/value_builder.h"
 
-#if defined(OS_CHROMEOS)
-#include "ash/public/cpp/shell_window_ids.h"
-#include "ash/public/interfaces/constants.mojom.h"
-#include "ash/public/interfaces/shell_test_api.test-mojom-test-utils.h"
-#include "content/public/common/service_manager_connection.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "ui/aura/test/mus/change_completion_waiter.h"
-#endif
-
 namespace {
 
 const char kUninstallUrl[] = "https://www.google.com/";
@@ -62,25 +53,6 @@
                              std::make_unique<base::Value>(kUninstallUrl));
 }
 
-#if defined(OS_CHROMEOS)
-// Returns the number of child windows in the AppList container on ChromeOS.
-// Blocks until the ash service responds.
-int GetWindowCountForAppListContainer() {
-  // Wait for window visibility to stabilize.
-  aura::test::WaitForAllChangesToComplete();
-
-  ash::mojom::ShellTestApiPtr shell_test_api;
-  content::ServiceManagerConnection::GetForProcess()
-      ->GetConnector()
-      ->BindInterface(ash::mojom::kServiceName, &shell_test_api);
-  ash::mojom::ShellTestApiAsyncWaiter waiter(shell_test_api.get());
-  int child_window_count = 0;
-  waiter.GetChildWindowCountInContainer(ash::kShellWindowId_AppListContainer,
-                                        &child_window_count);
-  return child_window_count;
-}
-#endif
-
 class TestExtensionUninstallDialogDelegate
     : public extensions::ExtensionUninstallDialog::Delegate {
  public:
@@ -164,54 +136,6 @@
 }
 
 #if defined(OS_CHROMEOS)
-IN_PROC_BROWSER_TEST_F(ExtensionUninstallDialogViewBrowserTest,
-                       ParentWindowIsAppList) {
-  scoped_refptr<const extensions::Extension> extension(BuildTestExtension());
-  extensions::ExtensionSystem::Get(browser()->profile())
-      ->extension_service()
-      ->AddExtension(extension.get());
-
-  // Initially the AppList window should have no children.
-  EXPECT_EQ(0, GetWindowCountForAppListContainer());
-
-  // Open the extension uninstall dialog without a browser parent window. This
-  // occurs when the dialog is opened from the Launcher.
-  std::unique_ptr<extensions::ExtensionUninstallDialog> dialog;
-  dialog = extensions::ExtensionUninstallDialog::Create(browser()->profile(),
-                                                        nullptr, nullptr);
-  dialog->ConfirmUninstall(extension.get(),
-                           extensions::UNINSTALL_REASON_FOR_TESTING,
-                           extensions::UNINSTALL_SOURCE_APP_LIST);
-
-  // Verify that a child dialog window has been added to the AppList as a child.
-  EXPECT_EQ(1, GetWindowCountForAppListContainer());
-}
-
-IN_PROC_BROWSER_TEST_F(ExtensionUninstallDialogViewBrowserTest,
-                       ParentWindowIsBrowser) {
-  scoped_refptr<const extensions::Extension> extension(BuildTestExtension());
-  extensions::ExtensionSystem::Get(browser()->profile())
-      ->extension_service()
-      ->AddExtension(extension.get());
-
-  // When the uninstall dialog is launched from a browser, the AppList should
-  // never be the parent.
-  EXPECT_EQ(0, GetWindowCountForAppListContainer());
-
-  // Open the extension uninstall dialog with a browser parent window. This is
-  // occurs when the dialog is opened from chrome://extensions rather than the
-  // launcher.
-  std::unique_ptr<extensions::ExtensionUninstallDialog> dialog;
-  dialog = extensions::ExtensionUninstallDialog::Create(
-      browser()->profile(), browser()->window()->GetNativeWindow(), nullptr);
-  dialog->ConfirmUninstall(extension.get(),
-                           extensions::UNINSTALL_REASON_FOR_TESTING,
-                           extensions::UNINSTALL_SOURCE_FOR_TESTING);
-
-  // Verify that the uninstall dialog is not parented to the AppList.
-  EXPECT_EQ(0, GetWindowCountForAppListContainer());
-}
-
 // Test that we don't crash when uninstalling an extension from a bookmark app
 // window in Ash. Context: crbug.com/825554
 IN_PROC_BROWSER_TEST_F(ExtensionUninstallDialogViewBrowserTest,
diff --git a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
index 93abbea..ca53bf0 100644
--- a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
+++ b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
@@ -311,8 +311,8 @@
   context_menu_runner_.reset(new views::MenuRunner(
       controller_->GetContextMenu(id),
       views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU,
-      base::Bind(&MediaGalleriesDialogViews::OnMenuClosed,
-                 base::Unretained(this))));
+      base::BindRepeating(&MediaGalleriesDialogViews::OnMenuClosed,
+                          base::Unretained(this))));
 
   context_menu_runner_->RunMenuAt(
       GetWidget(), NULL,
diff --git a/chrome/browser/ui/views/frame/browser_frame.cc b/chrome/browser/ui/views/frame/browser_frame.cc
index bba0a98..dbca6092a 100644
--- a/chrome/browser/ui/views/frame/browser_frame.cc
+++ b/chrome/browser/ui/views/frame/browser_frame.cc
@@ -248,7 +248,8 @@
     menu_runner_.reset(new views::MenuRunner(
         GetSystemMenuModel(),
         views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU,
-        base::Bind(&BrowserFrame::OnMenuClosed, base::Unretained(this))));
+        base::BindRepeating(&BrowserFrame::OnMenuClosed,
+                            base::Unretained(this))));
     menu_runner_->RunMenuAt(source->GetWidget(), nullptr,
                             gfx::Rect(p, gfx::Size(0, 0)),
                             views::MENU_ANCHOR_TOPLEFT, source_type);
diff --git a/chrome/browser/ui/views/tabs/glow_hover_controller.cc b/chrome/browser/ui/views/tabs/glow_hover_controller.cc
index 681db8d..e2d9e0b 100644
--- a/chrome/browser/ui/views/tabs/glow_hover_controller.cc
+++ b/chrome/browser/ui/views/tabs/glow_hover_controller.cc
@@ -40,15 +40,15 @@
   subtle_opacity_scale_ = opacity_scale;
 }
 
-void GlowHoverController::Show(ShowStyle style) {
+void GlowHoverController::Show(TabStyle::ShowHoverStyle style) {
   switch (style) {
-    case ShowStyle::kSubtle:
+    case TabStyle::ShowHoverStyle::kSubtle:
       opacity_scale_ = subtle_opacity_scale_;
       animation_.SetSlideDuration(kTrackHoverDurationMs);
       animation_.SetTweenType(gfx::Tween::EASE_OUT);
       animation_.Show();
       break;
-    case ShowStyle::kPronounced:
+    case TabStyle::ShowHoverStyle::kPronounced:
       opacity_scale_ = kPronouncedOpacityScale;
       // Force the end state to show immediately.
       animation_.Show();
@@ -57,13 +57,13 @@
   }
 }
 
-void GlowHoverController::Hide(HideStyle style) {
+void GlowHoverController::Hide(TabStyle::HideHoverStyle style) {
   switch (style) {
-    case HideStyle::kGradual:
+    case TabStyle::HideHoverStyle::kGradual:
       animation_.SetTweenType(gfx::Tween::EASE_IN);
       animation_.Hide();
       break;
-    case HideStyle::kImmediate:
+    case TabStyle::HideHoverStyle::kImmediate:
       if (ShouldDraw())
         view_->SchedulePaint();
       animation_.Reset();
diff --git a/chrome/browser/ui/views/tabs/glow_hover_controller.h b/chrome/browser/ui/views/tabs/glow_hover_controller.h
index d95b558..1890bc34 100644
--- a/chrome/browser/ui/views/tabs/glow_hover_controller.h
+++ b/chrome/browser/ui/views/tabs/glow_hover_controller.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_VIEWS_TABS_GLOW_HOVER_CONTROLLER_H_
 
 #include "base/macros.h"
+#include "chrome/browser/ui/tabs/tab_style.h"
 #include "ui/gfx/animation/animation_delegate.h"
 #include "ui/gfx/animation/slide_animation.h"
 
@@ -27,13 +28,6 @@
 // invokes SchedulePaint() back on the View as necessary.
 class GlowHoverController : public gfx::AnimationDelegate {
  public:
-  enum class ShowStyle { kSubtle, kPronounced };
-
-  enum class HideStyle {
-    kGradual,    // The hover should fade out.
-    kImmediate,  // The hover should cut off, with no fade out.
-  };
-
   explicit GlowHoverController(views::View* view);
   ~GlowHoverController() override;
 
@@ -50,10 +44,10 @@
   const gfx::Point& location() const { return location_; }
 
   // Initiates showing the hover.
-  void Show(ShowStyle style);
+  void Show(TabStyle::ShowHoverStyle style);
 
   // Hides the hover.
-  void Hide(HideStyle);
+  void Hide(TabStyle::HideHoverStyle style);
 
   // Returns the value of the animation.
   double GetAnimationValue() const;
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 3a3d939d8..a24bfa58 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -28,6 +28,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
+#include "chrome/browser/ui/tabs/tab_style.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
@@ -39,7 +40,7 @@
 #include "chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h"
 #include "chrome/browser/ui/views/tabs/tab_icon.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
-#include "chrome/browser/ui/views/tabs/tab_style.h"
+#include "chrome/browser/ui/views/tabs/tab_style_views.h"
 #include "chrome/browser/ui/views/touch_uma/touch_uma.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/grit/generated_resources.h"
@@ -121,7 +122,7 @@
       title_animation_(this) {
   DCHECK(controller);
 
-  tab_style_ = TabStyle::CreateForTab(this);
+  tab_style_ = TabStyleViews::CreateForTab(this);
 
   // So we get don't get enter/exit on children and don't prematurely stop the
   // hover.
@@ -483,7 +484,7 @@
 
 void Tab::OnMouseEntered(const ui::MouseEvent& event) {
   mouse_hovered_ = true;
-  tab_style_->ShowHover(GlowHoverController::ShowStyle::kSubtle);
+  tab_style_->ShowHover(TabStyle::ShowHoverStyle::kSubtle);
   UpdateForegroundColors();
   Layout();
   controller_->UpdateHoverCard(this, true);
@@ -491,7 +492,7 @@
 
 void Tab::OnMouseExited(const ui::MouseEvent& event) {
   mouse_hovered_ = false;
-  tab_style_->HideHover(GlowHoverController::HideStyle::kGradual);
+  tab_style_->HideHover(TabStyle::HideHoverStyle::kGradual);
   UpdateForegroundColors();
   Layout();
 }
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index 0320a31..25b0fce 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -28,7 +28,7 @@
 class TabCloseButton;
 class TabController;
 class TabIcon;
-class TabStyle;
+class TabStyleViews;
 
 namespace gfx {
 class Animation;
@@ -169,8 +169,8 @@
   bool mouse_hovered() const { return mouse_hovered_; }
 
   // Returns the TabStyle associated with this tab.
-  TabStyle* tab_style() { return tab_style_.get(); }
-  const TabStyle* tab_style() const { return tab_style_.get(); }
+  TabStyleViews* tab_style() { return tab_style_.get(); }
+  const TabStyleViews* tab_style() const { return tab_style_.get(); }
 
   // Returns the text to show in a tab's tooltip: The contents |title|, followed
   // by a break, followed by a localized string describing the |alert_state|.
@@ -214,7 +214,7 @@
 
   TabRendererData data_;
 
-  std::unique_ptr<TabStyle> tab_style_;
+  std::unique_ptr<TabStyleViews> tab_style_;
 
   // True if the tab is being animated closed.
   bool closing_ = false;
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 3b0474cc..b807bc6a 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -31,7 +31,7 @@
 #include "chrome/browser/ui/views/tabs/stacked_tab_strip_layout.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
-#include "chrome/browser/ui/views/tabs/tab_style.h"
+#include "chrome/browser/ui/views/tabs/tab_style_views.h"
 #include "chrome/browser/ui/views/tabs/window_finder.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
index 212ed4e..b269f06 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
@@ -9,10 +9,10 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_features.h"
+#include "chrome/browser/ui/tabs/tab_style.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
 #include "chrome/browser/ui/views/tabs/tab_renderer_data.h"
-#include "chrome/browser/ui/views/tabs/tab_style.h"
 #include "components/url_formatter/url_formatter.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/views/bubble/bubble_frame_view.h"
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index f1b44cb..b1d00fbc 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -39,7 +39,7 @@
 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_layout.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_observer.h"
-#include "chrome/browser/ui/views/tabs/tab_style.h"
+#include "chrome/browser/ui/views/tabs/tab_style_views.h"
 #include "chrome/browser/ui/views/touch_uma/touch_uma.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
@@ -205,8 +205,8 @@
   TabSizeInfo* info = MD::touch_ui() ? &touch_tab_size_info : &tab_size_info;
   if (info->standard_size.IsEmpty()) {
     info->pinned_tab_width = TabStyle::GetPinnedWidth();
-    info->min_active_width = TabStyle::GetMinimumActiveWidth();
-    info->min_inactive_width = TabStyle::GetMinimumInactiveWidth();
+    info->min_active_width = TabStyleViews::GetMinimumActiveWidth();
+    info->min_inactive_width = TabStyleViews::GetMinimumInactiveWidth();
     info->standard_size =
         gfx::Size(TabStyle::GetStandardWidth(), GetLayoutConstant(TAB_HEIGHT));
     info->tab_overlap = TabStyle::GetTabOverlap();
@@ -1482,8 +1482,8 @@
     const int pinned_tab_count = GetPinnedTabCount();
     needed_tab_width = pinned_tab_count * TabStyle::GetPinnedWidth();
     const int remaining_tab_count = tab_count() - pinned_tab_count;
-    const int min_selected_width = TabStyle::GetMinimumActiveWidth();
-    const int min_unselected_width = TabStyle::GetMinimumInactiveWidth();
+    const int min_selected_width = TabStyleViews::GetMinimumActiveWidth();
+    const int min_unselected_width = TabStyleViews::GetMinimumInactiveWidth();
     if (remaining_tab_count > 0) {
       needed_tab_width += min_selected_width +
                           ((remaining_tab_count - 1) * min_unselected_width);
diff --git a/chrome/browser/ui/views/tabs/tab_strip_unittest.cc b/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
index 6529caf..a106daa7 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
@@ -17,7 +17,7 @@
 #include "chrome/browser/ui/views/tabs/tab_renderer_data.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_observer.h"
-#include "chrome/browser/ui/views/tabs/tab_style.h"
+#include "chrome/browser/ui/views/tabs/tab_style_views.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/views/chrome_views_test_base.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -779,7 +779,7 @@
   tab_strip_->SetBounds(0, 0, 200, 20);
 
   // Create a lot of tabs in order to make inactive tabs tiny.
-  const int min_inactive_width = TabStyle::GetMinimumInactiveWidth();
+  const int min_inactive_width = TabStyleViews::GetMinimumInactiveWidth();
   while (current_inactive_width() != min_inactive_width)
     controller_->CreateNewTab();
 
@@ -792,7 +792,7 @@
   // During mouse-based tab closure, the active tab should remain at least as
   // wide as it's minium width.
   controller_->SelectTab(0, dummy_event_);
-  for (const int min_active_width = TabStyle::GetMinimumActiveWidth();
+  for (const int min_active_width = TabStyleViews::GetMinimumActiveWidth();
        tab_strip_->tab_count();) {
     const int active_index = controller_->GetActiveIndex();
     EXPECT_GE(tab_strip_->ideal_bounds(active_index).width(), min_active_width);
@@ -808,8 +808,8 @@
 
   // Create a lot of tabs in order to make inactive tabs smaller than active
   // tab but not the minimum.
-  const int min_inactive_width = TabStyle::GetMinimumInactiveWidth();
-  const int min_active_width = TabStyle::GetMinimumActiveWidth();
+  const int min_inactive_width = TabStyleViews::GetMinimumInactiveWidth();
+  const int min_active_width = TabStyleViews::GetMinimumActiveWidth();
   while (current_inactive_width() >=
          (min_inactive_width + min_active_width) / 2)
     controller_->CreateNewTab();
@@ -831,11 +831,11 @@
   tab_strip_->SetBounds(0, 0, 200, 20);
 
   // Create a lot of tabs in order to make inactive tabs tiny.
-  const int min_inactive_width = TabStyle::GetMinimumInactiveWidth();
+  const int min_inactive_width = TabStyleViews::GetMinimumInactiveWidth();
   while (current_inactive_width() != min_inactive_width)
     controller_->CreateNewTab();
 
-  const int min_active_width = TabStyle::GetMinimumActiveWidth();
+  const int min_active_width = TabStyleViews::GetMinimumActiveWidth();
 
   int dragged_tab_index = controller_->GetActiveIndex();
   EXPECT_GE(tab_strip_->ideal_bounds(dragged_tab_index).width(),
diff --git a/chrome/browser/ui/views/tabs/tab_style.cc b/chrome/browser/ui/views/tabs/tab_style_views.cc
similarity index 93%
rename from chrome/browser/ui/views/tabs/tab_style.cc
rename to chrome/browser/ui/views/tabs/tab_style_views.cc
index 7aaac14f7..f6c4165 100644
--- a/chrome/browser/ui/views/tabs/tab_style.cc
+++ b/chrome/browser/ui/views/tabs/tab_style_views.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/views/tabs/tab_style.h"
+#include "chrome/browser/ui/views/tabs/tab_style_views.h"
 
 #include <algorithm>
 #include <utility>
@@ -11,7 +11,6 @@
 #include "cc/paint/paint_record.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/layout_constants.h"
-#include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/tabs/glow_hover_controller.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
 #include "chrome/browser/ui/views/tabs/tab_close_button.h"
@@ -19,7 +18,6 @@
 #include "chrome/grit/theme_resources.h"
 #include "third_party/skia/include/core/SkScalar.h"
 #include "third_party/skia/include/pathops/SkPathOps.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/theme_provider.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/scoped_canvas.h"
@@ -72,7 +70,7 @@
 };
 
 // Tab style implementation for the GM2 refresh (Chrome 69).
-class GM2TabStyle : public TabStyle {
+class GM2TabStyle : public TabStyleViews {
  public:
   explicit GM2TabStyle(Tab* tab);
 
@@ -88,8 +86,8 @@
   TabStyle::TabColors CalculateColors() const override;
   void PaintTab(gfx::Canvas* canvas, const SkPath& clip) const override;
   void SetHoverLocation(const gfx::Point& location) override;
-  void ShowHover(GlowHoverController::ShowStyle style) override;
-  void HideHover(GlowHoverController::HideStyle style) override;
+  void ShowHover(ShowHoverStyle style) override;
+  void HideHover(HideHoverStyle style) override;
 
  private:
   // Gets the bounds for the leading and trailing separators for a tab.
@@ -162,27 +160,6 @@
   DISALLOW_COPY_AND_ASSIGN(GM2TabStyle);
 };
 
-// Thickness in DIPs of the separator painted on the left and right edges of
-// the tab.
-constexpr int kSeparatorThickness = 1;
-
-// Returns the radius of the outer corners of the tab shape.
-int GetCornerRadius() {
-  return ChromeLayoutProvider::Get()->GetCornerRadiusMetric(
-      views::EMPHASIS_HIGH);
-}
-
-// Returns how far from the leading and trailing edges of a tab the contents
-// should actually be laid out.
-int GetContentsHorizontalInsetSize() {
-  return GetCornerRadius() * 2;
-}
-
-// Returns the height of the separator between tabs.
-int GetSeparatorHeight() {
-  return ui::MaterialDesignController::touch_ui() ? 24 : 20;
-}
-
 void DrawHighlight(gfx::Canvas* canvas,
                    const SkPoint& p,
                    SkScalar radius,
@@ -551,18 +528,18 @@
     hover_controller_->SetLocation(location);
 }
 
-void GM2TabStyle::ShowHover(GlowHoverController::ShowStyle style) {
+void GM2TabStyle::ShowHover(ShowHoverStyle style) {
   if (!hover_controller_)
     return;
 
-  if (style == GlowHoverController::ShowStyle::kSubtle) {
+  if (style == ShowHoverStyle::kSubtle) {
     hover_controller_->SetSubtleOpacityScale(
         tab_->controller()->GetHoverOpacityForRadialHighlight());
   }
   hover_controller_->Show(style);
 }
 
-void GM2TabStyle::HideHover(GlowHoverController::HideStyle style) {
+void GM2TabStyle::HideHover(HideHoverStyle style) {
   if (hover_controller_)
     hover_controller_->Hide(style);
 }
@@ -925,7 +902,7 @@
   // bottom inset, because we want to pixel-align the bottom of the stroke, not
   // the bottom of the overlap.
   gfx::InsetsF layout_insets(stroke_thickness, corner_radius, stroke_thickness,
-                             corner_radius + kSeparatorThickness);
+                             corner_radius + GetSeparatorSize().width());
   aligned_bounds.Inset(layout_insets);
 
   // Scale layout bounds from DIP to px.
@@ -950,58 +927,24 @@
 
 // TabStyle --------------------------------------------------------------------
 
-TabStyle::~TabStyle() = default;
+TabStyleViews::~TabStyleViews() = default;
 
 // static
-std::unique_ptr<TabStyle> TabStyle::CreateForTab(Tab* tab) {
+std::unique_ptr<TabStyleViews> TabStyleViews::CreateForTab(Tab* tab) {
   return std::make_unique<GM2TabStyle>(tab);
 }
 
 // static
-int TabStyle::GetMinimumActiveWidth() {
+int TabStyleViews::GetMinimumActiveWidth() {
   return TabCloseButton::GetWidth() + GetContentsHorizontalInsetSize() * 2;
 }
 
 // static
-int TabStyle::GetMinimumInactiveWidth() {
+int TabStyleViews::GetMinimumInactiveWidth() {
   // Allow tabs to shrink until they appear to be 16 DIP wide excluding
   // outer corners.
   constexpr int kInteriorWidth = 16;
   // The overlap contains the trailing separator that is part of the interior
   // width; avoid double-counting it.
-  return kInteriorWidth - kSeparatorThickness + GetTabOverlap();
-}
-
-// static
-int TabStyle::GetStandardWidth() {
-  // The standard tab width is 240 DIP including both separators.
-  constexpr int kTabWidth = 240;
-  // The overlap includes one separator, so subtract it here.
-  return kTabWidth + GetTabOverlap() - kSeparatorThickness;
-}
-
-// static
-int TabStyle::GetPinnedWidth() {
-  constexpr int kTabPinnedContentWidth = 23;
-  return kTabPinnedContentWidth + GetContentsHorizontalInsetSize() * 2;
-}
-
-// static
-int TabStyle::GetTabOverlap() {
-  return GetCornerRadius() * 2 + kSeparatorThickness;
-}
-
-// static
-int TabStyle::GetDragHandleExtension(int height) {
-  return (height - GetSeparatorHeight()) / 2 - 1;
-}
-
-// static
-gfx::Insets TabStyle::GetTabInternalPadding() {
-  return gfx::Insets(0, GetCornerRadius());
-}
-
-// static
-gfx::Size TabStyle::GetSeparatorSize() {
-  return gfx::Size(kSeparatorThickness, GetSeparatorHeight());
+  return kInteriorWidth - GetSeparatorSize().width() + GetTabOverlap();
 }
diff --git a/chrome/browser/ui/views/tabs/tab_style_views.h b/chrome/browser/ui/views/tabs/tab_style_views.h
new file mode 100644
index 0000000..ea5b9f6c
--- /dev/null
+++ b/chrome/browser/ui/views/tabs/tab_style_views.h
@@ -0,0 +1,38 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_STYLE_VIEWS_H_
+#define CHROME_BROWSER_UI_VIEWS_TABS_TAB_STYLE_VIEWS_H_
+
+#include <memory>
+
+#include "chrome/browser/ui/tabs/tab_style.h"
+#include "chrome/browser/ui/views/tabs/glow_hover_controller.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+class Tab;
+
+// Holds Views-specific logic for rendering and sizing tabs.
+class TabStyleViews : public TabStyle {
+ public:
+  // Factory function allows to experiment with different variations on tab
+  // style at runtime or via flag.
+  static std::unique_ptr<TabStyleViews> CreateForTab(Tab* tab);
+
+  ~TabStyleViews() override;
+
+  // Returns the minimum possible width of a selected Tab. Selected tabs must
+  // always show a close button, and thus have a larger minimum size than
+  // unselected tabs.
+  static int GetMinimumActiveWidth();
+
+  // Returns the minimum possible width of a single unselected Tab.
+  static int GetMinimumInactiveWidth();
+
+ protected:
+  // Avoid implicitly-deleted constructor.
+  TabStyleViews() = default;
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_TABS_TAB_STYLE_VIEWS_H_
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc
index d20db95..7b86a69 100644
--- a/chrome/browser/ui/views/tabs/tab_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -19,7 +19,7 @@
 #include "chrome/browser/ui/views/tabs/tab_controller.h"
 #include "chrome/browser/ui/views/tabs/tab_icon.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
-#include "chrome/browser/ui/views/tabs/tab_style.h"
+#include "chrome/browser/ui/views/tabs/tab_style_views.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/grit/theme_resources.h"
 #include "chrome/test/views/chrome_views_test_base.h"
@@ -461,8 +461,8 @@
           width = min_width = TabStyle::GetPinnedWidth();
         } else {
           width = TabStyle::GetStandardWidth();
-          min_width = is_active_tab ? TabStyle::GetMinimumActiveWidth()
-                                    : TabStyle::GetMinimumInactiveWidth();
+          min_width = is_active_tab ? TabStyleViews::GetMinimumActiveWidth()
+                                    : TabStyleViews::GetMinimumInactiveWidth();
         }
         const int height = GetLayoutConstant(TAB_HEIGHT);
         for (; width >= min_width; --width) {
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
index f679c65..f51401b 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
@@ -343,8 +343,8 @@
   // menu. Any action that would lead to the deletion of |this| first triggers
   // the closing of the menu through lost capture.
   menu_adapter_.reset(new views::MenuModelAdapter(
-      context_menu_model,
-      base::Bind(&ToolbarActionView::OnMenuClosed, base::Unretained(this))));
+      context_menu_model, base::BindRepeating(&ToolbarActionView::OnMenuClosed,
+                                              base::Unretained(this))));
   menu_ = menu_adapter_->CreateMenu();
   menu_runner_.reset(new views::MenuRunner(menu_, run_types));
 
diff --git a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc
index 8b46908..4015441 100644
--- a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc
@@ -35,6 +35,16 @@
     screen_->OnViewDestroyed(this);
 }
 
+void ResetScreenHandler::Bind(ResetScreen* screen) {
+  screen_ = screen;
+  BaseScreenHandler::SetBaseScreen(screen_);
+}
+
+void ResetScreenHandler::Unbind() {
+  screen_ = nullptr;
+  BaseScreenHandler::SetBaseScreen(nullptr);
+}
+
 void ResetScreenHandler::Show() {
   if (!page_is_ready()) {
     show_on_init_ = true;
@@ -94,6 +104,11 @@
   builder->Add("confirmResetButton", IDS_RESET_SCREEN_POPUP_CONFIRM_BUTTON);
 }
 
+void ResetScreenHandler::DeclareJSCallbacks() {
+  AddCallback("ResetScreen.setTpmFirmwareUpdateChecked",
+              &ResetScreenHandler::HandleSetTpmFirmwareUpdateChecked);
+}
+
 void ResetScreenHandler::Initialize() {
   if (!page_is_ready())
     return;
@@ -104,14 +119,70 @@
   }
 }
 
-void ResetScreenHandler::Bind(ResetScreen* screen) {
-  screen_ = screen;
-  BaseScreenHandler::SetBaseScreen(screen_);
+void ResetScreenHandler::SetIsRollbackAvailable(bool value) {
+  is_rollback_available_ = value;
+  CallJS("login.ResetScreen.setIsRollbackAvailable", value);
 }
 
-void ResetScreenHandler::Unbind() {
-  screen_ = nullptr;
-  BaseScreenHandler::SetBaseScreen(nullptr);
+void ResetScreenHandler::SetIsRollbackChecked(bool value) {
+  is_rollback_checked_ = value;
+  CallJS("login.ResetScreen.setIsRollbackChecked", value);
+}
+
+void ResetScreenHandler::SetIsTpmFirmwareUpdateAvailable(bool value) {
+  CallJS("login.ResetScreen.setIsTpmFirmwareUpdateAvailable", value);
+}
+
+void ResetScreenHandler::SetIsTpmFirmwareUpdateChecked(bool value) {
+  is_tpm_firmware_update_checked_ = value;
+  CallJS("login.ResetScreen.setIsTpmFirmwareUpdateChecked", value);
+}
+
+void ResetScreenHandler::SetIsTpmFirmwareUpdateEditable(bool value) {
+  CallJS("login.ResetScreen.setIsTpmFirmwareUpdateEditable", value);
+}
+
+void ResetScreenHandler::SetTpmFirmwareUpdateMode(
+    tpm_firmware_update::Mode value) {
+  mode_ = value;
+  CallJS("login.ResetScreen.setTpmFirmwareUpdateMode", static_cast<int>(value));
+}
+
+void ResetScreenHandler::SetIsConfirmational(bool value) {
+  CallJS("login.ResetScreen.setIsConfirmational", value);
+}
+
+void ResetScreenHandler::SetIsOfficialBuild(bool value) {
+  CallJS("login.ResetScreen.setIsOfficialBuild", value);
+}
+
+void ResetScreenHandler::SetScreenState(State value) {
+  state_ = value;
+  CallJS("login.ResetScreen.setScreenState", static_cast<int>(value));
+}
+
+ResetView::State ResetScreenHandler::GetScreenState() {
+  return state_;
+}
+
+tpm_firmware_update::Mode ResetScreenHandler::GetTpmFirmwareUpdateMode() {
+  return mode_;
+}
+
+bool ResetScreenHandler::GetIsRollbackAvailable() {
+  return is_rollback_available_;
+}
+
+bool ResetScreenHandler::GetIsRollbackChecked() {
+  return is_rollback_checked_;
+}
+
+bool ResetScreenHandler::GetIsTpmFirmwareUpdateChecked() {
+  return is_tpm_firmware_update_checked_;
+}
+
+void ResetScreenHandler::HandleSetTpmFirmwareUpdateChecked(bool value) {
+  is_tpm_firmware_update_checked_ = value;
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h
index f69d5b2c..e23e06bf 100644
--- a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h
@@ -8,6 +8,7 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "chrome/browser/chromeos/login/screens/reset_view.h"
+#include "chrome/browser/chromeos/tpm_firmware_update.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 #include "content/public/browser/web_ui.h"
 
@@ -29,14 +30,37 @@
   // BaseScreenHandler implementation:
   void DeclareLocalizedValues(
       ::login::LocalizedValuesBuilder* builder) override;
+  void DeclareJSCallbacks() override;
   void Initialize() override;
+  void SetIsRollbackAvailable(bool value) override;
+  void SetIsRollbackChecked(bool value) override;
+  void SetIsTpmFirmwareUpdateAvailable(bool value) override;
+  void SetIsTpmFirmwareUpdateChecked(bool value) override;
+  void SetIsTpmFirmwareUpdateEditable(bool value) override;
+  void SetTpmFirmwareUpdateMode(tpm_firmware_update::Mode value) override;
+  void SetIsConfirmational(bool value) override;
+  void SetIsOfficialBuild(bool value) override;
+  void SetScreenState(State value) override;
+  State GetScreenState() override;
+  tpm_firmware_update::Mode GetTpmFirmwareUpdateMode() override;
+  bool GetIsRollbackAvailable() override;
+  bool GetIsRollbackChecked() override;
+  bool GetIsTpmFirmwareUpdateChecked() override;
 
  private:
+  void HandleSetTpmFirmwareUpdateChecked(bool value);
+
   ResetScreen* screen_ = nullptr;
 
   // If true, Initialize() will call Show().
   bool show_on_init_ = false;
 
+  ResetView::State state_ = ResetView::State::kRestartRequired;
+  tpm_firmware_update::Mode mode_ = tpm_firmware_update::Mode::kNone;
+  bool is_rollback_available_ = false;
+  bool is_rollback_checked_ = false;
+  bool is_tpm_firmware_update_checked_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(ResetScreenHandler);
 };
 
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.cc b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
index 5026d255..3c3885bc 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_ui.cc
+++ b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
@@ -8,10 +8,12 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/feature_list.h"
 #include "base/i18n/rtl.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
+#include "chrome/browser/browser_features.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h"
 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
@@ -29,6 +31,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/native_theme/native_theme.h"
 #include "url/gurl.h"
 
 namespace {
@@ -50,7 +53,11 @@
 ///////////////////////////////////////////////////////////////////////////////
 // NewTabUI
 
-NewTabUI::NewTabUI(content::WebUI* web_ui) : content::WebUIController(web_ui) {
+NewTabUI::NewTabUI(content::WebUI* web_ui)
+    : content::WebUIController(web_ui),
+      dark_mode_observer_(ui::NativeTheme::GetInstanceForNativeUi(),
+                          base::BindRepeating(&NewTabUI::OnDarkModeChanged,
+                                              base::Unretained(this))) {
   web_ui->OverrideTitle(l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE));
 
   Profile* profile = GetProfile();
@@ -69,6 +76,8 @@
   pref_change_registrar_.Add(
       prefs::kWebKitDefaultFontSize,
       base::Bind(&NewTabUI::OnDefaultFontSizeChanged, base::Unretained(this)));
+
+  dark_mode_observer_.Start();
 }
 
 NewTabUI::~NewTabUI() {}
@@ -82,6 +91,16 @@
                                          attached);
 }
 
+void NewTabUI::OnDarkModeChanged(bool /*dark_mode*/) {
+  if (!web_ui() || !web_ui()->CanCallJavascript())
+    return;
+
+  bool enabled = base::FeatureList::IsEnabled(features::kWebUIDarkMode);
+  web_ui()->CallJavascriptFunctionUnsafe(
+      "document.documentElement.toggleAttribute", base::Value("dark"),
+      base::Value(enabled && dark_mode_observer_.InDarkMode()));
+}
+
 void NewTabUI::OnDefaultFontSizeChanged() {
   web_ui()->CallJavascriptFunctionUnsafe("ntp.defaultFontSizeChanged");
 }
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.h b/chrome/browser/ui/webui/ntp/new_tab_ui.h
index e3bf3c65..f5e776d 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_ui.h
+++ b/chrome/browser/ui/webui/ntp/new_tab_ui.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "base/strings/string16.h"
+#include "chrome/browser/ui/dark_mode_observer.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "content/public/browser/url_data_source.h"
 #include "content/public/browser/web_ui_controller.h"
@@ -73,11 +74,14 @@
     DISALLOW_COPY_AND_ASSIGN(NewTabHTMLSource);
   };
 
-  void OnShowBookmarkBarChanged();
+  void OnDarkModeChanged(bool dark_mode);
   void OnDefaultFontSizeChanged();
+  void OnShowBookmarkBarChanged();
 
   Profile* GetProfile() const;
 
+  DarkModeObserver dark_mode_observer_;
+
   PrefChangeRegistrar pref_change_registrar_;
 
   DISALLOW_COPY_AND_ASSIGN(NewTabUI);
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
index dab1b70..6d373f6 100644
--- a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
+++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
@@ -11,6 +11,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/task/post_task.h"
 #include "base/values.h"
@@ -92,17 +93,46 @@
 
 LocalPrinterHandlerChromeos::LocalPrinterHandlerChromeos(
     Profile* profile,
-    content::WebContents* preview_web_contents)
+    content::WebContents* preview_web_contents,
+    chromeos::CupsPrintersManager* printers_manager,
+    std::unique_ptr<chromeos::PrinterConfigurer> printer_configurer)
     : profile_(profile),
       preview_web_contents_(preview_web_contents),
-      printers_manager_(
-          CupsPrintersManagerFactory::GetForBrowserContext(profile)),
-      printer_configurer_(chromeos::PrinterConfigurer::Create(profile)),
+      printers_manager_(printers_manager),
+      printer_configurer_(std::move(printer_configurer)),
       weak_factory_(this) {
   // Construct the CupsPrintJobManager to listen for printing events.
   chromeos::CupsPrintJobManagerFactory::GetForBrowserContext(profile);
 }
 
+// static
+std::unique_ptr<LocalPrinterHandlerChromeos>
+LocalPrinterHandlerChromeos::CreateDefault(
+    Profile* profile,
+    content::WebContents* preview_web_contents) {
+  chromeos::CupsPrintersManager* printers_manager(
+      CupsPrintersManagerFactory::GetForBrowserContext(profile));
+  std::unique_ptr<chromeos::PrinterConfigurer> printer_configurer(
+      chromeos::PrinterConfigurer::Create(profile));
+  // Using 'new' to access non-public constructor.
+  return base::WrapUnique(new LocalPrinterHandlerChromeos(
+      profile, preview_web_contents, printers_manager,
+      std::move(printer_configurer)));
+}
+
+// static
+std::unique_ptr<LocalPrinterHandlerChromeos>
+LocalPrinterHandlerChromeos::CreateForTesting(
+    Profile* profile,
+    content::WebContents* preview_web_contents,
+    chromeos::CupsPrintersManager* printers_manager,
+    std::unique_ptr<chromeos::PrinterConfigurer> printer_configurer) {
+  // Using 'new' to access non-public constructor.
+  return base::WrapUnique(new LocalPrinterHandlerChromeos(
+      profile, preview_web_contents, printers_manager,
+      std::move(printer_configurer)));
+}
+
 LocalPrinterHandlerChromeos::~LocalPrinterHandlerChromeos() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 }
@@ -185,27 +215,9 @@
       VLOG(1) << "Printer setup successful for " << printer->id()
               << " fetching properties";
       printers_manager_->PrinterInstalled(*printer, true /*is_automatic*/);
-
-      // populate |policies| with policies for native printers.
-      base::Value policies(base::Value::Type::DICTIONARY);
-      const PrefService* prefs = profile_->GetPrefs();
-      policies.SetKey(
-          kAllowedColorModes,
-          base::Value(prefs->GetInteger(prefs::kPrintingAllowedColorModes)));
-      policies.SetKey(
-          kAllowedDuplexModes,
-          base::Value(prefs->GetInteger(prefs::kPrintingAllowedDuplexModes)));
-      policies.SetKey(
-          kAllowedPinModes,
-          base::Value(prefs->GetInteger(prefs::kPrintingAllowedPinModes)));
-      policies.SetKey(kDefaultColorMode,
-                      base::Value(prefs->Get(prefs::kPrintingColorDefault)));
-      policies.SetKey(kDefaultDuplexMode,
-                      base::Value(prefs->Get(prefs::kPrintingDuplexDefault)));
-      policies.SetKey(kDefaultPinMode,
-                      base::Value(prefs->Get(prefs::kPrintingPinDefault)));
       // fetch settings on the blocking pool and invoke callback.
-      FetchCapabilities(std::move(printer), std::move(policies), std::move(cb));
+      FetchCapabilities(std::move(printer), GetNativePrinterPolicies(),
+                        std::move(cb));
       return;
     }
     case chromeos::PrinterSetupResult::kPpdNotFound:
@@ -258,4 +270,25 @@
                   preview_web_contents_, std::move(callback));
 }
 
+base::Value LocalPrinterHandlerChromeos::GetNativePrinterPolicies() const {
+  base::Value policies(base::Value::Type::DICTIONARY);
+  const PrefService* prefs = profile_->GetPrefs();
+  policies.SetKey(
+      kAllowedColorModes,
+      base::Value(prefs->GetInteger(prefs::kPrintingAllowedColorModes)));
+  policies.SetKey(
+      kAllowedDuplexModes,
+      base::Value(prefs->GetInteger(prefs::kPrintingAllowedDuplexModes)));
+  policies.SetKey(
+      kAllowedPinModes,
+      base::Value(prefs->GetInteger(prefs::kPrintingAllowedPinModes)));
+  policies.SetKey(kDefaultColorMode,
+                  base::Value(prefs->Get(prefs::kPrintingColorDefault)));
+  policies.SetKey(kDefaultDuplexMode,
+                  base::Value(prefs->Get(prefs::kPrintingDuplexDefault)));
+  policies.SetKey(kDefaultPinMode,
+                  base::Value(prefs->Get(prefs::kPrintingPinDefault)));
+  return policies;
+}
+
 }  // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.h b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.h
index de085a0d..fe9fea9 100644
--- a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.h
+++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.h
@@ -27,8 +27,16 @@
 
 class LocalPrinterHandlerChromeos : public PrinterHandler {
  public:
-  LocalPrinterHandlerChromeos(Profile* profile,
-                              content::WebContents* preview_web_contents);
+  static std::unique_ptr<LocalPrinterHandlerChromeos> CreateDefault(
+      Profile* profile,
+      content::WebContents* preview_web_contents);
+
+  static std::unique_ptr<LocalPrinterHandlerChromeos> CreateForTesting(
+      Profile* profile,
+      content::WebContents* preview_web_contents,
+      chromeos::CupsPrintersManager* printers_manager,
+      std::unique_ptr<chromeos::PrinterConfigurer> printer_configurer);
+
   ~LocalPrinterHandlerChromeos() override;
 
   // PrinterHandler implementation
@@ -44,6 +52,16 @@
                   PrintCallback callback) override;
 
  private:
+  explicit LocalPrinterHandlerChromeos(
+      Profile* profile,
+      content::WebContents* preview_web_contents,
+      chromeos::CupsPrintersManager* printers_manager,
+      std::unique_ptr<chromeos::PrinterConfigurer> printer_configurer);
+
+  // Creates a value dictionary containing the printing policies set by
+  // |profile_|.
+  base::Value GetNativePrinterPolicies() const;
+
   void HandlePrinterSetup(std::unique_ptr<chromeos::Printer> printer,
                           GetCapabilityCallback cb,
                           chromeos::PrinterSetupResult result);
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos_unittest.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos_unittest.cc
new file mode 100644
index 0000000..de450a08
--- /dev/null
+++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos_unittest.cc
@@ -0,0 +1,293 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc"
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/containers/flat_set.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/memory/ref_counted.h"
+#include "base/values.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "printing/backend/print_backend.h"
+#include "printing/backend/test_print_backend.h"
+#include "printing/print_job_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace printing {
+
+namespace {
+
+using chromeos::CupsPrintersManager;
+using chromeos::Printer;
+using chromeos::PrinterConfigurer;
+using chromeos::PrinterSetupCallback;
+using chromeos::PrinterSetupResult;
+
+// Used as a callback to StartGetPrinters in tests.
+// Increases |*call_count| and records values returned by StartGetPrinters.
+void RecordPrinterList(size_t* call_count,
+                       std::unique_ptr<base::ListValue>* printers_out,
+                       const base::ListValue& printers) {
+  ++(*call_count);
+  printers_out->reset(printers.DeepCopy());
+}
+
+// Used as a callback to StartGetPrinters in tests.
+// Records that the test is done.
+void RecordPrintersDone(bool* is_done_out) {
+  *is_done_out = true;
+}
+
+void RecordGetCapability(std::unique_ptr<base::Value>* capabilities_out,
+                         base::Value capability) {
+  capabilities_out->reset(capability.DeepCopy());
+}
+
+Printer CreateTestPrinter(const std::string& id, const std::string& name) {
+  Printer printer;
+  printer.set_id(id);
+  printer.set_display_name(name);
+  return printer;
+}
+
+Printer CreateEnterprisePrinter(const std::string& id,
+                                const std::string& name) {
+  Printer printer = CreateTestPrinter(id, name);
+  printer.set_source(Printer::SRC_POLICY);
+  return printer;
+}
+
+class FakeCupsPrintersManager : public CupsPrintersManager {
+ public:
+  FakeCupsPrintersManager() : printers_(kNumPrinterClasses) {}
+
+  std::vector<Printer> GetPrinters(PrinterClass printer_class) const override {
+    return printers_[printer_class];
+  }
+
+  void RemoveUnavailablePrinters(std::vector<Printer>*) const override {}
+  void UpdateConfiguredPrinter(const Printer& printer) override {}
+  void RemoveConfiguredPrinter(const std::string& printer_id) override {}
+  void AddObserver(CupsPrintersManager::Observer* observer) override {}
+  void RemoveObserver(CupsPrintersManager::Observer* observer) override {}
+  void PrinterInstalled(const Printer& printer, bool is_automatic) override {}
+  void RecordSetupAbandoned(const Printer& printer) override {}
+
+  bool IsPrinterInstalled(const Printer& printer) const override {
+    return installed_.contains(printer.id());
+  }
+
+  std::unique_ptr<Printer> GetPrinter(const std::string& id) const override {
+    for (const std::vector<Printer>& v : printers_) {
+      auto iter = std::find_if(
+          v.begin(), v.end(), [&id](const Printer& p) { return p.id() == id; });
+      if (iter != v.end()) {
+        return std::make_unique<Printer>(*iter);
+      }
+    }
+    return nullptr;
+  }
+
+  // Add |printer| to the corresponding list in |printers_| bases on the given
+  // |printer_class|.
+  void AddPrinter(const Printer& printer, PrinterClass printer_class) {
+    ASSERT_LT(printer_class, printers_.size());
+    printers_[printer_class].push_back(printer);
+  }
+
+  void InstallPrinter(const std::string& id) { installed_.insert(id); }
+
+ private:
+  std::vector<std::vector<Printer>> printers_;
+  base::flat_set<std::string> installed_;
+};
+
+class FakePrinterConfigurer : public PrinterConfigurer {
+ public:
+  void SetUpPrinter(const Printer& printer,
+                    PrinterSetupCallback callback) override {
+    std::move(callback).Run(PrinterSetupResult::kSuccess);
+  }
+};
+
+// Converts JSON string to base::ListValue object.
+// On failure, returns NULL and fills |*error| string.
+std::unique_ptr<base::ListValue> GetJSONAsListValue(const std::string& json,
+                                                    std::string* error) {
+  auto ret = base::ListValue::From(
+      JSONStringValueDeserializer(json).Deserialize(nullptr, error));
+  if (!ret)
+    *error = "Value is not a list.";
+  return ret;
+}
+
+}  // namespace
+
+class LocalPrinterHandlerChromeosTest : public testing::Test {
+ public:
+  LocalPrinterHandlerChromeosTest() = default;
+  ~LocalPrinterHandlerChromeosTest() override = default;
+
+  void SetUp() override {
+    test_backend_ = base::MakeRefCounted<TestPrintBackend>();
+    PrintBackend::SetPrintBackendForTesting(test_backend_.get());
+    local_printer_handler_ = LocalPrinterHandlerChromeos::CreateForTesting(
+        &profile_, nullptr, &printers_manager_,
+        std::make_unique<FakePrinterConfigurer>());
+  }
+
+ protected:
+  // Must outlive |profile_|.
+  content::TestBrowserThreadBundle thread_bundle_;
+  // Must outlive |printers_manager_|.
+  TestingProfile profile_;
+  scoped_refptr<TestPrintBackend> test_backend_;
+  FakeCupsPrintersManager printers_manager_;
+  std::unique_ptr<LocalPrinterHandlerChromeos> local_printer_handler_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LocalPrinterHandlerChromeosTest);
+};
+
+TEST_F(LocalPrinterHandlerChromeosTest, GetPrinters) {
+  size_t call_count = 0;
+  std::unique_ptr<base::ListValue> printers;
+  bool is_done = false;
+
+  Printer configured_printer = CreateTestPrinter("printer1", "configured");
+  Printer enterprise_printer =
+      CreateEnterprisePrinter("printer2", "enterprise");
+  Printer automatic_printer = CreateTestPrinter("printer3", "automatic");
+
+  printers_manager_.AddPrinter(configured_printer,
+                               CupsPrintersManager::kConfigured);
+  printers_manager_.AddPrinter(enterprise_printer,
+                               CupsPrintersManager::kEnterprise);
+  printers_manager_.AddPrinter(automatic_printer,
+                               CupsPrintersManager::kAutomatic);
+
+  local_printer_handler_->StartGetPrinters(
+      base::BindRepeating(&RecordPrinterList, &call_count, &printers),
+      base::BindOnce(&RecordPrintersDone, &is_done));
+
+  EXPECT_EQ(call_count, 1u);
+  EXPECT_TRUE(is_done);
+  ASSERT_TRUE(printers);
+
+  const std::string expected_list = R"(
+    [
+      {
+        "cupsEnterprisePrinter": false,
+        "deviceName": "printer1",
+        "printerDescription": "",
+        "printerName": "configured",
+        "printerOptions": {
+          "cupsEnterprisePrinter": "false",
+          "system_driverinfo": ""
+        }
+      },
+      {
+        "cupsEnterprisePrinter": true,
+        "deviceName": "printer2",
+        "printerDescription": "",
+        "printerName": "enterprise",
+        "printerOptions": {
+          "cupsEnterprisePrinter": "true",
+          "system_driverinfo": ""
+        }
+      },
+      {
+        "cupsEnterprisePrinter": false,
+        "deviceName": "printer3",
+        "printerDescription": "",
+        "printerName": "automatic",
+        "printerOptions": {
+          "cupsEnterprisePrinter": "false",
+          "system_driverinfo": ""
+        }
+      }
+    ]
+  )";
+  std::string error;
+  std::unique_ptr<base::ListValue> expected_printers(
+      GetJSONAsListValue(expected_list, &error));
+  ASSERT_TRUE(expected_printers) << "Error deserializing printers: " << error;
+  EXPECT_EQ(*printers, *expected_printers);
+}
+
+// Tests that fetching capabilities for an existing installed printer is
+// successful.
+TEST_F(LocalPrinterHandlerChromeosTest, StartGetCapabilityValidPrinter) {
+  Printer configured_printer = CreateTestPrinter("printer1", "configured");
+  printers_manager_.AddPrinter(configured_printer,
+                               CupsPrintersManager::kConfigured);
+  printers_manager_.InstallPrinter("printer1");
+
+  // Add printer capabilities to |test_backend_|.
+  PrinterSemanticCapsAndDefaults caps;
+  test_backend_->AddValidPrinter(
+      "printer1", std::make_unique<PrinterSemanticCapsAndDefaults>(caps));
+
+  std::unique_ptr<base::Value> fetched_caps;
+  local_printer_handler_->StartGetCapability(
+      "printer1", base::BindOnce(&RecordGetCapability, &fetched_caps));
+
+  thread_bundle_.RunUntilIdle();
+
+  ASSERT_TRUE(fetched_caps);
+  base::DictionaryValue* dict;
+  ASSERT_TRUE(fetched_caps->GetAsDictionary(&dict));
+  ASSERT_TRUE(dict->HasKey(kSettingCapabilities));
+  ASSERT_TRUE(dict->HasKey(kPrinter));
+}
+
+// Test that printers which have not yet been installed are installed with
+// SetUpPrinter before their capabilities are fetched.
+TEST_F(LocalPrinterHandlerChromeosTest, StartGetCapabilityPrinterNotInstalled) {
+  Printer discovered_printer = CreateTestPrinter("printer1", "discovered");
+  // NOTE: The printer |discovered_printer| is not installed using
+  // InstallPrinter.
+  printers_manager_.AddPrinter(discovered_printer,
+                               CupsPrintersManager::kDiscovered);
+
+  // Add printer capabilities to |test_backend_|.
+  PrinterSemanticCapsAndDefaults caps;
+  test_backend_->AddValidPrinter(
+      "printer1", std::make_unique<PrinterSemanticCapsAndDefaults>(caps));
+
+  std::unique_ptr<base::Value> fetched_caps;
+  local_printer_handler_->StartGetCapability(
+      "printer1", base::BindOnce(&RecordGetCapability, &fetched_caps));
+
+  thread_bundle_.RunUntilIdle();
+
+  ASSERT_TRUE(fetched_caps);
+  base::DictionaryValue* dict;
+  ASSERT_TRUE(fetched_caps->GetAsDictionary(&dict));
+  ASSERT_TRUE(dict->HasKey(kSettingCapabilities));
+  ASSERT_TRUE(dict->HasKey(kPrinter));
+}
+
+// In this test we expect the StartGetCapability to bail early because the
+// provided printer can't be found in the CupsPrintersManager.
+TEST_F(LocalPrinterHandlerChromeosTest, StartGetCapabilityInvalidPrinter) {
+  std::unique_ptr<base::Value> fetched_caps;
+  local_printer_handler_->StartGetCapability(
+      "invalid printer", base::BindOnce(&RecordGetCapability, &fetched_caps));
+
+  thread_bundle_.RunUntilIdle();
+
+  ASSERT_TRUE(fetched_caps);
+  EXPECT_TRUE(fetched_caps->is_none());
+}
+
+}  // namespace printing
diff --git a/chrome/browser/ui/webui/print_preview/printer_handler.cc b/chrome/browser/ui/webui/print_preview/printer_handler.cc
index d5fcabd..84afb6f 100644
--- a/chrome/browser/ui/webui/print_preview/printer_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/printer_handler.cc
@@ -38,8 +38,8 @@
     content::WebContents* preview_web_contents,
     Profile* profile) {
 #if defined(OS_CHROMEOS)
-  return std::make_unique<LocalPrinterHandlerChromeos>(profile,
-                                                       preview_web_contents);
+  return LocalPrinterHandlerChromeos::CreateDefault(profile,
+                                                    preview_web_contents);
 #else
   return std::make_unique<LocalPrinterHandlerDefault>(preview_web_contents);
 #endif
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index b0e6f27c..4deb4c34 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -132,7 +132,7 @@
 #include "chrome/browser/ui/webui/settings/printing_handler.h"
 #endif
 
-#if defined(SAFE_BROWSING_FULL)
+#if defined(FULL_SAFE_BROWSING)
 #include "chrome/browser/safe_browsing/chrome_password_protection_service.h"
 #include "chrome/browser/ui/webui/settings/change_password_handler.h"
 #endif
@@ -270,7 +270,7 @@
 #endif  // OS_WIN && defined(GOOGLE_CHROME_BUILD)
 
   bool password_protection_available = false;
-#if defined(SAFE_BROWSING_FULL)
+#if defined(FULL_SAFE_BROWSING)
   safe_browsing::ChromePasswordProtectionService* password_protection =
       safe_browsing::ChromePasswordProtectionService::
           GetPasswordProtectionService(profile);
diff --git a/chrome/browser/ui/webui/welcome/welcome_ui.cc b/chrome/browser/ui/webui/welcome/welcome_ui.cc
index 4d26cf73..7fb5102e2 100644
--- a/chrome/browser/ui/webui/welcome/welcome_ui.cc
+++ b/chrome/browser/ui/webui/welcome/welcome_ui.cc
@@ -4,7 +4,11 @@
 
 #include "chrome/browser/ui/webui/welcome/welcome_ui.h"
 
+#include <vector>
+
+#include "base/bind.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
 #include "build/build_config.h"
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
 #include "chrome/browser/ui/webui/dark_mode_handler.h"
@@ -144,13 +148,17 @@
   const bool is_nux_onboarding_enabled = nux::IsNuxOnboardingEnabled(profile);
 
   if (is_nux_onboarding_enabled) {
-    html_source->UseGzip(base::BindRepeating([](const std::string& path) {
-      for (size_t i = 0; i < kOnboardingWelcomeResourcesSize; ++i) {
-        if (path == kOnboardingWelcomeResources[i].name)
-          return kOnboardingWelcomeResources[i].gzipped;
-      }
-      return true;
-    }));
+    std::vector<std::string> gzipped_paths{""};
+    for (size_t i = 0; i < kOnboardingWelcomeResourcesSize; ++i) {
+      if (kOnboardingWelcomeResources[i].gzipped)
+        gzipped_paths.emplace_back(kOnboardingWelcomeResources[i].name);
+    }
+    html_source->UseGzip(base::BindRepeating(
+        [](const std::vector<std::string>& gzipped_paths,
+           const std::string& path) {
+          return base::ContainsValue(gzipped_paths, path);
+        },
+        std::move(gzipped_paths)));
   }
 
   bool is_dice =
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_mac.mm b/chrome/browser/web_applications/components/web_app_shortcut_mac.mm
index cde6a67..878bf53 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut_mac.mm
+++ b/chrome/browser/web_applications/components/web_app_shortcut_mac.mm
@@ -75,6 +75,7 @@
 @implementation TerminationObserver
 - (id)initWithRunningApplication:(NSRunningApplication*)app
                         callback:(base::OnceClosure)callback {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (self = [super init]) {
     callback_ = std::move(callback);
     app_.reset(app, base::scoped_policy::RETAIN);
@@ -96,22 +97,60 @@
   NSNumber* newNumberValue = [change objectForKey:NSKeyValueChangeNewKey];
   BOOL newValue = [newNumberValue boolValue];
   if (newValue) {
+    base::scoped_nsobject<TerminationObserver> scoped_self(
+        self, base::scoped_policy::RETAIN);
     base::PostTaskWithTraits(
         FROM_HERE, {content::BrowserThread::UI},
         base::BindOnce(
-            [](TerminationObserver* observer) { [observer onTerminated]; },
-            self));
+            [](base::scoped_nsobject<TerminationObserver> observer) {
+              [observer onTerminated];
+            },
+            scoped_self));
   }
 }
 
 - (void)onTerminated {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  // If |onTerminated| is called repeatedly (which in theory it should not),
+  // then ensure that we only call removeObserver and release once by doing an
+  // early-out if |callback_| has already been made.
+  if (!callback_)
+    return;
   std::move(callback_).Run();
+  DCHECK(!callback_);
   [app_ removeObserver:self forKeyPath:@"isTerminated" context:nullptr];
   [self release];
 }
 @end
 
+// TODO(https://crbug.com/941909): Change all launch functions to take a single
+// callback that returns a NSRunningApplication, rather than separate launch and
+// termination callbacks.
+void RunAppLaunchCallbacks(
+    base::scoped_nsobject<NSRunningApplication> app,
+    base::OnceCallback<void(base::Process)> launch_callback,
+    base::OnceClosure termination_callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK(app);
+
+  // If the app doesn't have a valid pid, or if the application has been
+  // terminated, then indicate failure in |launch_callback|.
+  base::Process process([app processIdentifier]);
+  if (!process.IsValid() || [app isTerminated]) {
+    std::move(launch_callback).Run(base::Process());
+    return;
+  }
+
+  // Otherwise, indicate successful launch, and watch for termination.
+  // TODO(https://crbug.com/941909): This watches for termination indefinitely,
+  // but we only need to watch for termination until the app establishes a
+  // (whereupon termination will be noticed by the mojo connection closing).
+  std::move(launch_callback).Run(std::move(process));
+  [[TerminationObserver alloc]
+      initWithRunningApplication:app
+                        callback:std::move(termination_callback)];
+}
+
 bool g_app_shims_allow_update_and_launch_in_tests = false;
 
 namespace {
@@ -369,17 +408,16 @@
       command_line.AppendSwitch(app_mode::kLaunchedAfterRebuild);
 
     // Launch without activating (NSWorkspaceLaunchWithoutActivation).
-    NSRunningApplication* app = base::mac::OpenApplicationWithPath(
-        shim_path, command_line,
-        NSWorkspaceLaunchDefault | NSWorkspaceLaunchWithoutActivation);
+    base::scoped_nsobject<NSRunningApplication> app(
+        base::mac::OpenApplicationWithPath(
+            shim_path, command_line,
+            NSWorkspaceLaunchDefault | NSWorkspaceLaunchWithoutActivation),
+        base::scoped_policy::RETAIN);
     if (app) {
-      base::Process process([app processIdentifier]);
-      base::PostTaskWithTraits(
-          FROM_HERE, {content::BrowserThread::UI},
-          base::BindOnce(std::move(launched_callback), std::move(process)));
-      [[TerminationObserver alloc]
-          initWithRunningApplication:app
-                            callback:std::move(terminated_callback)];
+      base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
+                               base::BindOnce(&RunAppLaunchCallbacks, app,
+                                              std::move(launched_callback),
+                                              std::move(terminated_callback)));
       return;
     }
   }
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 7c82a92..370728b 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -4,12 +4,21 @@
 
 #include "chrome/common/chrome_features.h"
 
+#include <vector>
+
 #include "base/command_line.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/no_destructor.h"
+#include "base/strings/string_split.h"
 #include "build/build_config.h"
 #include "chrome/common/chrome_switches.h"
 #include "extensions/buildflags/buildflags.h"
 #include "ppapi/buildflags/buildflags.h"
 
+#if defined(OS_ANDROID)
+#include "base/android/build_info.h"
+#endif
+
 namespace features {
 
 // All features in alphabetical order.
@@ -628,6 +637,39 @@
                                             base::FEATURE_ENABLED_BY_DEFAULT};
 #endif
 
+#if defined(OS_ANDROID)
+const base::Feature kUseDisplayWideColorGamut{"UseDisplayWideColorGamut",
+                                              base::FEATURE_ENABLED_BY_DEFAULT};
+
+bool UseDisplayWideColorGamut() {
+  auto compute_use_display_wide_color_gamut = []() {
+    // Enabled this feature for devices listed in "enabled_models" field trial
+    // param. This is a comma separated list.
+    std::string enabled_models_list = base::GetFieldTrialParamValueByFeature(
+        kUseDisplayWideColorGamut, "enabled_models");
+    if (enabled_models_list.empty())
+      return false;
+
+    const char* current_model =
+        base::android::BuildInfo::GetInstance()->model();
+    std::vector<std::string> enabled_models =
+        base::SplitString(enabled_models_list, ",", base::KEEP_WHITESPACE,
+                          base::SPLIT_WANT_NONEMPTY);
+    for (const std::string& model : enabled_models) {
+      if (model == current_model)
+        return true;
+    }
+
+    return false;
+  };
+
+  // As it takes some work to compute this, cache the result.
+  static base::NoDestructor<bool> is_wide_color_gamut_enabled(
+      compute_use_display_wide_color_gamut());
+  return *is_wide_color_gamut_enabled;
+}
+#endif
+
 #if defined(OS_CHROMEOS)
 // Enables or disables logging for adaptive screen brightness on Chrome OS.
 const base::Feature kAdaptiveScreenBrightnessLogging{
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 0b947172..39c60442 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -416,6 +416,14 @@
 extern const base::Feature kUsageTimeStateNotifier;
 #endif
 
+#if defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kUseDisplayWideColorGamut;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+bool UseDisplayWideColorGamut();
+#endif
+
 #if defined(OS_CHROMEOS)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kAdaptiveScreenBrightnessLogging;
diff --git a/chrome/renderer/autofill/form_autofill_browsertest.cc b/chrome/renderer/autofill/form_autofill_browsertest.cc
index d8207cd2..e27de98 100644
--- a/chrome/renderer/autofill/form_autofill_browsertest.cc
+++ b/chrome/renderer/autofill/form_autofill_browsertest.cc
@@ -13,6 +13,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
+#include "build/build_config.h"
 #include "chrome/test/base/chrome_render_view_test.h"
 #include "components/autofill/content/renderer/form_autofill_util.h"
 #include "components/autofill/content/renderer/form_cache.h"
@@ -32,6 +33,10 @@
 #include "third_party/blink/public/web/web_script_source.h"
 #include "third_party/blink/public/web/web_select_element.h"
 
+#if defined(OS_WIN)
+#include "third_party/blink/public/web/win/web_font_rendering.h"
+#endif
+
 using autofill::features::kAutofillEnforceMinRequiredFieldsForHeuristics;
 using autofill::features::kAutofillEnforceMinRequiredFieldsForQuery;
 using autofill::features::kAutofillEnforceMinRequiredFieldsForUpload;
@@ -279,6 +284,17 @@
   }
   ~FormAutofillTest() override {}
 
+#if defined(OS_WIN)
+  void SetUp() override {
+    ChromeRenderViewTest::SetUp();
+
+    // Autofill uses the system font to render suggestion previews. On Windows
+    // an extra step is required to ensure that the system font is configured.
+    blink::WebFontRendering::SetMenuFontMetrics(
+        base::ASCIIToUTF16("Arial").c_str(), 12);
+  }
+#endif
+
   void ExpectLabels(const char* html,
                     const std::vector<base::string16>& id_attributes,
                     const std::vector<base::string16>& name_attributes,
diff --git a/chrome/renderer/resources/plugins/plugin_poster.html b/chrome/renderer/resources/plugins/plugin_poster.html
index 6758fa72..ec97d91 100644
--- a/chrome/renderer/resources/plugins/plugin_poster.html
+++ b/chrome/renderer/resources/plugins/plugin_poster.html
@@ -72,7 +72,7 @@
 
 <body>
   <div title="$i18n{name}" id="outer">
-    <img id="poster" i18n-values="srcset:poster">
+    <img id="poster" srcset="$i18n{poster}">
     <div id="shielding"></div>
     <div id="inner-container"
          style="width:$i18n{visibleWidth};height:$i18n{visibleHeight}">
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 7478f0d..65aacb7 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -354,6 +354,7 @@
     # For isolate contract.
     "//testing/scripts/common.py",
     "//testing/xvfb.py",
+    "//testing/scripts/gpu_integration_test_adapter.py",
     "//testing/scripts/run_gpu_integration_test_as_googletest.py",
     "//testing/trigger_scripts/trigger_multiple_dimensions.py",
 
@@ -2858,6 +2859,7 @@
 
     # TODO(hashimoto): those tests should be componentized and moved to
     # //components:components_unittests, http://crbug.com/527882.
+    "../browser/scoped_visibility_tracker_unittest.cc",
     "../browser/search_engines/template_url_fetcher_unittest.cc",
     "../browser/search_engines/template_url_parser_unittest.cc",
     "../browser/search_engines/template_url_service_sync_unittest.cc",
@@ -2920,7 +2922,6 @@
     "../browser/ui/bloated_renderer/bloated_renderer_tab_helper_unittest.cc",
     "../browser/ui/blocked_content/popup_opener_tab_helper_unittest.cc",
     "../browser/ui/blocked_content/safe_browsing_triggered_popup_blocker_unittest.cc",
-    "../browser/ui/blocked_content/scoped_visibility_tracker_unittest.cc",
     "../browser/ui/bookmarks/bookmark_editor_unittest.cc",
     "../browser/ui/bookmarks/bookmark_ui_utils_desktop_unittest.cc",
     "../browser/ui/bookmarks/recently_used_folders_combo_model_unittest.cc",
@@ -4325,6 +4326,8 @@
         "../service/service_ipc_server_unittest.cc",
         "../service/service_process_prefs_unittest.cc",
       ]
+    } else {
+      sources += [ "../browser/ui/webui/print_preview/local_printer_handler_chromeos_unittest.cc" ]
     }
   }
 
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc
index c4808c4..41ca463 100644
--- a/chrome/test/base/in_process_browser_test.cc
+++ b/chrome/test/base/in_process_browser_test.cc
@@ -90,10 +90,14 @@
 
 #if defined(OS_CHROMEOS)
 #include "ash/test/ui_controls_factory_ash.h"
+#include "base/system/sys_info.h"
 #include "chrome/browser/chromeos/input_method/input_method_configuration.h"
 #include "chrome/test/base/default_ash_event_generator_delegate.h"
+#include "chromeos/constants/chromeos_switches.h"
+#include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/services/device_sync/device_sync_impl.h"
 #include "chromeos/services/device_sync/fake_device_sync.h"
+#include "components/user_manager/user_names.h"
 #include "ui/aura/test/mus/change_completion_waiter.h"
 #include "ui/aura/test/ui_controls_factory_aura.h"
 #include "ui/aura/window.h"
@@ -231,17 +235,37 @@
       << "Could not set up user data directory.";
 
 #if defined(OS_CHROMEOS)
-  // Make sure that the log directory exists.
-  base::FilePath log_dir = logging::GetSessionLogDir(*command_line);
-  base::CreateDirectory(log_dir);
+  // No need to redirect log for test.
+  command_line->AppendSwitch(switches::kDisableLoggingRedirect);
+
   // Disable IME extension loading to avoid many browser tests failures.
   chromeos::input_method::DisableExtensionLoading();
-  if (!command_line->HasSwitch(switches::kHostWindowBounds)) {
+
+  if (!command_line->HasSwitch(switches::kHostWindowBounds) &&
+      !base::SysInfo::IsRunningOnChromeOS()) {
     // Adjusting window location & size so that the ash desktop window fits
-    // inside the Xvfb'x default resolution.
+    // inside the Xvfb's default resolution. Only do that when not running
+    // on device. Otherwise, device display is not properly configured.
     command_line->AppendSwitchASCII(switches::kHostWindowBounds,
                                     "0+0-1280x800");
   }
+
+  // Default to run in a signed in session of stub user if tests do not run
+  // in the login screen (--login-manager), or logged in user session
+  // (--login-user), or the guest session (--bwsi). This is essentially
+  // the same as in ChromeBrowserMainPartsChromeos::PreEarlyInitialization
+  // but it will be done on device and only for tests.
+  if (!command_line->HasSwitch(chromeos::switches::kLoginManager) &&
+      !command_line->HasSwitch(chromeos::switches::kLoginUser) &&
+      !command_line->HasSwitch(chromeos::switches::kGuestSession)) {
+    command_line->AppendSwitchASCII(
+        chromeos::switches::kLoginUser,
+        cryptohome::Identification(user_manager::StubAccountId()).id());
+    if (!command_line->HasSwitch(chromeos::switches::kLoginProfile)) {
+      command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile,
+                                      chrome::kTestUserProfileDir);
+    }
+  }
 #endif
 
   SetScreenInstance();
diff --git a/chrome/test/chromedriver/capabilities.cc b/chrome/test/chromedriver/capabilities.cc
index 1d43bf2d..a2b42ba 100644
--- a/chrome/test/chromedriver/capabilities.cc
+++ b/chrome/test/chromedriver/capabilities.cc
@@ -225,12 +225,20 @@
     return Status(kInvalidArgument, "'timeouts' must be a JSON object");
   for (const auto& it : timeouts->DictItems()) {
     int64_t timeout_ms_int64 = -1;
-    if (!GetOptionalSafeInt(timeouts, it.first, &timeout_ms_int64)
-        || timeout_ms_int64 < 0)
-      return Status(kInvalidArgument, "value must be a non-negative integer");
-    base::TimeDelta timeout =
-                          base::TimeDelta::FromMilliseconds(timeout_ms_int64);
+    base::TimeDelta timeout;
     const std::string& type = it.first;
+    if (it.second.is_none()) {
+      if (type == "script")
+        timeout = base::TimeDelta::Max();
+      else
+        return Status(kInvalidArgument, "timeout can not be null");
+    } else {
+      if (!GetOptionalSafeInt(timeouts, it.first, &timeout_ms_int64) ||
+          timeout_ms_int64 < 0)
+        return Status(kInvalidArgument, "value must be a non-negative integer");
+      else
+        timeout = base::TimeDelta::FromMilliseconds(timeout_ms_int64);
+    }
     if (type == "script") {
       capabilities->script_timeout = timeout;
     } else if (type == "pageLoad") {
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc
index abe0053..055ad1a 100644
--- a/chrome/test/chromedriver/session_commands.cc
+++ b/chrome/test/chromedriver/session_commands.cc
@@ -133,8 +133,11 @@
   } else {
     caps->SetBoolean("setWindowRect", true);
   }
-  SetSafeInt(caps.get(), "timeouts.script",
-             session->script_timeout.InMilliseconds());
+  if (session->script_timeout == base::TimeDelta::Max())
+    caps->SetPath({"timeouts", "script"}, base::Value());
+  else
+    SetSafeInt(caps.get(), "timeouts.script",
+               session->script_timeout.InMilliseconds());
   SetSafeInt(caps.get(), "timeouts.pageLoad",
              session->page_load_timeout.InMilliseconds());
   SetSafeInt(caps.get(), "timeouts.implicit",
@@ -755,12 +758,21 @@
                              std::unique_ptr<base::Value>* value) {
   for (const auto& setting : params.DictItems()) {
     int64_t timeout_ms_int64 = -1;
-    if (!GetOptionalSafeInt(&params, setting.first, &timeout_ms_int64) ||
-        timeout_ms_int64 < 0)
-      return Status(kInvalidArgument, "value must be a non-negative integer");
-    base::TimeDelta timeout =
-                    base::TimeDelta::FromMilliseconds(timeout_ms_int64);
+    base::TimeDelta timeout;
     const std::string& type = setting.first;
+    if (setting.second.is_none()) {
+      if (type == "script")
+        timeout = base::TimeDelta::Max();
+      else
+        return Status(kInvalidArgument, "timeout can not be null");
+    } else {
+        if (!GetOptionalSafeInt(&params, setting.first, &timeout_ms_int64)
+            || timeout_ms_int64 < 0)
+            return Status(kInvalidArgument,
+                          "value must be a non-negative integer");
+        else
+            timeout = base::TimeDelta::FromMilliseconds(timeout_ms_int64);
+    }
     if (type == "script") {
       session->script_timeout = timeout;
     } else if (type == "pageLoad") {
@@ -791,7 +803,11 @@
                           const base::DictionaryValue& params,
                           std::unique_ptr<base::Value>* value) {
   base::DictionaryValue timeouts;
-  SetSafeInt(&timeouts, "script", session->script_timeout.InMilliseconds());
+  if (session->script_timeout == base::TimeDelta::Max())
+    timeouts.SetKey("script", base::Value());
+  else
+    SetSafeInt(&timeouts, "script", session->script_timeout.InMilliseconds());
+
   SetSafeInt(&timeouts, "pageLoad",
                         session->page_load_timeout.InMilliseconds());
   SetSafeInt(&timeouts, "implicit", session->implicit_wait.InMilliseconds());
diff --git a/chrome/test/data/extensions/api_test/activity_log_private/test/test.js b/chrome/test/data/extensions/api_test/activity_log_private/test/test.js
index aaa43008..6774e9b 100644
--- a/chrome/test/data/extensions/api_test/activity_log_private/test/test.js
+++ b/chrome/test/data/extensions/api_test/activity_log_private/test/test.js
@@ -58,11 +58,7 @@
     chrome.runtime.sendMessage(FRIEND_EXTENSION_ID,
                                'message_self', function response() { });
   },
-  expected_activity_js: [
-    'runtime.connect',
-    'runtime.sendMessage'
-  ],
-  expected_activity_native: [
+  expected_activity: [
     'runtime.sendMessage'
   ]
 });
@@ -71,11 +67,7 @@
     chrome.runtime.sendMessage(FRIEND_EXTENSION_ID,
                                'message_other', function response() { });
   },
-  expected_activity_js: [
-    'runtime.connect',
-    'runtime.sendMessage'
-  ],
-  expected_activity_native: [
+  expected_activity: [
     'runtime.sendMessage'
   ]
 });
@@ -182,17 +174,7 @@
     chrome.runtime.sendMessage(FRIEND_EXTENSION_ID,
                                'api_tab_updated', function response() { });
   },
-  expected_activity_js: [
-    'tabs.onUpdated',
-    'tabs.onUpdated',
-    'tabs.onUpdated',
-    'tabs.connect',
-    'tabs.sendMessage',
-    'tabs.executeScript',
-    'tabs.executeScript',
-    'tabs.remove'
-  ],
-  expected_activity_native: [
+  expected_activity: [
     'tabs.onUpdated',
     'tabs.onUpdated',
     'tabs.onUpdated',
@@ -209,18 +191,7 @@
                                function response() { });
   },
   is_incognito: true,
-  expected_activity_js: [
-    'windows.create',
-    'tabs.onUpdated',
-    'tabs.onUpdated',
-    'tabs.onUpdated',
-    'tabs.connect',
-    'tabs.sendMessage',
-    'tabs.executeScript',
-    'tabs.executeScript',
-    'tabs.remove'
-  ],
-  expected_activity_native: [
+  expected_activity: [
     'windows.create',
     'tabs.onUpdated',
     'tabs.onUpdated',
@@ -556,16 +527,6 @@
             console.log('Expecting OS specific activity for: ' + info.os);
             enabledTestCase.expected_activity =
                 enabledTestCase[activityListForOS];
-          } else if ('expected_activity_js' in enabledTestCase) {
-            // Some tests have different activity depending on whether native
-            // bindings are being used. This is in the case of the extension
-            // using the sendMessage() API. With JS bindings, this is
-            // implemented using connect(), so both API calls are seen. With
-            // native bindings, we fix this, and only the sendMessage call is
-            // seen.
-            var key = config.nativeCrxBindingsEnabled ?
-                'expected_activity_native' : 'expected_activity_js';
-            enabledTestCase.expected_activity = enabledTestCase[key];
           }
 
           enabledTestCases.push(enabledTestCase);
diff --git a/chrome/test/data/extensions/api_test/bindings/invalidate_context/background.js b/chrome/test/data/extensions/api_test/bindings/invalidate_context/background.js
index 5ea3ef4..9280fae 100644
--- a/chrome/test/data/extensions/api_test/bindings/invalidate_context/background.js
+++ b/chrome/test/data/extensions/api_test/bindings/invalidate_context/background.js
@@ -6,7 +6,6 @@
 var frameRuntime;
 var frameStorage;
 var frameTabs;
-var nativeBindingsEnabled;
 
 function createFrame() {
   frame = document.createElement('iframe');
@@ -54,12 +53,6 @@
   chrome.test.assertTrue(result.postMessageThrow);
   chrome.test.assertTrue(result.disconnectThrow);
 
-  // With native bindings, the event object instantiated on a Port is set as a
-  // lazy data property, and thus is safe to access even after the context has
-  // been removed. JS bindings always throw errors when trying to access them
-  // after context invalidation.
-  expectEventsValid &= nativeBindingsEnabled;
-
   if (expectEventsValid) {
     chrome.test.assertFalse(result.getOnMessageThrow);
     chrome.test.assertFalse(result.getOnDisconnectThrow);
@@ -73,7 +66,7 @@
   }
 }
 
-const tests = [
+chrome.test.runTests([
   function useFrameStorageAndRuntime() {
     createFrame().then(() => {
       frameRuntime = frame.contentWindow.chrome.runtime;
@@ -150,9 +143,4 @@
       chrome.test.succeed();
     });
   },
-];
-
-chrome.test.getConfig((config) => {
-  nativeBindingsEnabled = config.nativeCrxBindingsEnabled;
-  chrome.test.runTests(tests);
-});
+]);
diff --git a/chrome/test/data/extensions/api_test/messaging/connect/page.js b/chrome/test/data/extensions/api_test/messaging/connect/page.js
index f349a355..02c7675d 100644
--- a/chrome/test/data/extensions/api_test/messaging/connect/page.js
+++ b/chrome/test/data/extensions/api_test/messaging/connect/page.js
@@ -2,30 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-function clobberJSON() {
-  JSON.parse = function() {
-    return "JSON.parse clobbered by content script.";
-  };
-
-  JSON.stringify = function() {
-    return "JSON.stringify clobbered by content script.";
-  };
-
-  Array.prototype.toJSON = function() {
-    return "Array.prototype.toJSON clobbered by content script.";
-  };
-
-  Object.prototype.toJSON = function() {
-    return "Object.prototype.toJSON clobbered by content script.";
-  };
-}
-
-chrome.test.getConfig((config) => {
-  // We don't clobber JSON with native bindings. See https://crbug.com/792602.
-  if (!config.nativeCrxBindingsEnabled)
-    clobberJSON();
-});
-
 // For complex connect tests.
 chrome.runtime.onConnect.addListener(function onConnect(port) {
   console.log('connected');
diff --git a/chrome/test/data/extensions/api_test/messaging/connect/test.js b/chrome/test/data/extensions/api_test/messaging/connect/test.js
index 48ab6425..0310b73 100644
--- a/chrome/test/data/extensions/api_test/messaging/connect/test.js
+++ b/chrome/test/data/extensions/api_test/messaging/connect/test.js
@@ -5,24 +5,6 @@
 var listenOnce = chrome.test.listenOnce;
 var listenForever = chrome.test.listenForever;
 
-function clobberJSON() {
-  JSON.parse = function() {
-    return "JSON.parse clobbered by extension.";
-  };
-
-  JSON.stringify = function() {
-    return "JSON.stringify clobbered by extension.";
-  };
-
-  Array.prototype.toJSON = function() {
-    return "Array.prototype.toJSON clobbered by extension.";
-  };
-
-  Object.prototype.toJSON = function() {
-    return "Object.prototype.toJSON clobbered by extension.";
-  };
-}
-
 // Keep track of the tab that we're running tests in, for simplicity.
 var testTab = null;
 
@@ -45,10 +27,6 @@
 }
 
 chrome.test.getConfig(function(config) {
-  // We don't clobber JSON with native bindings. See https://crbug.com/792602.
-  if (!config.nativeCrxBindingsEnabled)
-    clobberJSON();
-
   chrome.test.runTests([
     function setupTestTab() {
       chrome.test.log("Creating tab...");
@@ -279,20 +257,16 @@
     // Tests that a message which fails to serialize prints an error and
     // doesn't send (http://crbug.com/263077).
     function unserializableMessage() {
-      // Unserializable messages throw an error with native bindings, and only
-      // log a warning with JS bindings.
-      var expectThrow = config.nativeCrxBindingsEnabled;
       try {
         chrome.tabs.connect(testTab.id).postMessage(function() {
           // This shouldn't ever be called, so it's a bit pointless.
           chrome.test.fail();
         });
-        // Didn't crash.
-        chrome.test.assertFalse(expectThrow);
+        // The call above should have thrown an error.
+        chrome.test.fail();
       } catch (e) {
-        chrome.test.assertTrue(expectThrow);
+        chrome.test.succeed();
       }
-      chrome.test.succeed();
     },
 
     // Tests that reloading a child frame disconnects the port if it was the
diff --git a/chrome/test/data/webui/print_preview/destination_select_test.js b/chrome/test/data/webui/print_preview/destination_select_test.js
index 68b91f5e..7575ac6 100644
--- a/chrome/test/data/webui/print_preview/destination_select_test.js
+++ b/chrome/test/data/webui/print_preview/destination_select_test.js
@@ -21,7 +21,7 @@
   const suiteName = 'DestinationSelectTests';
   suite(suiteName, function() {
     /** @type {?PrintPreviewAppElement} */
-    let page = null;
+    let destinationSettings = null;
 
     /** @type {?PrintPreview.NativeLayerStub} */
     let nativeLayer = null;
@@ -63,30 +63,45 @@
       nativeLayer.setLocalDestinations(localDestinations);
       print_preview.NativeLayer.setInstance(nativeLayer);
       const cloudPrintInterface = new print_preview.CloudPrintInterfaceStub();
-      cloudprint.setCloudPrintInterfaceForTesting(cloudPrintInterface);
       cloudDestinations.forEach(cloudDestination => {
         cloudPrintInterface.setPrinter(cloudDestination);
       });
       PolymerTest.clearBody();
-      page = document.createElement('print-preview-app');
-      document.body.appendChild(page);
-      cr.webUIListenerCallback('use-cloud-print', 'cloudprint url', false);
-      page.destinationStore_.addEventListener(
+      destinationSettings =
+          document.createElement('print-preview-destination-settings');
+      destinationSettings.destination = null;
+      document.body.appendChild(destinationSettings);
+      const whenCapabilitiesReady = test_util.eventToPromise(
+          print_preview.DestinationStore.EventType
+              .SELECTED_DESTINATION_CAPABILITIES_READY,
+          destinationSettings.destinationStore_);
+      destinationSettings.destinationStore_.addEventListener(
           print_preview.DestinationStore.EventType.DESTINATION_SELECT,
           function() {
             numPrintersSelected++;
           });
-      const whenCapabilitiesReady = test_util.eventToPromise(
-          print_preview.DestinationStore.EventType
-              .SELECTED_DESTINATION_CAPABILITIES_READY,
-          page.destinationStore_);
-
-      return nativeLayer.whenCalled('getInitialSettings').then(() => {
-        return opt_expectPrinterFailure ? Promise.resolve() : Promise.race([
-          nativeLayer.whenCalled('getPrinterCapabilities'),
-          whenCapabilitiesReady
-        ]);
-      });
+      destinationSettings.setCloudPrintInterface(cloudPrintInterface);
+      destinationSettings.appKioskMode = initialSettings.isInAppKioskMode;
+      const recentDestinations = initialSettings.serializedAppStateStr ?
+          JSON.parse(initialSettings.serializedAppStateStr).recentDestinations :
+          [];
+      destinationSettings.settings = {
+        recentDestinations: {
+          value: recentDestinations,
+          unavailableValue: [],
+          valid: true,
+          available: true,
+          setByPolicy: false,
+          key: 'recentDestinations',
+        },
+      };
+      destinationSettings.initDestinationStore(
+          initialSettings.printerName,
+          initialSettings.serializedDefaultDestinationSelectionRulesStr);
+      destinationSettings.disabled = false;
+      return opt_expectPrinterFailure ? Promise.resolve() : Promise.race([
+        nativeLayer.whenCalled('getPrinterCapabilities'), whenCapabilitiesReady
+      ]);
     }
 
     /**
@@ -97,7 +112,6 @@
      * @return {!Promise} Promise that resolves when checks are complete.
      */
     function assertPrinterDisplay(printerName, disabled) {
-      const destinationSettings = page.$$('print-preview-destination-settings');
       const destinationSelect = destinationSettings.$.destinationSelect;
 
       Polymer.dom.flush();
@@ -130,7 +144,7 @@
       return setInitialSettings().then(function(args) {
         assertEquals('ID1', args.destinationId);
         assertEquals(print_preview.PrinterType.LOCAL, args.type);
-        assertEquals('ID1', page.destination_.id);
+        assertEquals('ID1', destinationSettings.destination.id);
         return assertPrinterDisplay('One', false);
       });
     });
@@ -155,12 +169,13 @@
             // recent.
             assertEquals('ID1', args.destinationId);
             assertEquals(print_preview.PrinterType.LOCAL, args.type);
-            assertEquals('ID1', page.destination_.id);
+            assertEquals('ID1', destinationSettings.destination.id);
             return assertPrinterDisplay('One', false);
           })
           .then(function() {
             // Verify the correct printers are marked as recent in the store.
-            const reportedPrinters = page.destinationStore_.destinations();
+            const reportedPrinters =
+                destinationSettings.destinationStore_.destinations();
             destinations.forEach((destination, index) => {
               const match = reportedPrinters.find((reportedPrinter) => {
                 return reportedPrinter.id == destination.id;
@@ -191,18 +206,12 @@
             // recent.
             assertEquals('ID1', args.destinationId);
             assertEquals(print_preview.PrinterType.LOCAL, args.type);
-            assertEquals('ID1', page.destination_.id);
-
-            return nativeLayer.whenCalled('getPreview');
-          })
-          .then(function(previewArgs) {
-            const ticket = JSON.parse(previewArgs.printTicket);
-            assertEquals(0, ticket.requestID);
-            assertEquals('ID1', ticket.deviceName);
+            assertEquals('ID1', destinationSettings.destination.id);
 
             // The other recent destinations should be prefetched, but only one
             // should have been selected so there was only one preview request.
-            const reportedPrinters = page.destinationStore_.destinations();
+            const reportedPrinters =
+                destinationSettings.destinationStore_.destinations();
             assertEquals(4, reportedPrinters.length);
             destinations.forEach((destination, index) => {
               assertEquals(
@@ -226,7 +235,7 @@
         // the rules.
         assertEquals('ID4', args.destinationId);
         assertEquals(print_preview.PrinterType.LOCAL, args.type);
-        assertEquals('ID4', page.destination_.id);
+        assertEquals('ID4', destinationSettings.destination.id);
         return assertPrinterDisplay('Four', false);
       });
     });
@@ -255,12 +264,12 @@
             test_util.eventToPromise(
                 print_preview.DestinationStore.EventType
                     .SELECTED_DESTINATION_CAPABILITIES_READY,
-                page.destinationStore_),
+                destinationSettings.destinationStore_),
           ])
           .then(function(argsArray) {
             // Need to load FooDevice as the printer, since it is the system
             // default.
-            assertEquals('FooDevice', page.destination_.id);
+            assertEquals('FooDevice', destinationSettings.destination.id);
             assertPrinterDisplay('FooName', false);
           });
     });
@@ -281,7 +290,7 @@
         // Should have loaded the first destination as the selected printer.
         assertEquals(destinations[0].id, args.destinationId);
         assertEquals(print_preview.PrinterType.LOCAL, args.type);
-        assertEquals(destinations[0].id, page.destination_.id);
+        assertEquals(destinations[0].id, destinationSettings.destination.id);
         return assertPrinterDisplay(destinations[0].displayName, false);
       });
     });
@@ -303,13 +312,11 @@
           .all([
             setInitialSettings(true),
             test_util.eventToPromise(
-                print_preview.DestinationStore.EventType.NO_DESTINATIONS_FOUND,
-                page.destinationStore_),
+                print_preview.DestinationStore.EventType.ERROR,
+                destinationSettings.destinationStore_),
           ])
           .then(function() {
-            assertEquals(null, page.destination_);
-            const destinationSettings =
-                page.$$('print-preview-destination-settings');
+            assertEquals(null, destinationSettings.destination);
             assertTrue(destinationSettings.$$('.throbber-container').hidden);
             const destinationSelect = destinationSettings.$.destinationSelect;
             assertFalse(destinationSelect.hidden);
@@ -334,10 +341,9 @@
       });
 
       return setInitialSettings().then(function(args) {
-        assertEquals(print_preview_new.State.READY, page.state);
         assertEquals('FooDevice', args.destinationId);
         assertEquals(print_preview.PrinterType.LOCAL, args.type);
-        assertEquals('FooDevice', page.destination_.id);
+        assertEquals('FooDevice', destinationSettings.destination.id);
         return assertPrinterDisplay('FooName', false);
       });
     });
@@ -358,17 +364,15 @@
       print_preview.DestinationStore.AUTO_SELECT_TIMEOUT_ = 0;
       return setInitialSettings()
           .then(function() {
-            assertEquals(print_preview_new.State.READY, page.state);
             assertPrinterDisplay('Save as PDF', false);
             // Simulate setting a bad ticket value.
-            page.$.state.transitTo(print_preview_new.State.INVALID_TICKET);
+            destinationSettings.disabled = true;
             return new Promise(resolve => setTimeout(resolve));
           })
           .then(function() {
             // Should still have Save as PDF. Dropdown is disabled due to
             // invalid ticket.
             assertPrinterDisplay('Save as PDF', true);
-            assertEquals(print_preview_new.State.INVALID_TICKET, page.state);
           });
     });
 
@@ -405,20 +409,13 @@
             // was most recent.
             assertEquals(
                 print_preview.Destination.GooglePromotedId.DOCS,
-                page.destination_.id);
+                destinationSettings.destination.id);
             assertPrinterDisplay('Save to Google Drive', false);
-            return nativeLayer.whenCalled('getPreview');
-          })
-          .then(function(previewArgs) {
-            const ticket = JSON.parse(previewArgs.printTicket);
-            assertEquals(0, ticket.requestID);
-            assertEquals(
-                print_preview.Destination.GooglePromotedId.DOCS,
-                ticket.deviceName);
 
             // Only the other cloud destination for the same user account should
             // have been prefetched.
-            const loadedPrinters = page.destinationStore_.destinations();
+            const loadedPrinters =
+                destinationSettings.destinationStore_.destinations();
             assertEquals(3, loadedPrinters.length);
             cloudDestinations.forEach((destination) => {
               assertEquals(
diff --git a/chrome/test/data/webui/print_preview/destination_settings_test.js b/chrome/test/data/webui/print_preview/destination_settings_test.js
index 1e174e18..19191d8 100644
--- a/chrome/test/data/webui/print_preview/destination_settings_test.js
+++ b/chrome/test/data/webui/print_preview/destination_settings_test.js
@@ -15,6 +15,7 @@
     SelectRecentDestination: 'select recent destination',
     OpenDialog: 'open dialog',
     TwoAccountsRecentDestinations: 'two accounts recent destinations',
+    UpdateRecentDestinations: 'update recent destinations',
   };
 
   const suiteName = 'DestinationSettingsTest';
@@ -57,14 +58,16 @@
 
       destinationSettings =
           document.createElement('print-preview-destination-settings');
-      destinationSettings.destinationStore = null;
-      destinationSettings.destination = null;
-      destinationSettings.recentDestinations = [];
-      destinationSettings.state = print_preview_new.State.NOT_READY;
-      destinationSettings.cloudPrintState =
-          print_preview.CloudPrintState.DISABLED;
-      destinationSettings.noDestinationsFound = false;
-      // Disabled is true when state is NOT_READY.
+      destinationSettings.settings = {
+        recentDestinations: {
+          value: [],
+          unavailableValue: [],
+          available: true,
+          valid: true,
+          setByPolicy: false,
+          key: 'recentDestinations',
+        },
+      };
       destinationSettings.disabled = true;
       document.body.appendChild(destinationSettings);
     });
@@ -79,58 +82,61 @@
 
       // Set up the destination store, but no destination yet. Dropdown is still
       // hidden.
-      const destinationStore =
-          print_preview_test_utils.createDestinationStore();
-      destinationStore.init(
-          false /* isInAppKioskMode */, 'FooDevice' /* printerName */,
-          '' /* serializedDefaultDestinationSelectionRulesStr */,
-          [] /* recentDestinations */);
-      destinationSettings.destinationStore = destinationStore;
-      destinationSettings.state = print_preview_new.State.NOT_READY;
+      destinationSettings.initDestinationStore(
+          'FooDevice' /* printerName */,
+          '' /* serializedDefaultDestinationSelectionRulesStr */);
       assertTrue(dropdown.hidden);
 
-      // Simulate loading a recent destination.
-      destinationSettings.destination = new print_preview.Destination(
-          'FooDevice', print_preview.DestinationType.LOCAL, getLocalOrigin(),
-          'FooName', print_preview.DestinationConnectionStatus.ONLINE);
-      destinationSettings.recentDestinations = [
-        print_preview.makeRecentDestination(destinationSettings.destination),
-      ];
-      destinationSettings.cloudPrintState =
-          print_preview.CloudPrintState.NOT_SIGNED_IN;
-      destinationSettings.state = print_preview_new.State.READY;
+      return test_util
+          .eventToPromise(
+              print_preview.DestinationStore.EventType
+                  .SELECTED_DESTINATION_CAPABILITIES_READY,
+              destinationSettings.destinationStore_)
+          .then(() => {
+            // Dropdown is visible but disabled since controls are disabled.
+            assertTrue(dropdown.disabled);
+            assertFalse(dropdown.hidden);
+            destinationSettings.disabled = false;
 
-      // Dropdown is visible but disabled due to NOT_READY state.
-      assertTrue(dropdown.disabled);
-      assertFalse(dropdown.hidden);
+            assertFalse(dropdown.disabled);
 
-      // Enable controls.
-      destinationSettings.disabled = false;
-      return test_util.waitForRenderOrTimeout0(dropdown).then(() => {
-        assertFalse(dropdown.disabled);
+            // Simulate setting a setting to an invalid value. Dropdown is
+            // disabled due to validation error on another control.
+            destinationSettings.disabled = true;
+            assertTrue(dropdown.disabled);
 
-        // Simulate setting a setting to an invalid value. Dropdown is disabled
-        // due to validation error on another control.
-        destinationSettings.state = print_preview_new.State.INVALID_TICKET;
-        destinationSettings.disabled = true;
-        assertTrue(dropdown.disabled);
+            // Simulate the user fixing the validation error, and then selecting
+            // an invalid printer. Dropdown is enabled, so that the user can fix
+            // the error.
+            destinationSettings.disabled = false;
+            destinationSettings.destinationStore_.dispatchEvent(new CustomEvent(
+                print_preview.DestinationStore.EventType.ERROR,
+                {detail: print_preview.DestinationErrorType.INVALID}));
+            Polymer.dom.flush();
 
-        // Simulate the user fixing the validation error, and then selecting an
-        // invalid printer. Dropdown is enabled, so that the user can fix the
-        // error.
-        destinationSettings.state = print_preview_new.State.READY;
-        destinationSettings.disabled = false;
-        destinationSettings.state = print_preview_new.State.INVALID_PRINTER;
-        destinationSettings.disabled = true;
-        assertFalse(dropdown.disabled);
+            assertEquals(
+                print_preview.DestinationState.INVALID,
+                destinationSettings.destinationState);
+            destinationSettings.disabled = true;
+            assertFalse(dropdown.disabled);
 
-        // Simulate the user having no printers.
-        destinationSettings.destination = null;
-        destinationSettings.state = print_preview_new.State.INVALID_PRINTER;
-        destinationSettings.disabled = true;
-        destinationSettings.noDestinationsFound = true;
-        assertTrue(dropdown.disabled);
-      });
+            if (cr.isChromeOS) {
+              // Simulate the user having no printers.
+              destinationSettings.destinationStore_.dispatchEvent(
+                  new CustomEvent(
+                      print_preview.DestinationStore.EventType.ERROR, {
+                        detail:
+                            print_preview.DestinationErrorType.NO_DESTINATIONS
+                      }));
+              Polymer.dom.flush();
+
+              assertEquals(
+                  print_preview.DestinationState.NO_DESTINATIONS,
+                  destinationSettings.destinationState);
+              destinationSettings.disabled = true;
+              assertTrue(dropdown.disabled);
+            }
+          });
     });
 
     /** @return {!print_preview.DestinationOrigin} */
@@ -144,39 +150,21 @@
      * |destinations| and |recentDestinations|.
      */
     function initialize() {
-      const destinationStore =
-          print_preview_test_utils.createDestinationStore();
-
       // Initialize destination settings.
-      destinationSettings.destinationStore = destinationStore;
-      destinationSettings.invitationStore = new print_preview.InvitationStore();
-      destinationSettings.recentDestinations = recentDestinations;
+      destinationSettings.setCloudPrintInterface(cloudPrintInterface);
+      destinationSettings.setSetting('recentDestinations', recentDestinations);
       destinationSettings.appKioskMode = false;
-      destinationSettings.activeUser = '';
-      destinationSettings.users = [];
+      destinationSettings.initDestinationStore(
+          '' /* printerName */,
+          '' /* serializedDefaultDestinationSelectionRulesStr */);
       destinationSettings.disabled = false;
-      destinationSettings.state = print_preview_new.State.READY;
-      destinationSettings.cloudPrintState =
-          print_preview.CloudPrintState.ENABLED;
-
-      // Initialize destination store.
-      destinationStore.setCloudPrintInterface(cloudPrintInterface);
-      destinationStore.init(
-          false /* isInAppKioskMode */, 'FooDevice' /* printerName */,
-          '' /* serializedDefaultDestinationSelectionRulesStr */,
-          recentDestinations);
     }
 
     /** Simulates a user signing in to Chrome. */
     function signIn() {
       cloudPrintInterface.setPrinter(
           print_preview_test_utils.getGoogleDriveDestination(defaultUser));
-      destinationSettings.activeUser = defaultUser;
-      destinationSettings.users = [defaultUser];
-      destinationSettings.cloudPrintState =
-          print_preview.CloudPrintState.SIGNED_IN;
-      destinationSettings.destinationStore.setActiveUser(defaultUser);
-      destinationSettings.destinationStore.onDestinationsReload();
+      cr.webUIListenerCallback('reload-printer-list');
       Polymer.dom.flush();
     }
 
@@ -376,7 +364,7 @@
             // Simulate selection of Save as PDF printer.
             const whenDestinationSelect = test_util.eventToPromise(
                 print_preview.DestinationStore.EventType.DESTINATION_SELECT,
-                destinationSettings.destinationStore);
+                destinationSettings.destinationStore_);
             dropdown.fire('selected-option-change', 'Save as PDF/local/');
 
             // Ensure this fires the destination select event.
@@ -385,7 +373,7 @@
           .then(() => {
             assertEquals(
                 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF,
-                destinationSettings.destinationStore.selectedDestination_.id);
+                destinationSettings.destination.id);
           });
     });
 
@@ -425,7 +413,7 @@
             // Simulate selection of Google Drive printer.
             const whenDestinationSelect = test_util.eventToPromise(
                 print_preview.DestinationStore.EventType.DESTINATION_SELECT,
-                destinationSettings.destinationStore);
+                destinationSettings.destinationStore_);
             dropdown.fire(
                 'selected-option-change',
                 '__google__docs/cookies/foo@chromium.org');
@@ -434,7 +422,7 @@
           .then(() => {
             assertEquals(
                 print_preview.Destination.GooglePromotedId.DOCS,
-                destinationSettings.destinationStore.selectedDestination_.id);
+                destinationSettings.destination.id);
           });
     });
 
@@ -468,15 +456,13 @@
             // Simulate selection of Save as PDF printer.
             const whenDestinationSelect = test_util.eventToPromise(
                 print_preview.DestinationStore.EventType.DESTINATION_SELECT,
-                destinationSettings.destinationStore);
+                destinationSettings.destinationStore_);
             dropdown.fire(
                 'selected-option-change', makeLocalDestinationKey('ID2'));
             return whenDestinationSelect;
           })
           .then(() => {
-            assertEquals(
-                'ID2',
-                destinationSettings.destinationStore.selectedDestination_.id);
+            assertEquals('ID2', destinationSettings.destination.id);
           });
     });
 
@@ -513,17 +499,6 @@
           });
     });
 
-    /*
-     * Simulates setting a new user account. Normally done in user_info.js.
-     * @param {string} newAccount
-     */
-    function updateUser(newAccount) {
-      destinationSettings.activeUser = newAccount;
-      destinationSettings.destinationStore.setActiveUser(newAccount);
-      destinationSettings.destinationStore.reloadUserCookieBasedDestinations(
-          newAccount);
-    }
-
     test(assert(TestNames.TwoAccountsRecentDestinations), function() {
       const account2 = 'bar@chromium.org';
       const driveUser1 =
@@ -551,10 +526,6 @@
       ].map(destination => print_preview.makeRecentDestination(destination));
 
       initialize();
-      destinationSettings.users = [defaultUser, account2];
-      destinationSettings.cloudPrintState =
-          print_preview.CloudPrintState.SIGNED_IN;
-      updateUser(defaultUser);
       Polymer.dom.flush();
 
       const dropdown = destinationSettings.$.destinationSelect;
@@ -580,11 +551,11 @@
             return test_util.waitForRender(destinationSettings);
           })
           .then(() => {
-            assertTrue(
-                destinationSettings.$$('print-preview-destination-dialog')
-                    .isOpen());
+            const dialog =
+                destinationSettings.$$('print-preview-destination-dialog');
+            assertTrue(dialog.isOpen());
             // Simulate setting a new account.
-            updateUser(account2);
+            dialog.fire('account-change', account2);
             Polymer.dom.flush();
             return test_util.waitForRender(destinationSettings);
           })
@@ -597,6 +568,57 @@
             ]);
           });
     });
+
+    /**
+     * @param {!Array<string>} expectedDestinationIds An array of the expected
+     *     recent destination ids.
+     */
+    function assertRecentDestinations(expectedDestinationIds) {
+      const recentDestinations =
+          destinationSettings.getSettingValue('recentDestinations');
+      assertEquals(expectedDestinationIds.length, recentDestinations.length);
+      expectedDestinationIds.forEach((expectedId, index) => {
+        assertEquals(expectedId, recentDestinations[index].id);
+      });
+    }
+
+    function selectDestination(destination) {
+      destinationSettings.destinationStore_.selectDestination(destination);
+      Polymer.dom.flush();
+    }
+
+    /**
+     * Tests that the destination being set correctly updates the recent
+     * destinations array.
+     */
+    test(assert(TestNames.UpdateRecentDestinations), function() {
+      // Recent destinations start out empty.
+      assertRecentDestinations([]);
+
+      initialize();
+
+      // Recent destinations start out empty.
+      assertRecentDestinations(['Save as PDF']);
+
+      // Simulate setting a destination.
+      selectDestination(destinations[0]);
+      assertRecentDestinations(['ID1', 'Save as PDF']);
+
+      // Reselect a recent destination. Still 2 destinations, but in a
+      // different order.
+      selectDestination(
+          destinationSettings.destinationStore_.getDestinationByKey(
+              'Save as PDF/local/')),
+          assertRecentDestinations(['Save as PDF', 'ID1']);
+
+      // Select a third destination
+      selectDestination(destinations[1]);
+      assertRecentDestinations(['ID2', 'Save as PDF', 'ID1']);
+
+      // Select a fourth destination. List does not grow.
+      selectDestination(destinations[2]);
+      assertRecentDestinations(['ID3', 'ID2', 'Save as PDF']);
+    });
   });
 
   return {
diff --git a/chrome/test/data/webui/print_preview/invalid_settings_browsertest.js b/chrome/test/data/webui/print_preview/invalid_settings_browsertest.js
index 46b056f..f9416e4 100644
--- a/chrome/test/data/webui/print_preview/invalid_settings_browsertest.js
+++ b/chrome/test/data/webui/print_preview/invalid_settings_browsertest.js
@@ -100,8 +100,6 @@
 
       createPage(true);
 
-      page.activeUser = 'foo@chromium.org';
-      page.users = [page.activeUser];
       cr.webUIListenerCallback('use-cloud-print', 'cloudprint url', false);
       printers.forEach(printer => cloudPrintInterface.setPrinter(printer));
     }
@@ -155,10 +153,11 @@
       const messageEl = previewAreaEl.$$('.preview-area-message');
       const header = page.$$('print-preview-header');
       const printButton = header.$$('.action-button');
+      const destinationSettings = page.$$('print-preview-destination-settings');
 
       return nativeLayer.whenCalled('getInitialSettings')
           .then(function() {
-            page.destinationStore_.startLoadAllDestinations();
+            destinationSettings.destinationStore_.startLoadAllDestinations();
             // Wait for the preview request.
             return Promise.all([
               nativeLayer.whenCalled('getPrinterCapabilities'),
@@ -178,15 +177,14 @@
             nativeLayer.reset();
 
             // Select a new destination
-            const barDestination = page.destinationStore_.destinations().find(
-                d => d.id == 'BarDevice');
-            page.destinationStore_.selectDestination(barDestination);
+            const barDestination =
+                destinationSettings.destinationStore_.destinations().find(
+                    d => d.id == 'BarDevice');
+            destinationSettings.destinationStore_.selectDestination(
+                barDestination);
 
             // Wait for the preview to be updated.
-            return Promise.all([
-              nativeLayer.whenCalled('getPrinterCapabilities'),
-              nativeLayer.whenCalled('getPreview')
-            ]);
+            return nativeLayer.whenCalled('getPreview');
           })
           .then(function() {
             // Message should be gone.
@@ -260,7 +258,7 @@
             // Set this to enable the scaling input.
             page.setSetting('customScaling', true);
 
-            page.destinationStore_.startLoadCloudDestinations();
+            destinationSettings.destinationStore_.startLoadCloudDestinations();
 
             // FooDevice will be selected since it is the most recently used
             // printer, so the invalid certificate error should be shown.
@@ -288,7 +286,9 @@
             nativeLayer.reset();
 
             // Select a new, valid cloud destination.
-            page.destinationStore_.selectDestination(validPrinter);
+            destinationSettings.destinationStore_.selectDestination(
+                validPrinter);
+
             return nativeLayer.whenCalled('getPreview');
           })
           .then(function() {
@@ -329,12 +329,15 @@
           const messageEl = previewAreaEl.$$('.preview-area-message');
           const header = page.$$('print-preview-header');
           const printButton = header.$$('.action-button');
+          const destinationSettings =
+              page.$$('print-preview-destination-settings');
 
           return nativeLayer.whenCalled('getInitialSettings')
               .then(function() {
                 // Start loading cloud destinations so that the printer
                 // capabilities arrive.
-                page.destinationStore_.startLoadCloudDestinations();
+                destinationSettings.destinationStore_
+                    .startLoadCloudDestinations();
                 return nativeLayer.whenCalled('getPreview');
               })
               .then(function() {
@@ -345,10 +348,10 @@
 
                 // Select the invalid destination and wait for the event.
                 const whenInvalid = test_util.eventToPromise(
-                    print_preview.DestinationStore.EventType
-                        .SELECTED_DESTINATION_UNSUPPORTED,
-                    page.destinationStore_);
-                page.destinationStore_.selectDestination(invalidPrinter);
+                    print_preview.DestinationStore.EventType.ERROR,
+                    destinationSettings.destinationStore_);
+                destinationSettings.destinationStore_.selectDestination(
+                    invalidPrinter);
                 return whenInvalid;
               })
               .then(function() {
@@ -361,8 +364,9 @@
                 // Reselect the valid cloud destination.
                 const whenSelected = test_util.eventToPromise(
                     print_preview.DestinationStore.EventType.DESTINATION_SELECT,
-                    page.destinationStore_);
-                page.destinationStore_.selectDestination(validPrinter);
+                    destinationSettings.destinationStore_);
+                destinationSettings.destinationStore_.selectDestination(
+                    validPrinter);
                 return whenSelected;
               })
               .then(function() {
diff --git a/chrome/test/data/webui/print_preview/model_test.js b/chrome/test/data/webui/print_preview/model_test.js
index f9a2091..6efc19c7 100644
--- a/chrome/test/data/webui/print_preview/model_test.js
+++ b/chrome/test/data/webui/print_preview/model_test.js
@@ -9,7 +9,6 @@
     SetPolicySettings: 'set policy settings',
     GetPrintTicket: 'get print ticket',
     GetCloudPrintTicket: 'get cloud print ticket',
-    UpdateRecentDestinations: 'update recent destinations',
     ChangeDestination: 'change destination'
   };
 
@@ -383,55 +382,6 @@
       expectEquals(expectedNewTicket, newTicket);
     });
 
-    /**
-     * @param {!Array<string>} expectedDestinationIds An array of the expected
-     *     recent destination ids.
-     */
-    function assertRecentDestinations(expectedDestinationIds) {
-      assertEquals(
-          expectedDestinationIds.length, model.recentDestinations.length);
-      expectedDestinationIds.forEach((expectedId, index) => {
-        assertEquals(expectedId, model.recentDestinations[index].id);
-      });
-    }
-
-    /**
-     * Tests that the destination being set correctly updates the recent
-     * destinations array.
-     */
-    test(assert(TestNames.UpdateRecentDestinations), function() {
-      initializeModel();
-      model.applyStickySettings();
-
-      let localDestinations = [];
-      let destinations =
-          print_preview_test_utils.getDestinations(null, localDestinations);
-
-      // Recent destinations start out empty.
-      assertRecentDestinations([]);
-
-      // Simulate setting a destination.
-      model.destination = destinations[0];
-      assertRecentDestinations(['ID1']);
-
-      // Set a new destination
-      model.destination = destinations[1];
-      assertRecentDestinations(['ID2', 'ID1']);
-
-      // Reselect a recent destination. Still 2 destinations, but in a
-      // different order.
-      model.destination = destinations[0];
-      assertRecentDestinations(['ID1', 'ID2']);
-
-      // Select a third destination
-      model.destination = destinations[2];
-      assertRecentDestinations(['ID3', 'ID1', 'ID2']);
-
-      // Select a fourth destination. List does not grow.
-      model.destination = destinations[3];
-      assertRecentDestinations(['ID4', 'ID3', 'ID1']);
-    });
-
     test(assert(TestNames.ChangeDestination), function() {
       const testDestination = new print_preview.Destination(
           'FooDevice', print_preview.DestinationType.LOCAL,
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 03508b3b..dbd57b9 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
@@ -291,10 +291,6 @@
   this.runMochaTest(model_test.TestNames.GetCloudPrintTicket);
 });
 
-TEST_F('PrintPreviewModelTest', 'UpdateRecentDestinations', function() {
-  this.runMochaTest(model_test.TestNames.UpdateRecentDestinations);
-});
-
 TEST_F('PrintPreviewModelTest', 'ChangeDestination', function() {
   this.runMochaTest(model_test.TestNames.ChangeDestination);
 });
@@ -566,7 +562,7 @@
 PrintPreviewDestinationSelectTest = class extends NewPrintPreviewTest {
   /** @override */
   get browsePreload() {
-    return 'chrome://print/new/app.html';
+    return 'chrome://print/new/destination_settings.html';
   }
 
   /** @override */
@@ -1206,6 +1202,13 @@
           destination_settings_test.TestNames.TwoAccountsRecentDestinations);
     });
 
+TEST_F(
+    'PrintPreviewDestinationSettingsTest', 'UpdateRecentDestinations',
+    function() {
+      this.runMochaTest(
+          destination_settings_test.TestNames.UpdateRecentDestinations);
+    });
+
 PrintPreviewScalingSettingsTest = class extends NewPrintPreviewTest {
   /** @override */
   get browsePreload() {
diff --git a/chrome/test/data/webui/print_preview/preview_generation_test.js b/chrome/test/data/webui/print_preview/preview_generation_test.js
index 9e75bad5..157e686c 100644
--- a/chrome/test/data/webui/print_preview/preview_generation_test.js
+++ b/chrome/test/data/webui/print_preview/preview_generation_test.js
@@ -360,6 +360,8 @@
                     .capabilities;
             nativeLayer.resetResolver('getPreview');
             page.set('destination_', barDestination);
+            page.destinationState_ = print_preview.DestinationState.SELECTED;
+            page.destinationState_ = print_preview.DestinationState.UPDATED;
             return nativeLayer.whenCalled('getPreview');
           })
           .then(function(args) {
diff --git a/chrome/test/data/webui/print_preview/print_button_test.js b/chrome/test/data/webui/print_preview/print_button_test.js
index f8cc50c0..e418ae6 100644
--- a/chrome/test/data/webui/print_preview/print_button_test.js
+++ b/chrome/test/data/webui/print_preview/print_button_test.js
@@ -74,7 +74,6 @@
     function waitForInitialPreview() {
       return nativeLayer.whenCalled('getInitialSettings')
           .then(function() {
-            page.destinationStore_.startLoadAllDestinations();
             // Wait for the preview request.
             return Promise.all([
               nativeLayer.whenCalled('getPrinterCapabilities'),
@@ -105,30 +104,30 @@
     test(assert(TestNames.PDFPrintVisiblePreview), function() {
       printBeforePreviewReady = false;
 
-      return waitForInitialPreview().then(function() {
-        // Setup to print before the preview loads.
-        printBeforePreviewReady = true;
+      return waitForInitialPreview()
+          .then(function() {
+            nativeLayer.reset();
+            // 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);
+            // Select Save as PDF destination
+            const pdfDestination = page.$$('print-preview-destination-settings')
+                                       .destinationStore_.destinations()
+                                       .find(d => d.id == 'Save as PDF');
+            assertTrue(!!pdfDestination);
+            page.$$('print-preview-destination-settings')
+                .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);
+            // Reload preview and wait for print.
+            return nativeLayer.whenCalled('print');
+          })
+          .then(function(printTicket) {
+            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');
-      });
+            // Verify that the printer name is correct.
+            assertEquals('Save as PDF', JSON.parse(printTicket).deviceName);
+            return nativeLayer.whenCalled('dialogClose');
+          });
     });
   });
 
diff --git a/chrome/test/data/webui/print_preview/print_preview_app_test.js b/chrome/test/data/webui/print_preview/print_preview_app_test.js
index d7bddbf..0aee7b7 100644
--- a/chrome/test/data/webui/print_preview/print_preview_app_test.js
+++ b/chrome/test/data/webui/print_preview/print_preview_app_test.js
@@ -40,34 +40,18 @@
       serializedDefaultDestinationSelectionRulesStr: null
     };
 
-    let localDestinations = [];
-    let cloudDestinations = [];
-
     /** @override */
     setup(function() {
       // Stub out the native layer, the cloud print interface, and the plugin.
       nativeLayer = new print_preview.NativeLayerStub();
       print_preview.NativeLayer.setInstance(nativeLayer);
+      nativeLayer.setInitialSettings(initialSettings);
+      nativeLayer.setLocalDestinationCapabilities(
+          print_preview_test_utils.getCddTemplate(initialSettings.printerName));
       cloudPrintInterface = new print_preview.CloudPrintInterfaceStub();
       cloudprint.setCloudPrintInterfaceForTesting(cloudPrintInterface);
       pluginProxy = new print_preview.PDFPluginStub();
       print_preview_new.PluginProxy.setInstance(pluginProxy);
-    });
-
-    /**
-     * Initializes the native layer and cloud print interface based on
-     * |initialSettings|, |localDestinations|, and |cloudDestinations|, and
-     * creates the page.
-     * @return {!Promise} Promise that resolves when the selected printer is
-     *     loaded.
-     */
-    function finishSetup() {
-      nativeLayer.setInitialSettings(initialSettings);
-      nativeLayer.setLocalDestinations(localDestinations);
-      nativeLayer.setLocalDestinationCapabilities(
-          print_preview_test_utils.getCddTemplate(initialSettings.printerName));
-      cloudDestinations.forEach(
-          destination => cloudPrintInterface.setPrinter(destination));
 
       PolymerTest.clearBody();
       page = document.createElement('print-preview-app');
@@ -75,35 +59,23 @@
       const previewArea = page.$.previewArea;
       pluginProxy.setLoadCallback(previewArea.onPluginLoad_.bind(previewArea));
       cr.webUIListenerCallback('use-cloud-print', 'cloudprint url', false);
-
-      return test_util.eventToPromise(
-          print_preview.DestinationStore.EventType
-              .SELECTED_DESTINATION_CAPABILITIES_READY,
-          page.destinationStore_);
-    }
+      return nativeLayer.whenCalled('getInitialSettings').then(() => {
+        page.destination_ = new print_preview.Destination(
+            'FooDevice', print_preview.DestinationType.LOCAL,
+            print_preview.DestinationOrigin.LOCAL, 'FooName',
+            print_preview.DestinationConnectionStatus.ONLINE);
+        page.destination_.capabilities =
+            print_preview_test_utils.getCddTemplate('FooDevice').capabilities;
+      });
+    });
 
     // Regression test for https://crbug.com/936029
     test(assert(TestNames.PrintToGoogleDrive), async () => {
-      // Set up the UI to have Google Drive as the most recent printer.
-      const account = 'foo@chromium.org';
-      const drivePrinter =
-          print_preview_test_utils.getGoogleDriveDestination(account);
-      const recentDestinations = [
-        print_preview.makeRecentDestination(drivePrinter),
-      ];
-      cloudDestinations = [drivePrinter];
-      initialSettings.serializedAppStateStr = JSON.stringify({
-        version: 2,
-        recentDestinations: recentDestinations,
-      });
-
-      await finishSetup();
-
-      // Should have loaded Google Drive as the selected printer, since it
-      // was most recent.
-      assertEquals(
-          print_preview.Destination.GooglePromotedId.DOCS,
-          page.destination_.id);
+      // Set up the UI to have Google Drive as the printer.
+      page.destination_ = print_preview_test_utils.getGoogleDriveDestination(
+          'foo@chromium.org');
+      page.destination_.capabilities =
+          print_preview_test_utils.getCddTemplate(page.destination_.id);
 
       // Trigger print.
       const header = page.$$('print-preview-header');
@@ -119,8 +91,7 @@
       assertEquals('1.0', JSON.parse(args.printTicket).version);
     });
 
-    test(assert(TestNames.SettingsSectionsVisibilityChange), async () => {
-      await finishSetup();
+    test(assert(TestNames.SettingsSectionsVisibilityChange), function() {
       const moreSettingsElement = page.$$('print-preview-more-settings');
       moreSettingsElement.$.label.click();
       const camelToKebab = s => s.replace(/([A-Z])/g, '-$1').toLowerCase();
@@ -138,9 +109,7 @@
           });
     });
 
-    test(assert(TestNames.PrintPresets), async () => {
-      await finishSetup();
-
+    test(assert(TestNames.PrintPresets), function() {
       assertEquals(1, page.settings.copies.value);
       page.setSetting('duplex', false);
       assertFalse(page.settings.duplex.value);
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn
index 4e6a6d6..31e79e3 100644
--- a/chromecast/BUILD.gn
+++ b/chromecast/BUILD.gn
@@ -568,9 +568,9 @@
 
 # A meta-target which repacks resources by locale.
 group("chromecast_locales_pak") {
-  deps = []
+  data_deps = []
   foreach(locale, cast_locales) {
-    deps += [ ":_cast_repack_${locale}" ]
+    data_deps += [ ":_cast_repack_${locale}" ]
   }
 }
 
diff --git a/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java b/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java
index 21d6f251..b8d94f9 100644
--- a/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java
+++ b/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java
@@ -13,6 +13,7 @@
 import android.media.AudioTrack;
 import android.os.Build;
 import android.os.SystemClock;
+import android.support.annotation.IntDef;
 import android.util.SparseIntArray;
 
 import org.chromium.base.ContextUtils;
@@ -21,6 +22,8 @@
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chromecast.media.AudioContentType;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 
@@ -134,19 +137,25 @@
     private ThrottledLog mUnderrunWarningLog;
     private ThrottledLog mTStampJitterWarningLog;
 
-    private enum ReferenceTimestampState {
-        STARTING_UP, // Starting up, no valid reference time yet.
-        STABLE, // Reference time exists and is updated regularly.
-        RESYNCING_AFTER_PAUSE, // Sync the timestamp after pause so that the renderer delay will be
-                               // correct.
-        RESYNCING_AFTER_UNDERRUN, // The AudioTrack hit an underrun and we need to find a new
-                                  // reference timestamp after the underrun point.
-        RESYNCING_AFTER_EXCESSIVE_TIMESTAMP_DRIFT, // We experienced excessive and consistent
-                                                   // jitters in the timestamps and we should find a
-                                                   // new reference timestamp.
+    @IntDef({ReferenceTimestampState.STARTING_UP, ReferenceTimestampState.STABLE,
+            ReferenceTimestampState.RESYNCING_AFTER_PAUSE,
+            ReferenceTimestampState.RESYNCING_AFTER_UNDERRUN,
+            ReferenceTimestampState.RESYNCING_AFTER_EXCESSIVE_TIMESTAMP_DRIFT})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface ReferenceTimestampState {
+        int STARTING_UP = 0; // Starting up, no valid reference time yet.
+        int STABLE = 1; // Reference time exists and is updated regularly.
+        int RESYNCING_AFTER_PAUSE = 2; // Sync the timestamp after pause so that the renderer delay
+                                       // will be correct.
+        int RESYNCING_AFTER_UNDERRUN = 3; // The AudioTrack hit an underrun and we need to find a
+                                          // new reference timestamp after the underrun point.
+        int RESYNCING_AFTER_EXCESSIVE_TIMESTAMP_DRIFT =
+                4; // We experienced excessive and consistent
+                   // jitters in the timestamps and we should find a
+                   // new reference timestamp.
     }
 
-    ReferenceTimestampState mReferenceTimestampState;
+    private @ReferenceTimestampState int mReferenceTimestampState;
 
     private boolean mIsInitialized;
 
@@ -630,7 +639,7 @@
         }
     }
 
-    private void resyncTimestamp(ReferenceTimestampState reason) {
+    private void resyncTimestamp(@ReferenceTimestampState int reason) {
         mLastTimestampUpdateNsec = NO_TIMESTAMP;
         mTimestampStabilityCounter = 0;
         mReferenceTimestampState = reason;
@@ -687,7 +696,7 @@
 
         long prevRefNanoTimeAtFramePos0 = mRefNanoTimeAtFramePos0;
         switch (mReferenceTimestampState) {
-            case STARTING_UP:
+            case ReferenceTimestampState.STARTING_UP:
                 // The Audiotrack produces a few timestamps at the beginning of time that are widely
                 // inaccurate. Hence, we require several stable timestamps before setting a
                 // reference point.
@@ -701,11 +710,11 @@
                         "First stable timestamp [" + mTimestampStabilityCounter + "/"
                                 + elapsedNsec(mTimestampStabilityStartTimeNsec) / 1000000 + "ms]");
                 break;
-            case RESYNCING_AFTER_PAUSE:
+            case ReferenceTimestampState.RESYNCING_AFTER_PAUSE:
             // fall-through
-            case RESYNCING_AFTER_EXCESSIVE_TIMESTAMP_DRIFT:
+            case ReferenceTimestampState.RESYNCING_AFTER_EXCESSIVE_TIMESTAMP_DRIFT:
             // fall-through
-            case RESYNCING_AFTER_UNDERRUN:
+            case ReferenceTimestampState.RESYNCING_AFTER_UNDERRUN:
                 // Resyncing happens after we hit a pause, underrun or excessive drift in the
                 // AudioTrack. This causes the Android Audio stack to insert additional samples,
                 // which increases the reference timestamp (at framePosition=0) by thousands of
@@ -730,7 +739,7 @@
                                 + elapsedNsec(mTimestampStabilityStartTimeNsec) / 1000000 + "ms]");
                 break;
 
-            case STABLE:
+            case ReferenceTimestampState.STABLE:
                 // Timestamps can be jittery, and on some systems they are occasionally off by
                 // hundreds of usecs. Filter out timestamps that are too jittery and use a low-pass
                 // filter on the smaller ones.
diff --git a/chromecast/media/cma/backend/audio_decoder_software_wrapper_unittest.cc b/chromecast/media/cma/backend/audio_decoder_software_wrapper_unittest.cc
index 09cbde4..7441d86 100644
--- a/chromecast/media/cma/backend/audio_decoder_software_wrapper_unittest.cc
+++ b/chromecast/media/cma/backend/audio_decoder_software_wrapper_unittest.cc
@@ -46,6 +46,7 @@
 
 TEST_F(AudioDecoderSoftwareWrapperTest, IsUsingSoftwareDecoder) {
   AudioConfig audio_config;
+  audio_config.channel_layout = ChannelLayout::STEREO;
   audio_config.sample_format = kSampleFormatS16;
   audio_config.bytes_per_channel = 2;
   audio_config.channel_number = 2;
diff --git a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
index 517e348..04f7dfc 100644
--- a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
+++ b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
@@ -72,6 +72,7 @@
 AudioConfig DefaultAudioConfig() {
   AudioConfig default_config;
   default_config.codec = kCodecPCM;
+  default_config.channel_layout = ChannelLayout::STEREO;
   default_config.sample_format = kSampleFormatS16;
   default_config.channel_number = 2;
   default_config.bytes_per_channel = 2;
@@ -466,6 +467,7 @@
   AudioConfig config;
   // First, make sure that kAudioCodecUnknown is not accepted.
   config.codec = kAudioCodecUnknown;
+  config.channel_layout = ChannelLayout::STEREO;
   config.sample_format = kSampleFormatS16;
   config.channel_number = 2;
   config.bytes_per_channel = 2;
diff --git a/chromecast/media/cma/backend/multizone_backend_unittest.cc b/chromecast/media/cma/backend/multizone_backend_unittest.cc
index 43ce10f..fc18fa7 100644
--- a/chromecast/media/cma/backend/multizone_backend_unittest.cc
+++ b/chromecast/media/cma/backend/multizone_backend_unittest.cc
@@ -318,6 +318,7 @@
                                       int playback_rate_change_count) {
   AudioConfig config;
   config.codec = kCodecPCM;
+  config.channel_layout = ChannelLayout::STEREO;
   config.sample_format = kSampleFormatPlanarF32;
   config.channel_number = 2;
   config.bytes_per_channel = 4;
@@ -334,6 +335,7 @@
 void MultizoneBackendTest::AddEffectsStreams() {
   AudioConfig effects_config;
   effects_config.codec = kCodecPCM;
+  effects_config.channel_layout = ChannelLayout::STEREO;
   effects_config.sample_format = kSampleFormatS16;
   effects_config.channel_number = 2;
   effects_config.bytes_per_channel = 2;
diff --git a/chromecast/media/cma/base/decoder_config_adapter.cc b/chromecast/media/cma/base/decoder_config_adapter.cc
index 933704f..9075813c 100644
--- a/chromecast/media/cma/base/decoder_config_adapter.cc
+++ b/chromecast/media/cma/base/decoder_config_adapter.cc
@@ -46,6 +46,25 @@
   return kAudioCodecUnknown;
 }
 
+ChannelLayout ToChannelLayout(const ::media::ChannelLayout channel_layout) {
+  switch (channel_layout) {
+    case ::media::ChannelLayout::CHANNEL_LAYOUT_UNSUPPORTED:
+      return ChannelLayout::UNSUPPORTED;
+    case ::media::ChannelLayout::CHANNEL_LAYOUT_MONO:
+      return ChannelLayout::MONO;
+    case ::media::ChannelLayout::CHANNEL_LAYOUT_STEREO:
+      return ChannelLayout::STEREO;
+    case ::media::ChannelLayout::CHANNEL_LAYOUT_5_1:
+      return ChannelLayout::SURROUND_5_1;
+    case ::media::ChannelLayout::CHANNEL_LAYOUT_BITSTREAM:
+      return ChannelLayout::BITSTREAM;
+
+    default:
+      NOTREACHED();
+      return ChannelLayout::UNSUPPORTED;
+  }
+}
+
 SampleFormat ToSampleFormat(const ::media::SampleFormat sample_format) {
   switch (sample_format) {
     case ::media::kUnknownSampleFormat:
@@ -74,15 +93,22 @@
   return kUnknownSampleFormat;
 }
 
-::media::ChannelLayout ToMediaChannelLayout(int channel_number) {
-  switch (channel_number) {
-    case 1:
+::media::ChannelLayout ToMediaChannelLayout(
+    const ChannelLayout channel_layout) {
+  switch (channel_layout) {
+    case ChannelLayout::UNSUPPORTED:
+      return ::media::ChannelLayout::CHANNEL_LAYOUT_UNSUPPORTED;
+    case ChannelLayout::MONO:
       return ::media::ChannelLayout::CHANNEL_LAYOUT_MONO;
-    case 2:
+    case ChannelLayout::STEREO:
       return ::media::ChannelLayout::CHANNEL_LAYOUT_STEREO;
-    case 6:
+    case ChannelLayout::SURROUND_5_1:
       return ::media::ChannelLayout::CHANNEL_LAYOUT_5_1;
+    case ChannelLayout::BITSTREAM:
+      return ::media::ChannelLayout::CHANNEL_LAYOUT_BITSTREAM;
+
     default:
+      NOTREACHED();
       return ::media::ChannelLayout::CHANNEL_LAYOUT_UNSUPPORTED;
   }
 }
@@ -192,12 +218,13 @@
   audio_config.codec = ToAudioCodec(config.codec());
   audio_config.sample_format = ToSampleFormat(config.sample_format());
   audio_config.bytes_per_channel = config.bytes_per_channel();
+  audio_config.channel_layout = ToChannelLayout(config.channel_layout());
   audio_config.channel_number =
       ::media::ChannelLayoutToChannelCount(config.channel_layout()),
   audio_config.samples_per_second = config.samples_per_second();
   audio_config.extra_data = config.extra_data();
-  audio_config.encryption_scheme = ToEncryptionScheme(
-      config.encryption_scheme());
+  audio_config.encryption_scheme =
+      ToEncryptionScheme(config.encryption_scheme());
 
 #if defined(OS_ANDROID)
   // On Android, Chromium's mp4 parser adds extra data for AAC, but we don't
@@ -215,9 +242,8 @@
   return ::media::AudioDecoderConfig(
       ToMediaAudioCodec(config.codec),
       ToMediaSampleFormat(config.sample_format),
-      ToMediaChannelLayout(config.channel_number), config.samples_per_second,
-      config.extra_data,
-      ToMediaEncryptionScheme(config.encryption_scheme));
+      ToMediaChannelLayout(config.channel_layout), config.samples_per_second,
+      config.extra_data, ToMediaEncryptionScheme(config.encryption_scheme));
 }
 
 // static
diff --git a/chromecast/public/media/decoder_config.h b/chromecast/public/media/decoder_config.h
index 4dc0acf..a81a9a22 100644
--- a/chromecast/public/media/decoder_config.h
+++ b/chromecast/public/media/decoder_config.h
@@ -20,6 +20,7 @@
 // Maximum audio sampling rate.
 static const int kMaxSampleRate = 192000;
 
+// TODO(guohuideng): change at least AudioCodec and SampleFormat to enum class.
 enum AudioCodec : int {
   kAudioCodecUnknown = 0,
   kCodecAAC,
@@ -38,6 +39,41 @@
   kAudioCodecMax = kCodecMpegHAudio,
 };
 
+enum class ChannelLayout {
+  UNSUPPORTED,
+
+  // Front C
+  MONO,
+
+  // Front L, Front R
+  STEREO,
+
+  // Front L, Front R, Front C, LFE, Side L, Side R
+  SURROUND_5_1,
+
+  // Actual channel layout is specified in the bitstream and the actual channel
+  // count is unknown at Chromium media pipeline level (useful for audio
+  // pass-through mode).
+  BITSTREAM,
+
+  // Max value, must always equal the largest entry ever logged.
+  MAX_LAST = BITSTREAM,
+};
+
+// Internal chromecast apps use this to decide on channel_layout.
+inline ChannelLayout ChannelLayoutFromChannelNumber(int channel_number) {
+  switch (channel_number) {
+    case 1:
+      return ChannelLayout::MONO;
+    case 2:
+      return ChannelLayout::STEREO;
+    case 6:
+      return ChannelLayout::SURROUND_5_1;
+    default:
+      return ChannelLayout::UNSUPPORTED;
+  }
+}
+
 enum SampleFormat : int {
   kUnknownSampleFormat = 0,
   kSampleFormatU8,         // Unsigned 8-bit w/ bias of 128.
@@ -238,6 +274,8 @@
   StreamId id;
   // Audio codec.
   AudioCodec codec;
+  // Audio channel layout.
+  ChannelLayout channel_layout;
   // The format of each audio sample.
   SampleFormat sample_format;
   // Number of bytes in each channel.
@@ -255,6 +293,7 @@
 inline AudioConfig::AudioConfig()
     : id(kPrimary),
       codec(kAudioCodecUnknown),
+      channel_layout(ChannelLayout::UNSUPPORTED),
       sample_format(kUnknownSampleFormat),
       bytes_per_channel(0),
       channel_number(0),
@@ -313,19 +352,15 @@
 inline VideoConfig::~VideoConfig() {
 }
 
-// TODO(erickung): Remove following two inline IsValidConfig() functions. These
-// are to keep existing CMA backend implementation consistent until the clean up
-// is done. These SHOULD NOT be used in New CMA backend implementation.
 inline bool IsValidConfig(const AudioConfig& config) {
   return config.codec >= kAudioCodecMin && config.codec <= kAudioCodecMax &&
          config.codec != kAudioCodecUnknown &&
+         config.channel_layout != ChannelLayout::UNSUPPORTED &&
          config.sample_format >= kSampleFormatMin &&
          config.sample_format <= kSampleFormatMax &&
          config.sample_format != kUnknownSampleFormat &&
-         // TODO(servolk): Add channel_layout field to the AudioConfig in the
-         // next Cast system update and change this condition to
-         // (channel_number > 0 || channel_layout == CHANNEL_LAYOUT_BITSTREAM)
-         (config.channel_number > 0 || config.codec == kCodecMpegHAudio) &&
+         (config.channel_number > 0 ||
+          config.channel_layout == ChannelLayout::BITSTREAM) &&
          config.bytes_per_channel > 0 &&
          config.bytes_per_channel <= kMaxBytesPerSample &&
          config.samples_per_second > 0 &&
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.cc b/chromeos/services/assistant/assistant_manager_service_impl.cc
index a545aee0..626546ac 100644
--- a/chromeos/services/assistant/assistant_manager_service_impl.cc
+++ b/chromeos/services/assistant/assistant_manager_service_impl.cc
@@ -63,6 +63,7 @@
 constexpr char kScreenBrightnessDeviceSettingId[] = "BRIGHTNESS_LEVEL";
 constexpr char kDoNotDisturbDeviceSettingId[] = "DO_NOT_DISTURB";
 constexpr char kNightLightDeviceSettingId[] = "NIGHT_LIGHT_SWITCH";
+constexpr char kIntentActionView[] = "android.intent.action.VIEW";
 
 constexpr base::Feature kChromeOSAssistantDogfood{
     "ChromeOSAssistantDogfood", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -206,9 +207,16 @@
   // Register handler for media actions.
   assistant_manager_internal_->RegisterFallbackMediaHandler(
       [this](std::string play_media_args_proto) {
-        std::string url = GetWebUrlFromMediaArgs(play_media_args_proto);
-        if (!url.empty()) {
-          OnOpenUrl(url);
+        std::unique_ptr<action::AndroidAppInfo> android_app_info =
+            GetAndroidAppInfoFromMediaArgs(play_media_args_proto);
+        if (android_app_info) {
+          OnOpenMediaAndroidIntent(play_media_args_proto,
+                                   android_app_info.get());
+        } else {
+          std::string url = GetWebUrlFromMediaArgs(play_media_args_proto);
+          // Fallack to web URL.
+          if (!url.empty())
+            OnOpenUrl(url);
         }
       });
 }
@@ -517,7 +525,7 @@
     const std::vector<action::AndroidAppInfo>& apps_info,
     const action::InteractionInfo& interaction) {
   std::vector<mojom::AndroidAppInfoPtr> apps_info_list;
-  for (auto app_info : apps_info) {
+  for (auto& app_info : apps_info) {
     mojom::AndroidAppInfoPtr app_info_ptr = mojom::AndroidAppInfo::New();
     app_info_ptr->package_name = app_info.package_name;
     apps_info_list.push_back(std::move(app_info_ptr));
@@ -529,6 +537,31 @@
           weak_factory_.GetWeakPtr(), interaction));
 }
 
+void AssistantManagerServiceImpl::OnOpenMediaAndroidIntent(
+    const std::string play_media_args_proto,
+    action::AndroidAppInfo* android_app_info) {
+  ENSURE_MAIN_THREAD(&AssistantManagerServiceImpl::OnOpenMediaAndroidIntent,
+                     play_media_args_proto, android_app_info);
+
+  // Handle android media playback intent.
+  mojom::AndroidAppInfoPtr app_info_ptr = mojom::AndroidAppInfo::New();
+  app_info_ptr->package_name = android_app_info->package_name;
+  app_info_ptr->action = kIntentActionView;
+  if (!android_app_info->intent.empty()) {
+    app_info_ptr->intent = android_app_info->intent;
+  } else {
+    std::string url = GetAndroidIntentUrlFromMediaArgs(play_media_args_proto);
+    if (!url.empty()) {
+      app_info_ptr->intent = url;
+    }
+  }
+  service_->device_actions()->OpenAndroidApp(
+      std::move(app_info_ptr),
+      base::BindOnce(
+          &AssistantManagerServiceImpl::HandleLaunchMediaIntentResponse,
+          weak_factory_.GetWeakPtr()));
+}
+
 void AssistantManagerServiceImpl::OnRecognitionStateChanged(
     assistant_client::ConversationStateListener::RecognitionState state,
     const assistant_client::ConversationStateListener::RecognitionResult&
@@ -830,6 +863,12 @@
     assistant_settings_manager_->SyncSpeakerIdEnrollmentStatus();
 }
 
+void AssistantManagerServiceImpl::HandleLaunchMediaIntentResponse(
+    bool app_opened) {
+  // TODO(llin): Handle the response.
+  NOTIMPLEMENTED();
+}
+
 void AssistantManagerServiceImpl::HandleOpenAndroidAppResponse(
     const action::InteractionInfo& interaction,
     bool app_opened) {
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.h b/chromeos/services/assistant/assistant_manager_service_impl.h
index b4f4a36d..3576fcc 100644
--- a/chromeos/services/assistant/assistant_manager_service_impl.h
+++ b/chromeos/services/assistant/assistant_manager_service_impl.h
@@ -196,6 +196,8 @@
       const action::InteractionInfo& interaction,
       std::vector<mojom::AndroidAppInfoPtr> apps_info);
 
+  void HandleLaunchMediaIntentResponse(bool app_opened);
+
   void OnConversationTurnStartedOnMainThread(bool is_mic_open);
   void OnConversationTurnFinishedOnMainThread(
       assistant_client::ConversationStateListener::Resolution resolution);
@@ -216,6 +218,8 @@
   void OnRespondingStartedOnMainThread(bool is_error_response);
   void OnSpeechLevelUpdatedOnMainThread(const float speech_level);
   void OnModifySettingsAction(const std::string& modify_setting_args_proto);
+  void OnOpenMediaAndroidIntent(const std::string play_media_args_proto,
+                                action::AndroidAppInfo* android_app_info);
 
   void RegisterFallbackMediaHandler();
 
diff --git a/chromeos/services/assistant/platform/audio_input_impl.cc b/chromeos/services/assistant/platform/audio_input_impl.cc
index 88f10e5..0997623e 100644
--- a/chromeos/services/assistant/platform/audio_input_impl.cc
+++ b/chromeos/services/assistant/platform/audio_input_impl.cc
@@ -9,6 +9,7 @@
 #include "base/stl_util.h"
 #include "base/timer/timer.h"
 #include "chromeos/services/assistant/public/features.h"
+#include "chromeos/services/assistant/utils.h"
 #include "libassistant/shared/public/platform_audio_buffer.h"
 #include "media/audio/audio_device_description.h"
 #include "media/base/audio_parameters.h"
@@ -23,11 +24,11 @@
 namespace {
 
 constexpr assistant_client::BufferFormat kFormatMono{
-    16000 /* sample_rate */, assistant_client::INTERLEAVED_S32, 1 /* channels */
+    16000 /* sample_rate */, assistant_client::INTERLEAVED_S16, 1 /* channels */
 };
 
 constexpr assistant_client::BufferFormat kFormatStereo{
-    16000 /* sample_rate */, assistant_client::INTERLEAVED_S32, 2 /* channels */
+    44100 /* sample_rate */, assistant_client::INTERLEAVED_S16, 2 /* channels */
 };
 
 assistant_client::BufferFormat g_current_format = kFormatMono;
@@ -193,12 +194,12 @@
 
   state_manager_->OnCaptureDataArrived();
 
-  std::vector<int32_t> buffer(audio_source->channels() *
+  std::vector<int16_t> buffer(audio_source->channels() *
                               audio_source->frames());
-  audio_source->ToInterleaved<media::SignedInt32SampleTypeTraits>(
+  audio_source->ToInterleaved<media::SignedInt16SampleTypeTraits>(
       audio_source->frames(), buffer.data());
-  int64_t time = base::TimeTicks::Now().since_origin().InMilliseconds() -
-                 audio_delay_milliseconds;
+  int64_t time = base::TimeTicks::Now().since_origin().InMicroseconds() -
+                 1000 * audio_delay_milliseconds;
   AudioInputBufferImpl input_buffer(buffer.data(), audio_source->frames());
   {
     base::AutoLock lock(lock_);
@@ -211,7 +212,7 @@
     auto now = base::TimeTicks::Now();
     if ((now - last_frame_count_report_time_) >
         base::TimeDelta::FromMinutes(2)) {
-      VLOG(1) << "Captured frames: " << captured_frames_count_;
+      VLOG(1) << device_id_ << " captured frames: " << captured_frames_count_;
       last_frame_count_report_time_ = now;
     }
   }
@@ -219,7 +220,7 @@
 
 // Runs on audio service thread.
 void AudioInputImpl::OnCaptureError(const std::string& message) {
-  LOG(ERROR) << "Capture error " << message;
+  LOG(ERROR) << device_id_ << " capture error " << message;
   base::AutoLock lock(lock_);
   for (auto* observer : observers_)
     observer->OnAudioError(AudioInput::Error::FATAL_ERROR);
@@ -237,7 +238,7 @@
 void AudioInputImpl::AddObserver(
     assistant_client::AudioInput::Observer* observer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(observer_sequence_checker_);
-  VLOG(1) << "Add observer";
+  VLOG(1) << device_id_ << " add observer";
   bool have_first_observer = false;
   {
     base::AutoLock lock(lock_);
@@ -259,7 +260,7 @@
 void AudioInputImpl::RemoveObserver(
     assistant_client::AudioInput::Observer* observer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(observer_sequence_checker_);
-  VLOG(1) << "Remove observer";
+  VLOG(1) << device_id_ << " remove observer";
   bool have_no_observer = false;
   {
     base::AutoLock lock(lock_);
@@ -345,7 +346,7 @@
 
   source_->Initialize(param, this);
   source_->Start();
-  VLOG(1) << "Start recording";
+  VLOG(1) << device_id_ << " start recording";
 }
 
 bool AudioInputImpl::IsHotwordAvailable() {
@@ -361,10 +362,11 @@
 void AudioInputImpl::StopRecording() {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
   if (source_) {
-    VLOG(1) << "Stop recording";
+    VLOG(1) << device_id_ << " stop recording";
     source_->Stop();
     source_.reset();
-    VLOG(1) << "Ending captured frames: " << captured_frames_count_;
+    VLOG(1) << device_id_
+            << " ending captured frames: " << captured_frames_count_;
   }
 }
 
diff --git a/chromeos/services/assistant/platform/audio_input_impl.h b/chromeos/services/assistant/platform/audio_input_impl.h
index ed70da3..fc46811 100644
--- a/chromeos/services/assistant/platform/audio_input_impl.h
+++ b/chromeos/services/assistant/platform/audio_input_impl.h
@@ -91,7 +91,7 @@
   scoped_refptr<media::AudioCapturerSource> source_;
 
   // Should audio input always recording actively.
-  bool default_on_ = false;
+  bool default_on_ = true;
 
   // User explicitly requested to open microphone.
   bool mic_open_ = false;
diff --git a/chromeos/services/assistant/platform/audio_input_provider_impl.cc b/chromeos/services/assistant/platform/audio_input_provider_impl.cc
index 3c70135f..bf4b8c2 100644
--- a/chromeos/services/assistant/platform/audio_input_provider_impl.cc
+++ b/chromeos/services/assistant/platform/audio_input_provider_impl.cc
@@ -4,6 +4,8 @@
 
 #include "chromeos/services/assistant/platform/audio_input_provider_impl.h"
 
+#include "chromeos/services/assistant/public/features.h"
+
 namespace chromeos {
 namespace assistant {
 
@@ -20,7 +22,9 @@
 }
 
 int64_t AudioInputProviderImpl::GetCurrentAudioTime() {
-  // TODO(xiaohuic): see if we can support real timestamp.
+  if (features::IsAudioEraserEnabled())
+    return base::TimeTicks::Now().since_origin().InMicroseconds();
+
   return 0;
 }
 
diff --git a/chromeos/services/assistant/platform/audio_output_provider_impl.cc b/chromeos/services/assistant/platform/audio_output_provider_impl.cc
index 5fae1867..6e53cd54 100644
--- a/chromeos/services/assistant/platform/audio_output_provider_impl.cc
+++ b/chromeos/services/assistant/platform/audio_output_provider_impl.cc
@@ -14,6 +14,7 @@
 #include "chromeos/services/assistant/public/mojom/assistant_audio_decoder.mojom.h"
 #include "chromeos/services/assistant/public/mojom/constants.mojom.h"
 #include "libassistant/shared/public/platform_audio_buffer.h"
+#include "media/audio/audio_device_description.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 namespace chromeos {
@@ -123,7 +124,10 @@
     AssistantMediaSession* media_session,
     scoped_refptr<base::SequencedTaskRunner> background_task_runner,
     const std::string& device_id)
-    : volume_control_impl_(connector, media_session),
+    : loop_back_input_(connector,
+                       media::AudioDeviceDescription::kLoopbackInputDeviceId,
+                       /*hotword_device_id=*/std::string()),
+      volume_control_impl_(connector, media_session),
       connector_(connector),
       main_task_runner_(base::SequencedTaskRunnerHandle::Get()),
       background_task_runner_(background_task_runner),
@@ -157,8 +161,7 @@
 }
 
 assistant_client::AudioInput* AudioOutputProviderImpl::GetReferenceInput() {
-  // TODO(muyuanli): implement.
-  return nullptr;
+  return &loop_back_input_;
 }
 
 bool AudioOutputProviderImpl::SupportsPlaybackTimestamp() const {
diff --git a/chromeos/services/assistant/platform/audio_output_provider_impl.h b/chromeos/services/assistant/platform/audio_output_provider_impl.h
index 287e44b..a68f9f5 100644
--- a/chromeos/services/assistant/platform/audio_output_provider_impl.h
+++ b/chromeos/services/assistant/platform/audio_output_provider_impl.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/single_thread_task_runner.h"
 #include "chromeos/services/assistant/platform/audio_device_owner.h"
+#include "chromeos/services/assistant/platform/audio_input_impl.h"
 #include "chromeos/services/assistant/platform/volume_control_impl.h"
 #include "chromeos/services/assistant/public/mojom/assistant_audio_decoder.mojom.h"
 #include "libassistant/shared/public/platform_audio_output.h"
@@ -54,6 +55,7 @@
       AudioEmittingStateCallback callback) override;
 
  private:
+  AudioInputImpl loop_back_input_;
   VolumeControlImpl volume_control_impl_;
   service_manager::Connector* connector_;
   scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
diff --git a/chromeos/services/assistant/public/features.cc b/chromeos/services/assistant/public/features.cc
index 1dde5ad..b48fb73 100644
--- a/chromeos/services/assistant/public/features.cc
+++ b/chromeos/services/assistant/public/features.cc
@@ -10,6 +10,9 @@
 namespace assistant {
 namespace features {
 
+const base::Feature kAssistantAudioEraser{"AssistantAudioEraser",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kAssistantFeedbackUi{"AssistantFeedbackUi",
                                          base::FEATURE_ENABLED_BY_DEFAULT};
 
@@ -64,6 +67,10 @@
       assistant::features::kAssistantAppSupport);
 }
 
+bool IsAudioEraserEnabled() {
+  return base::FeatureList::IsEnabled(kAssistantAudioEraser);
+}
+
 bool IsClearCutLogEnabled() {
   return base::FeatureList::IsEnabled(kEnableClearCutLog);
 }
@@ -80,12 +87,26 @@
   return base::FeatureList::IsEnabled(kInAssistantNotifications);
 }
 
+bool IsKeyRemappingEnabled() {
+  return base::FeatureList::IsEnabled(kAssistantKeyRemapping);
+}
+
+bool IsPowerManagerEnabled() {
+  return base::FeatureList::IsEnabled(kEnablePowerManager);
+}
+
 bool IsRoutinesEnabled() {
   return base::FeatureList::IsEnabled(kAssistantRoutines);
 }
 
+bool IsScreenContextQueryEnabled() {
+  return base::FeatureList::IsEnabled(kScreenContextQuery);
+}
+
 bool IsStereoAudioInputEnabled() {
-  return base::FeatureList::IsEnabled(kEnableStereoAudioInput);
+  return base::FeatureList::IsEnabled(kEnableStereoAudioInput) ||
+         // Audio eraser requires 2 channel input.
+         base::FeatureList::IsEnabled(kAssistantAudioEraser);
 }
 
 bool IsTimerNotificationEnabled() {
@@ -100,18 +121,6 @@
   return base::FeatureList::IsEnabled(kAssistantWarmerWelcomeFeature);
 }
 
-bool IsPowerManagerEnabled() {
-  return base::FeatureList::IsEnabled(kEnablePowerManager);
-}
-
-bool IsKeyRemappingEnabled() {
-  return base::FeatureList::IsEnabled(kAssistantKeyRemapping);
-}
-
-bool IsScreenContextQueryEnabled() {
-  return base::FeatureList::IsEnabled(kScreenContextQuery);
-}
-
 }  // namespace features
 }  // namespace assistant
 }  // namespace chromeos
diff --git a/chromeos/services/assistant/public/features.h b/chromeos/services/assistant/public/features.h
index f9fdada..abd109c 100644
--- a/chromeos/services/assistant/public/features.h
+++ b/chromeos/services/assistant/public/features.h
@@ -14,6 +14,10 @@
 
 // Enable Assistant Feedback UI.
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
+extern const base::Feature kAssistantAudioEraser;
+
+// Enable Assistant Feedback UI.
+COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
 extern const base::Feature kAssistantFeedbackUi;
 
 // Enables Assistant voice match enrollment.
@@ -74,6 +78,8 @@
 
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsAppSupportEnabled();
 
+COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsAudioEraserEnabled();
+
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsClearCutLogEnabled();
 
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsDspHotwordEnabled();
@@ -83,8 +89,14 @@
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC)
 bool IsInAssistantNotificationsEnabled();
 
+COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsKeyRemappingEnabled();
+
+COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsPowerManagerEnabled();
+
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsRoutinesEnabled();
 
+COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsScreenContextQueryEnabled();
+
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsStereoAudioInputEnabled();
 
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsTimerNotificationEnabled();
@@ -93,11 +105,6 @@
 
 COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsWarmerWelcomeEnabled();
 
-COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsKeyRemappingEnabled();
-
-COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsScreenContextQueryEnabled();
-
-COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) bool IsPowerManagerEnabled();
 
 }  // namespace features
 }  // namespace assistant
diff --git a/chromeos/services/assistant/public/mojom/assistant.mojom b/chromeos/services/assistant/public/mojom/assistant.mojom
index 339b2c3..3fbc76e 100644
--- a/chromeos/services/assistant/public/mojom/assistant.mojom
+++ b/chromeos/services/assistant/public/mojom/assistant.mojom
@@ -271,11 +271,23 @@
 
 // Models an Android app.
 struct AndroidAppInfo {
+  // Unique name to identify a specific app.
   string package_name;
+
+  // Version number of the app.
   int32 version;
+
+  // Localized app name.
   string localized_app_name;
+
+  // Intent data to operate on.
   string intent;
+
+  // Status of the app.
   AppStatus status;
+
+  // The general action to be performed, such as ACTION_VIEW, ACTION_MAIN, etc.
+  string action;
 };
 
 //  Details for Assistant feedback.
diff --git a/chromeos/services/assistant/service_unittest.cc b/chromeos/services/assistant/service_unittest.cc
index 01ee656c..585334e73 100644
--- a/chromeos/services/assistant/service_unittest.cc
+++ b/chromeos/services/assistant/service_unittest.cc
@@ -76,9 +76,6 @@
 
   void GetPrimaryAccountWhenAvailable(
       GetPrimaryAccountWhenAvailableCallback callback) override {}
-  void GetAccountInfoFromGaiaId(
-      const std::string& gaia_id,
-      GetAccountInfoFromGaiaIdCallback callback) override {}
   void GetAccessToken(const std::string& account_id,
                       const ::identity::ScopeSet& scopes,
                       const std::string& consumer_id,
diff --git a/chromeos/services/assistant/utils.cc b/chromeos/services/assistant/utils.cc
index ff0fd1f..49cbf7c 100644
--- a/chromeos/services/assistant/utils.cc
+++ b/chromeos/services/assistant/utils.cc
@@ -14,6 +14,7 @@
 #include "base/values.h"
 #include "chromeos/assistant/internal/internal_constants.h"
 #include "chromeos/dbus/util/version_loader.h"
+#include "chromeos/services/assistant/public/features.h"
 
 namespace chromeos {
 namespace assistant {
@@ -71,6 +72,15 @@
   Value audio_input(Type::DICTIONARY);
   // Skip sending speaker ID selection info to disable user verification.
   audio_input.SetKey("should_send_speaker_id_selection_info", Value(false));
+
+  Value sources(Type::LIST);
+  Value dict(Type::DICTIONARY);
+  dict.SetKey("enable_eraser", Value(features::IsAudioEraserEnabled()));
+  dict.SetKey("enable_eraser_toggling",
+              Value(features::IsAudioEraserEnabled()));
+  sources.GetList().push_back(std::move(dict));
+  audio_input.SetKey("sources", std::move(sources));
+
   config.SetKey("audio_input", std::move(audio_input));
 
   std::string json;
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 4dbc6a7..948478e 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -570,6 +570,7 @@
       sources += [ "dom_distiller/standalone/content_extractor_browsertest.cc" ]
       deps += [
         "//components/leveldb_proto",
+        "//components/leveldb_proto/content:factory",
         "//components/prefs:test_support",
         "//components/sync_preferences:test_support",
       ]
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index b3ea166..28bae00 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -93,8 +93,6 @@
     "autofill_subject.h",
     "autofill_type.cc",
     "autofill_type.h",
-    "autofill_wallet_data_type_controller.cc",
-    "autofill_wallet_data_type_controller.h",
     "contact_form_label_formatter.cc",
     "contact_form_label_formatter.h",
     "contact_info.cc",
@@ -145,6 +143,8 @@
     "password_requirements_spec_printer.cc",
     "password_requirements_spec_printer.h",
     "payments/account_info_getter.h",
+    "payments/autofill_wallet_data_type_controller.cc",
+    "payments/autofill_wallet_data_type_controller.h",
     "payments/autofill_wallet_model_type_controller.cc",
     "payments/autofill_wallet_model_type_controller.h",
     "payments/card_unmask_delegate.cc",
@@ -541,7 +541,6 @@
     "autofill_profile_validator_unittest.cc",
     "autofill_subject_unittest.cc",
     "autofill_type_unittest.cc",
-    "autofill_wallet_data_type_controller_unittest.cc",
     "contact_info_unittest.cc",
     "country_combobox_model_unittest.cc",
     "country_names_unittest.cc",
@@ -557,6 +556,7 @@
     "password_generator_fips181_unittest.cc",
     "password_generator_unittest.cc",
     "password_requirements_spec_fetcher_unittest.cc",
+    "payments/autofill_wallet_data_type_controller_unittest.cc",
     "payments/credit_card_save_manager_unittest.cc",
     "payments/full_card_request_unittest.cc",
     "payments/legacy_strike_database_unittest.cc",
diff --git a/components/autofill/core/browser/autofill_wallet_data_type_controller.cc b/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.cc
similarity index 95%
rename from components/autofill/core/browser/autofill_wallet_data_type_controller.cc
rename to components/autofill/core/browser/payments/autofill_wallet_data_type_controller.cc
index 7ad8b87..caeb3e4 100644
--- a/components/autofill/core/browser/autofill_wallet_data_type_controller.cc
+++ b/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/autofill/core/browser/autofill_wallet_data_type_controller.h"
+#include "components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h"
 
 #include <utility>
 
@@ -22,7 +22,7 @@
 AutofillWalletDataTypeController::AutofillWalletDataTypeController(
     syncer::ModelType type,
     scoped_refptr<base::SingleThreadTaskRunner> db_thread,
-    const base::Closure& dump_stack,
+    const base::RepeatingClosure& dump_stack,
     syncer::SyncService* sync_service,
     syncer::SyncClient* sync_client,
     const PersonalDataManagerProvider& pdm_provider,
@@ -69,8 +69,8 @@
 
   if (!callback_registered_) {
     web_data_service_->RegisterDBLoadedCallback(
-        base::Bind(&AutofillWalletDataTypeController::OnModelLoaded,
-                   base::AsWeakPtr(this)));
+        base::BindRepeating(&AutofillWalletDataTypeController::OnModelLoaded,
+                            base::AsWeakPtr(this)));
     callback_registered_ = true;
   }
 
diff --git a/components/autofill/core/browser/autofill_wallet_data_type_controller.h b/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h
similarity index 88%
rename from components/autofill/core/browser/autofill_wallet_data_type_controller.h
rename to components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h
index be0e0fff..af98486 100644
--- a/components/autofill/core/browser/autofill_wallet_data_type_controller.h
+++ b/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
 
 #include "base/callback.h"
 #include "base/macros.h"
@@ -35,7 +35,7 @@
   AutofillWalletDataTypeController(
       syncer::ModelType type,
       scoped_refptr<base::SingleThreadTaskRunner> db_thread,
-      const base::Closure& dump_stack,
+      const base::RepeatingClosure& dump_stack,
       syncer::SyncService* sync_service,
       syncer::SyncClient* sync_client,
       const PersonalDataManagerProvider& pdm_provider,
@@ -78,4 +78,4 @@
 
 }  // namespace browser_sync
 
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
diff --git a/components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc b/components/autofill/core/browser/payments/autofill_wallet_data_type_controller_unittest.cc
similarity index 90%
rename from components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc
rename to components/autofill/core/browser/payments/autofill_wallet_data_type_controller_unittest.cc
index c8a98af..1c5d218a 100644
--- a/components/autofill/core/browser/autofill_wallet_data_type_controller_unittest.cc
+++ b/components/autofill/core/browser/payments/autofill_wallet_data_type_controller_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/autofill/core/browser/autofill_wallet_data_type_controller.h"
+#include "components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h"
 
 #include <memory>
 
@@ -47,7 +47,7 @@
       const scoped_refptr<base::SingleThreadTaskRunner>& db_task_runner)
       : AutofillWebDataService(ui_task_runner, db_task_runner),
         is_database_loaded_(false),
-        db_loaded_callback_(base::Callback<void(void)>()) {}
+        db_loaded_callback_(base::RepeatingCallback<void(void)>()) {}
 
   // Mark the database as loaded and send out the appropriate notification.
   void LoadDatabase() {
@@ -57,14 +57,17 @@
       db_loaded_callback_.Run();
       // Clear the callback here or the WDS and DTC will have refs to each other
       // and create a memory leak.
-      db_loaded_callback_ = base::Callback<void(void)>();
+      // TODO(crbug.com/941530): Solve this with a OnceCallback. Note that
+      //     RegisterDBLoadedCallback overrides other functions that still use
+      //     base::[Repeating]Callbacks, so it would affect non-Autofill code.
+      db_loaded_callback_ = base::RepeatingCallback<void(void)>();
     }
   }
 
   bool IsDatabaseLoaded() override { return is_database_loaded_; }
 
   void RegisterDBLoadedCallback(
-      const base::Callback<void(void)>& callback) override {
+      const base::RepeatingCallback<void(void)>& callback) override {
     db_loaded_callback_ = callback;
   }
 
@@ -72,7 +75,7 @@
   ~FakeWebDataService() override {}
 
   bool is_database_loaded_;
-  base::Callback<void(void)> db_loaded_callback_;
+  base::RepeatingCallback<void(void)> db_loaded_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeWebDataService);
 };
@@ -123,13 +126,14 @@
   void Start() {
     autofill_wallet_dtc_->LoadModels(
         syncer::ConfigureContext(),
-        base::Bind(&AutofillWalletDataTypeControllerTest::OnLoadFinished,
-                   base::Unretained(this)));
+        base::BindRepeating(
+            &AutofillWalletDataTypeControllerTest::OnLoadFinished,
+            base::Unretained(this)));
     base::RunLoop().RunUntilIdle();
     if (autofill_wallet_dtc_->state() !=
         syncer::DataTypeController::MODEL_LOADED)
       return;
-    autofill_wallet_dtc_->StartAssociating(base::Bind(
+    autofill_wallet_dtc_->StartAssociating(base::BindRepeating(
         &syncer::StartCallbackMock::Run, base::Unretained(&start_callback_)));
     base::RunLoop().RunUntilIdle();
   }
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index 7237048..b953a1b 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -25,7 +25,7 @@
   }
   oneof client { Chrome chrome = 1; }
 
-  // locale should be a comma separated list of language tags. Each tag should
+  // locale will be the language tag of the default locale. The tag should
   // be a well-formed IETF BCP 47 language tag with language and country code
   // (e.g., "en-US").
   // The intent is to communicate the client language preferences to the server.
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc
index 7fc51a1..c669f35 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -11,7 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
 #include "build/build_config.h"
-#include "components/autofill/core/browser/autofill_wallet_data_type_controller.h"
+#include "components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h"
 #include "components/autofill/core/browser/payments/autofill_wallet_model_type_controller.h"
 #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h"
diff --git a/components/dom_distiller/core/dom_distiller_service_unittest.cc b/components/dom_distiller/core/dom_distiller_service_unittest.cc
index 5fe955c..d781a985c 100644
--- a/components/dom_distiller/core/dom_distiller_service_unittest.cc
+++ b/components/dom_distiller/core/dom_distiller_service_unittest.cc
@@ -92,7 +92,7 @@
         std::unique_ptr<DistillerFactory>(distiller_factory_),
         std::unique_ptr<DistillerPageFactory>(distiller_page_factory_),
         std::unique_ptr<DistilledPagePrefs>()));
-    fake_db->InitCallback(true);
+    fake_db->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
     fake_db->LoadCallback(true);
   }
 
diff --git a/components/dom_distiller/core/dom_distiller_store.cc b/components/dom_distiller/core/dom_distiller_store.cc
index 06cbad4..483b9c5 100644
--- a/components/dom_distiller/core/dom_distiller_store.cc
+++ b/components/dom_distiller/core/dom_distiller_store.cc
@@ -29,39 +29,25 @@
 using syncer::SyncError;
 using syncer::SyncMergeResult;
 
-namespace {
-// Statistics are logged to UMA with this string as part of histogram name. They
-// can all be found under LevelDB.*.DomDistillerStore. Changing this needs to
-// synchronize with histograms.xml, AND will also become incompatible with older
-// browsers still reporting the previous values.
-const char kDatabaseUMAClientName[] = "DomDistillerStore";
-}
-
 namespace dom_distiller {
 
 DomDistillerStore::DomDistillerStore(
-    std::unique_ptr<ProtoDatabase<ArticleEntry>> database,
-    const base::FilePath& database_dir)
+    std::unique_ptr<ProtoDatabase<ArticleEntry>> database)
     : database_(std::move(database)),
       database_loaded_(false),
       weak_ptr_factory_(this) {
-  database_->Init(kDatabaseUMAClientName, database_dir,
-                  leveldb_proto::CreateSimpleOptions(),
-                  base::BindOnce(&DomDistillerStore::OnDatabaseInit,
+  database_->Init(base::BindOnce(&DomDistillerStore::OnDatabaseInit,
                                  weak_ptr_factory_.GetWeakPtr()));
 }
 
 DomDistillerStore::DomDistillerStore(
     std::unique_ptr<ProtoDatabase<ArticleEntry>> database,
-    const std::vector<ArticleEntry>& initial_data,
-    const base::FilePath& database_dir)
+    const std::vector<ArticleEntry>& initial_data)
     : database_(std::move(database)),
       database_loaded_(false),
       model_(initial_data),
       weak_ptr_factory_(this) {
-  database_->Init(kDatabaseUMAClientName, database_dir,
-                  leveldb_proto::CreateSimpleOptions(),
-                  base::BindOnce(&DomDistillerStore::OnDatabaseInit,
+  database_->Init(base::BindOnce(&DomDistillerStore::OnDatabaseInit,
                                  weak_ptr_factory_.GetWeakPtr()));
 }
 
@@ -176,8 +162,9 @@
   NotifyObservers(*changes_applied);
 }
 
-void DomDistillerStore::OnDatabaseInit(bool success) {
-  if (!success) {
+void DomDistillerStore::OnDatabaseInit(
+    leveldb_proto::Enums::InitStatus status) {
+  if (status != leveldb_proto::Enums::InitStatus::kOK) {
     DVLOG(1) << "DOM Distiller database init failed.";
     database_.reset();
     return;
diff --git a/components/dom_distiller/core/dom_distiller_store.h b/components/dom_distiller/core/dom_distiller_store.h
index d98e538..1b04a16a 100644
--- a/components/dom_distiller/core/dom_distiller_store.h
+++ b/components/dom_distiller/core/dom_distiller_store.h
@@ -23,10 +23,6 @@
 #include "components/sync/model/syncable_service.h"
 #include "url/gurl.h"
 
-namespace base {
-class FilePath;
-}
-
 namespace dom_distiller {
 
 // Interface for accessing the stored/synced DomDistiller entries.
@@ -72,19 +68,15 @@
  public:
   typedef std::vector<ArticleEntry> EntryVector;
 
-  // Creates storage using the given database for local storage. Initializes the
-  // database with |database_dir|.
+  // Creates storage using the given database for local storage.
   DomDistillerStore(
-      std::unique_ptr<leveldb_proto::ProtoDatabase<ArticleEntry>> database,
-      const base::FilePath& database_dir);
+      std::unique_ptr<leveldb_proto::ProtoDatabase<ArticleEntry>> database);
 
   // Creates storage using the given database for local storage. Initializes the
-  // database with |database_dir|.  Also initializes the internal model to
-  // |initial_model|.
+  // internal model to |initial_model|.
   DomDistillerStore(
       std::unique_ptr<leveldb_proto::ProtoDatabase<ArticleEntry>> database,
-      const std::vector<ArticleEntry>& initial_data,
-      const base::FilePath& database_dir);
+      const std::vector<ArticleEntry>& initial_data);
 
   ~DomDistillerStore() override;
 
@@ -100,7 +92,7 @@
   void RemoveObserver(DomDistillerObserver* observer) override;
 
  private:
-  void OnDatabaseInit(bool success);
+  void OnDatabaseInit(leveldb_proto::Enums::InitStatus status);
   void OnDatabaseLoad(bool success, std::unique_ptr<EntryVector> entries);
   void OnDatabaseSave(bool success);
 
diff --git a/components/dom_distiller/core/dom_distiller_store_unittest.cc b/components/dom_distiller/core/dom_distiller_store_unittest.cc
index 92b35c70..4e4812f 100644
--- a/components/dom_distiller/core/dom_distiller_store_unittest.cc
+++ b/components/dom_distiller/core/dom_distiller_store_unittest.cc
@@ -209,9 +209,7 @@
 
   CreateStore();
 
-  fake_db_->InitCallback(true);
-  EXPECT_EQ(fake_db_->GetDirectory(),
-            FakeDB<ArticleEntry>::DirectoryForTestDB());
+  fake_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
 
   fake_db_->LoadCallback(true);
   EXPECT_TRUE(AreEntriesEqual(store_->GetEntries(), db_model_));
@@ -231,7 +229,7 @@
   AddEntry(GetSampleEntry(4), &expected_model);
 
   CreateStore();
-  fake_db_->InitCallback(true);
+  fake_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
   fake_db_->LoadCallback(true);
 
   EXPECT_TRUE(AreEntriesEqual(store_->GetEntries(), expected_model));
@@ -240,7 +238,7 @@
 
 TEST_F(DomDistillerStoreTest, TestAddAndRemoveEntry) {
   CreateStore();
-  fake_db_->InitCallback(true);
+  fake_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
   fake_db_->LoadCallback(true);
 
   EXPECT_TRUE(store_->GetEntries().empty());
@@ -263,7 +261,7 @@
 
 TEST_F(DomDistillerStoreTest, TestAddAndUpdateEntry) {
   CreateStore();
-  fake_db_->InitCallback(true);
+  fake_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
   fake_db_->LoadCallback(true);
 
   EXPECT_TRUE(store_->GetEntries().empty());
@@ -297,7 +295,7 @@
   CreateStore();
   MockDistillerObserver observer;
   store_->AddObserver(&observer);
-  fake_db_->InitCallback(true);
+  fake_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
   fake_db_->LoadCallback(true);
   std::vector<DomDistillerObserver::ArticleUpdate> expected_updates;
   DomDistillerObserver::ArticleUpdate update;
diff --git a/components/dom_distiller/core/dom_distiller_test_util.cc b/components/dom_distiller/core/dom_distiller_test_util.cc
index a69c7b7..52c77c34 100644
--- a/components/dom_distiller/core/dom_distiller_test_util.cc
+++ b/components/dom_distiller/core/dom_distiller_test_util.cc
@@ -92,7 +92,7 @@
     const FakeDB<ArticleEntry>::EntryMap& store_model) {
   return new DomDistillerStore(
       std::unique_ptr<leveldb_proto::ProtoDatabase<ArticleEntry>>(fake_db),
-      EntryMapToList(store_model), FakeDB<ArticleEntry>::DirectoryForTestDB());
+      EntryMapToList(store_model));
 }
 
 }  // namespace util
diff --git a/components/dom_distiller/standalone/content_extractor_browsertest.cc b/components/dom_distiller/standalone/content_extractor_browsertest.cc
index 2b235bb..6d7210f 100644
--- a/components/dom_distiller/standalone/content_extractor_browsertest.cc
+++ b/components/dom_distiller/standalone/content_extractor_browsertest.cc
@@ -30,6 +30,7 @@
 #include "components/dom_distiller/core/proto/distilled_article.pb.h"
 #include "components/dom_distiller/core/proto/distilled_page.pb.h"
 #include "components/dom_distiller/core/task_tracker.h"
+#include "components/leveldb_proto/content/proto_database_provider_factory.h"
 #include "components/leveldb_proto/public/proto_database.h"
 #include "components/leveldb_proto/public/proto_database_provider.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
@@ -130,12 +131,18 @@
   scoped_refptr<base::SequencedTaskRunner> background_task_runner =
       base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()});
 
+  auto* db_provider =
+      leveldb_proto::ProtoDatabaseProviderFactory::GetForBrowserContext(
+          context);
+
   // TODO(cjhopman): use an in-memory database instead of an on-disk one with
   // temporary directory.
-  auto db = leveldb_proto::ProtoDatabaseProvider::CreateUniqueDB<ArticleEntry>(
+  auto db = db_provider->GetDB<ArticleEntry>(
+      leveldb_proto::ProtoDbType::DOM_DISTILLER_STORE, db_path,
       background_task_runner);
+
   std::unique_ptr<DomDistillerStore> dom_distiller_store(
-      new DomDistillerStore(std::move(db), db_path));
+      new DomDistillerStore(std::move(db)));
 
   std::unique_ptr<DistillerPageFactory> distiller_page_factory(
       new DistillerPageWebContentsFactory(context));
diff --git a/components/gwp_asan/crash_handler/crash_handler.cc b/components/gwp_asan/crash_handler/crash_handler.cc
index 925ebde..ca6a75e9 100644
--- a/components/gwp_asan/crash_handler/crash_handler.cc
+++ b/components/gwp_asan/crash_handler/crash_handler.cc
@@ -80,8 +80,8 @@
 HandleException(const crashpad::ProcessSnapshot& snapshot) {
   gwp_asan::Crash proto;
   auto result = CrashAnalyzer::GetExceptionInfo(snapshot, &proto);
-  UMA_HISTOGRAM_ENUMERATION("GwpAsan.CrashAnalysisResult", result);
-
+  if (result != GwpAsanCrashAnalysisResult::kUnrelatedCrash)
+    UMA_HISTOGRAM_ENUMERATION("GwpAsan.CrashAnalysisResult", result);
   if (result != GwpAsanCrashAnalysisResult::kGwpAsanCrash)
     return nullptr;
 
diff --git a/components/leveldb_proto/internal/proto_database_impl.h b/components/leveldb_proto/internal/proto_database_impl.h
index 0b23b981..f6dc67d2 100644
--- a/components/leveldb_proto/internal/proto_database_impl.h
+++ b/components/leveldb_proto/internal/proto_database_impl.h
@@ -82,16 +82,14 @@
 
   virtual ~ProtoDatabaseImpl() = default;
 
-  // DEPRECATED. This is to be used in case of forced unique db behavior.
+  void Init(Callbacks::InitStatusCallback callback) override;
   void Init(const char* client_name,
             const base::FilePath& database_dir,
             const leveldb_env::Options& options,
             Callbacks::InitCallback callback) override;
-
-  // This can be used along with a database obtained from new api
-  // Provider::GetDB(). If using the old api to create unique db, then we do not
-  // know the database dir and init will fail.
-  void Init(const std::string& client_name,
+  void Init(const std::string& uma_name,
+            Callbacks::InitStatusCallback callback) override;
+  void Init(const leveldb_env::Options& unique_db_options,
             Callbacks::InitStatusCallback callback) override;
 
   // Internal only api.
@@ -161,9 +159,10 @@
   template <typename T_>
   friend class ProtoDatabaseImplTest;
 
-  void Init(const std::string& client_name,
-            bool use_shared_db,
-            Callbacks::InitStatusCallback callback);
+  void InitInternal(const std::string& client_name,
+                    const leveldb_env::Options& options,
+                    bool use_shared_db,
+                    Callbacks::InitStatusCallback callback);
 
   void PostTransaction(base::OnceClosure task);
 
@@ -391,23 +390,47 @@
   bool use_shared_db =
       !force_unique_db_ &&
       SharedProtoDatabaseClientList::ShouldUseSharedDB(db_type_);
-  Init(client_uma_name, use_shared_db, std::move(callback));
+  InitInternal(client_uma_name, CreateSimpleOptions(), use_shared_db,
+               std::move(callback));
 }
 
 template <typename P, typename T>
-void ProtoDatabaseImpl<P, T>::Init(const std::string& client_name,
-                                   bool use_shared_db,
-                                   Callbacks::InitStatusCallback callback) {
-  auto options = CreateSimpleOptions();
-  // If we're NOT using a shared DB, we want to force creation of the unique one
-  // because that's what we expect to be using moving forward. If we ARE using
-  // the shared DB, we only want to see if there's a unique DB that already
-  // exists and can be opened so that we can perform migration if necessary.
-  options.create_if_missing = !use_shared_db;
+void ProtoDatabaseImpl<P, T>::Init(
+    typename Callbacks::InitStatusCallback callback) {
+  bool use_shared_db =
+      !force_unique_db_ &&
+      SharedProtoDatabaseClientList::ShouldUseSharedDB(db_type_);
+  const std::string& client_uma_name =
+      SharedProtoDatabaseClientList::ProtoDbTypeToString(db_type_);
+
+  InitInternal(client_uma_name, CreateSimpleOptions(), use_shared_db,
+               std::move(callback));
+}
+
+template <typename P, typename T>
+void ProtoDatabaseImpl<P, T>::Init(
+    const leveldb_env::Options& unique_db_options,
+    typename Callbacks::InitStatusCallback callback) {
+  bool use_shared_db =
+      !force_unique_db_ &&
+      SharedProtoDatabaseClientList::ShouldUseSharedDB(db_type_);
+  const std::string& client_uma_name =
+      SharedProtoDatabaseClientList::ProtoDbTypeToString(db_type_);
+
+  InitInternal(client_uma_name, unique_db_options, use_shared_db,
+               std::move(callback));
+}
+
+template <typename P, typename T>
+void ProtoDatabaseImpl<P, T>::InitInternal(
+    const std::string& client_name,
+    const leveldb_env::Options& unique_db_options,
+    bool use_shared_db,
+    Callbacks::InitStatusCallback callback) {
   task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&ProtoDatabaseSelector::InitUniqueOrShared, db_wrapper_,
-                     client_name, db_dir_, options, use_shared_db,
+                     client_name, db_dir_, unique_db_options, use_shared_db,
                      base::SequencedTaskRunnerHandle::Get(),
                      std::move(callback)));
 }
diff --git a/components/leveldb_proto/internal/proto_database_impl_unittest.cc b/components/leveldb_proto/internal/proto_database_impl_unittest.cc
index 2d5a0b8..43571a3 100644
--- a/components/leveldb_proto/internal/proto_database_impl_unittest.cc
+++ b/components/leveldb_proto/internal/proto_database_impl_unittest.cc
@@ -188,14 +188,12 @@
     base::RunLoop run_init;
 
     // Initialize a database, it should succeed.
-    db->Init(kDefaultClientName,
-             base::BindOnce(
-                 [](base::OnceClosure closure,
-                    leveldb_proto::Enums::InitStatus status) {
-                   std::move(closure).Run();
-                   EXPECT_TRUE(status == leveldb_proto::Enums::InitStatus::kOK);
-                 },
-                 run_init.QuitClosure()));
+    db->Init(base::BindOnce(
+        [](base::OnceClosure closure, leveldb_proto::Enums::InitStatus status) {
+          std::move(closure).Run();
+          EXPECT_TRUE(status == leveldb_proto::Enums::InitStatus::kOK);
+        },
+        run_init.QuitClosure()));
 
     run_init.Run();
   }
@@ -234,7 +232,8 @@
                   const std::string& client_name,
                   bool use_shared_db,
                   Callbacks::InitStatusCallback callback) {
-    db_impl->Init(client_name, use_shared_db, std::move(callback));
+    db_impl->InitInternal(client_name, leveldb_proto::CreateSimpleOptions(),
+                          use_shared_db, std::move(callback));
   }
 
   void InitDBImplAndWait(ProtoDatabaseImpl<TestProto, T>* db_impl,
@@ -937,13 +936,43 @@
   EXPECT_FALSE(base::PathExists(temp_dir.GetPath()));
 }
 
+TYPED_TEST(ProtoDatabaseImplTest, InitWithOptions) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  EXPECT_TRUE(base::IsDirectoryEmpty(temp_dir.GetPath()));
+
+  auto db_provider = this->CreateProviderNoSharedDB();
+  auto db_impl =
+      this->CreateDBImpl(ProtoDbType::TEST_DATABASE1, temp_dir.GetPath(),
+                         this->GetTestThreadTaskRunner(),
+                         this->CreateSharedProvider(db_provider.get()));
+
+  base::RunLoop run_init;
+  auto options = leveldb_proto::CreateSimpleOptions();
+  options.create_if_missing = false;
+
+  // Initialize database with unique DB arguments, it should fail because we
+  // specified create_if_missing = false and there's no shared DB.
+  db_impl->Init(
+      options,
+      base::BindOnce(
+          [](base::OnceClosure closure, Enums::InitStatus expect_status,
+             Enums::InitStatus status) {
+            ASSERT_EQ(status, expect_status);
+            std::move(closure).Run();
+          },
+          run_init.QuitClosure(), Enums::InitStatus::kError));
+
+  run_init.Run();
+}
+
 TYPED_TEST(ProtoDatabaseImplTest, InitUniqueTwiceShouldSucceed) {
   base::ScopedTempDir temp_dir_profile;
   ASSERT_TRUE(temp_dir_profile.CreateUniqueTempDir());
 
   // Both databases will be opened as unique.
   auto experiment_params = std::map<std::string, std::string>{
-      {"migrate_TEST_DATABASE1", "false"}, {"migrate_TEST_DATABASE2", "false"}};
+      {"migrate_TestDatabase1", "false"}, {"migrate_TestDatabase2", "false"}};
   this->SetUpExperimentParams(experiment_params);
 
   leveldb_proto::ProtoDatabaseProvider* db_provider =
@@ -961,7 +990,7 @@
 
   // First database will open as unique, second DB will open as shared.
   auto experiment_params = std::map<std::string, std::string>{
-      {"migrate_TEST_DATABASE1", "false"}, {"migrate_TEST_DATABASE2", "true"}};
+      {"migrate_TestDatabase1", "false"}, {"migrate_TestDatabase2", "true"}};
   this->SetUpExperimentParams(experiment_params);
 
   leveldb_proto::ProtoDatabaseProvider* db_provider =
@@ -979,7 +1008,7 @@
 
   // First database will open as shared, second DB will open as unique.
   auto experiment_params = std::map<std::string, std::string>{
-      {"migrate_TEST_DATABASE1", "true"}, {"migrate_TEST_DATABASE2", "false"}};
+      {"migrate_TestDatabase1", "true"}, {"migrate_TestDatabase2", "false"}};
   this->SetUpExperimentParams(experiment_params);
 
   leveldb_proto::ProtoDatabaseProvider* db_provider =
@@ -997,7 +1026,7 @@
 
   // Both databases will open as shared.
   auto experiment_params = std::map<std::string, std::string>{
-      {"migrate_TEST_DATABASE1", "true"}, {"migrate_TEST_DATABASE2", "true"}};
+      {"migrate_TestDatabase1", "true"}, {"migrate_TestDatabase2", "true"}};
   this->SetUpExperimentParams(experiment_params);
 
   leveldb_proto::ProtoDatabaseProvider* db_provider =
diff --git a/components/leveldb_proto/internal/proto_database_selector.cc b/components/leveldb_proto/internal/proto_database_selector.cc
index 5edef99..695b42d 100644
--- a/components/leveldb_proto/internal/proto_database_selector.cc
+++ b/components/leveldb_proto/internal/proto_database_selector.cc
@@ -63,7 +63,7 @@
 void ProtoDatabaseSelector::InitUniqueOrShared(
     const std::string& client_name,
     base::FilePath db_dir,
-    const leveldb_env::Options& options,
+    const leveldb_env::Options& unique_db_options,
     bool use_shared_db,
     scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
     Callbacks::InitStatusCallback callback) {
@@ -71,8 +71,19 @@
   init_status_ = InitStatus::IN_PROGRESS;
   unique_database_dir_ = db_dir;
   client_name_ = client_name;
-  auto unique_db =
-      std::make_unique<UniqueProtoDatabase>(db_dir, options, task_runner_);
+
+  auto unique_options = unique_db_options;
+  // There are two Init methods, one that receives Options for its unique DB and
+  // another that uses CreateSimpleOptions() to open the unique DB. In case a
+  // shared DB needs to be used then we don't need to create a new unique DB if
+  // it doesn't exist. In case a unique DB needs to be used then we don't change
+  // the create_if_missing parameter, because it may have been set by a client.
+  if (use_shared_db) {
+    unique_options.create_if_missing = false;
+  }
+
+  auto unique_db = std::make_unique<UniqueProtoDatabase>(db_dir, unique_options,
+                                                         task_runner_);
   auto* unique_db_ptr = unique_db.get();
   unique_db_ptr->Init(
       client_name, base::BindOnce(&ProtoDatabaseSelector::OnInitUniqueDB, this,
diff --git a/components/leveldb_proto/internal/proto_database_selector.h b/components/leveldb_proto/internal/proto_database_selector.h
index afc80f2..48cab0c4 100644
--- a/components/leveldb_proto/internal/proto_database_selector.h
+++ b/components/leveldb_proto/internal/proto_database_selector.h
@@ -43,7 +43,7 @@
   void InitUniqueOrShared(
       const std::string& client_name,
       base::FilePath db_dir,
-      const leveldb_env::Options& options,
+      const leveldb_env::Options& unique_db_options,
       bool use_shared_db,
       scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
       Callbacks::InitStatusCallback callback);
diff --git a/components/leveldb_proto/internal/shared_proto_database_client_list_unittest.cc b/components/leveldb_proto/internal/shared_proto_database_client_list_unittest.cc
index 86e5662c0..35113c73 100644
--- a/components/leveldb_proto/internal/shared_proto_database_client_list_unittest.cc
+++ b/components/leveldb_proto/internal/shared_proto_database_client_list_unittest.cc
@@ -13,16 +13,16 @@
 namespace leveldb_proto {
 
 namespace {
-const char kTestClientName[] = "TEST_DATABASE1";
+const char kTestClientName[] = "TestDatabase1";
 }
 
 class SharedProtoDatabaseClientListTest : public testing::Test {
  public:
   void SetUpExperimentParam(std::string key, std::string value) {
     std::map<std::string, std::string> params = {
-        {"migrate_TEST_DATABASE0", "true"},
+        {"migrate_TestDatabase0", "true"},
         {"migrate_" + key, value},
-        {"migrate_TEST_DATABASE2", "false"},
+        {"migrate_TestDatabase2", "false"},
     };
 
     scoped_feature_list_.InitAndEnableFeatureWithParameters(
@@ -45,7 +45,7 @@
 
 TEST_F(SharedProtoDatabaseClientListTest,
        ShouldUseSharedDBTest_OnlyWhenParamMatchesName) {
-  SetUpExperimentParam("TEST_DATABASE10", "true");
+  SetUpExperimentParam("TestDatabase10", "true");
 
   bool use_shared = SharedProtoDatabaseClientList::ShouldUseSharedDB(
       ProtoDbType::TEST_DATABASE1);
diff --git a/components/leveldb_proto/public/proto_database.h b/components/leveldb_proto/public/proto_database.h
index a8369ef..f752e7fb 100644
--- a/components/leveldb_proto/public/proto_database.h
+++ b/components/leveldb_proto/public/proto_database.h
@@ -96,12 +96,25 @@
 
   virtual ~ProtoDatabase() = default;
 
-  // Asynchronously initializes the object with the specified |options|.
-  // |callback| will be invoked on the calling thread when complete.
-  virtual void Init(const std::string& client_name,
+  // Asynchronously initializes the object, which must have been created by the
+  // ProtoDatabaseProvider::GetDB<T> function. |callback| will be invoked on the
+  // calling thread when complete.
+  //
+  // DEPRECATED: |unique_db_options| is used only when a unique DB is loaded,
+  // once migration to shared DB is done, this parameter will be ignored.
+  //
+  // DEPRECATED: |client_uma_name| was used to record UMA metrics, new clients
+  // should instead add their name to
+  // SharedProtoDatabaseClientList::ProtoDbTypeToString.
+  virtual void Init(Callbacks::InitStatusCallback callback) = 0;
+  virtual void Init(const std::string& client_uma_name,
                     Callbacks::InitStatusCallback callback) = 0;
-  // This version of Init is for compatibility, since many of the current
-  // proto database clients still use this.
+  virtual void Init(const leveldb_env::Options& unique_db_options,
+                    Callbacks::InitStatusCallback callback) = 0;
+
+  // DEPRECATED. This version of Init is for compatibility, must be called only
+  // when the object is created by the ProtoDatabaseProvider::CreateUniqueDB<T>
+  // function.
   virtual void Init(const char* client_name,
                     const base::FilePath& database_dir,
                     const leveldb_env::Options& options,
diff --git a/components/leveldb_proto/public/shared_proto_database_client_list.cc b/components/leveldb_proto/public/shared_proto_database_client_list.cc
index 64d46e1..d3ecd28 100644
--- a/components/leveldb_proto/public/shared_proto_database_client_list.cc
+++ b/components/leveldb_proto/public/shared_proto_database_client_list.cc
@@ -17,31 +17,6 @@
 
 namespace {
 
-std::string PtotoDbTypeToString(ProtoDbType db_type) {
-  switch (db_type) {
-    case ProtoDbType::FEATURE_ENGAGEMENT_EVENT:
-      return "FEATURE_ENGAGEMENT_EVENT";
-    case ProtoDbType::FEATURE_ENGAGEMENT_AVAILABILITY:
-      return "FEATURE_ENGAGEMENT_AVAILABILITY";
-    case ProtoDbType::USAGE_STATS_WEBSITE_EVENT:
-      return "USAGE_STATS_WEBSITE_EVENT";
-    case ProtoDbType::USAGE_STATS_SUSPENSION:
-      return "USAGE_STATS_SUSPENSION";
-    case ProtoDbType::USAGE_STATS_TOKEN_MAPPING:
-      return "USAGE_STATS_TOKEN_MAPPING";
-    case ProtoDbType::LAST:
-      NOTREACHED();
-      break;
-    case ProtoDbType::TEST_DATABASE0:
-      return "TEST_DATABASE0";
-    case ProtoDbType::TEST_DATABASE1:
-      return "TEST_DATABASE1";
-    case ProtoDbType::TEST_DATABASE2:
-      return "TEST_DATABASE2";
-  }
-  return std::string();
-}
-
 constexpr ProtoDbType kWhitelistedListForSharedImpl[]{
     ProtoDbType::LAST,  // Marks the end of list.
 };
@@ -51,6 +26,35 @@
 }  // namespace
 
 // static
+std::string SharedProtoDatabaseClientList::ProtoDbTypeToString(
+    ProtoDbType db_type) {
+  switch (db_type) {
+    case ProtoDbType::FEATURE_ENGAGEMENT_EVENT:
+      return "FeatureEngagementTrackerEventStore";
+    case ProtoDbType::FEATURE_ENGAGEMENT_AVAILABILITY:
+      return "FeatureEngagementTrackerAvailabilityStore";
+    case ProtoDbType::USAGE_STATS_WEBSITE_EVENT:
+      return "UsageStatsWebsiteEvent";
+    case ProtoDbType::USAGE_STATS_SUSPENSION:
+      return "UsageStatsSuspension";
+    case ProtoDbType::USAGE_STATS_TOKEN_MAPPING:
+      return "UsageStatsTokenMapping";
+    case ProtoDbType::DOM_DISTILLER_STORE:
+      return "DomDistillerStore";
+    case ProtoDbType::LAST:
+      NOTREACHED();
+      break;
+    case ProtoDbType::TEST_DATABASE0:
+      return "TestDatabase0";
+    case ProtoDbType::TEST_DATABASE1:
+      return "TestDatabase1";
+    case ProtoDbType::TEST_DATABASE2:
+      return "TestDatabase2";
+  }
+  return std::string();
+}
+
+// static
 bool SharedProtoDatabaseClientList::ShouldUseSharedDB(ProtoDbType db_type) {
   for (size_t i = 0; kWhitelistedListForSharedImpl[i] != ProtoDbType::LAST;
        ++i) {
@@ -61,11 +65,8 @@
   if (!base::FeatureList::IsEnabled(kProtoDBSharedMigration))
     return false;
 
-  std::map<std::string, std::string> params;
-  if (!base::GetFieldTrialParamsByFeature(kProtoDBSharedMigration, &params))
-    return false;
-
-  std::string name = PtotoDbTypeToString(db_type);
+  std::string name =
+      SharedProtoDatabaseClientList::ProtoDbTypeToString(db_type);
   return base::GetFieldTrialParamByFeatureAsBool(
       kProtoDBSharedMigration, kDBNameParamPrefix + name, false);
 }
diff --git a/components/leveldb_proto/public/shared_proto_database_client_list.h b/components/leveldb_proto/public/shared_proto_database_client_list.h
index 211a24ab..332f079 100644
--- a/components/leveldb_proto/public/shared_proto_database_client_list.h
+++ b/components/leveldb_proto/public/shared_proto_database_client_list.h
@@ -25,6 +25,7 @@
   USAGE_STATS_WEBSITE_EVENT = 5,
   USAGE_STATS_SUSPENSION = 6,
   USAGE_STATS_TOKEN_MAPPING = 7,
+  DOM_DISTILLER_STORE = 8,
 
   LAST,
 };
@@ -43,7 +44,12 @@
 
 class SharedProtoDatabaseClientList {
  public:
+  // Determines if the given |db_type| should use a unique or shared DB.
   static bool ShouldUseSharedDB(ProtoDbType db_type);
+
+  // Converts a ProtoDbType to a string, which is used for UMA metrics and field
+  // trials. The strings returned should match the strings on histograms.xml
+  static std::string ProtoDbTypeToString(ProtoDbType db_type);
 };
 
 }  // namespace leveldb_proto
diff --git a/components/leveldb_proto/testing/fake_db.h b/components/leveldb_proto/testing/fake_db.h
index 3d947a3..8d7cba1f 100644
--- a/components/leveldb_proto/testing/fake_db.h
+++ b/components/leveldb_proto/testing/fake_db.h
@@ -34,6 +34,9 @@
   // ProtoDatabase implementation.
   void Init(const std::string& client_name,
             Callbacks::InitStatusCallback callback) override;
+  void Init(Callbacks::InitStatusCallback callback) override;
+  void Init(const leveldb_env::Options& unique_db_options,
+            Callbacks::InitStatusCallback callback) override;
   void Init(const char* client_name,
             const base::FilePath& database_dir,
             const leveldb_env::Options& options,
@@ -145,6 +148,17 @@
 }
 
 template <typename P, typename T>
+void FakeDB<P, T>::Init(const leveldb_env::Options& unique_db_options,
+                        Callbacks::InitStatusCallback callback) {
+  Init("fake_db", std::move(callback));
+}
+
+template <typename P, typename T>
+void FakeDB<P, T>::Init(Callbacks::InitStatusCallback callback) {
+  Init("fake_db", std::move(callback));
+}
+
+template <typename P, typename T>
 void FakeDB<P, T>::Init(const char* client_name,
                         const base::FilePath& database_dir,
                         const leveldb_env::Options& options,
diff --git a/components/omnibox/browser/autocomplete_input.cc b/components/omnibox/browser/autocomplete_input.cc
index 3c6f0572..ec510fd 100644
--- a/components/omnibox/browser/autocomplete_input.cc
+++ b/components/omnibox/browser/autocomplete_input.cc
@@ -18,6 +18,7 @@
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/base/url_util.h"
 #include "third_party/metrics_proto/omnibox_event.pb.h"
+#include "third_party/re2/src/re2/re2.h"
 #include "url/url_canon_ip.h"
 #include "url/url_util.h"
 
@@ -204,6 +205,12 @@
     return metrics::OmniboxInputType::URL;
   }
 
+  // Treat javascript: scheme queries followed by things that are unlikely to
+  // be code as QUERY, rather than script to execute (URL).
+  if (RE2::FullMatch(base::UTF16ToUTF8(text), "(?i)javascript:([^;=().]*)")) {
+    return metrics::OmniboxInputType::QUERY;
+  }
+
   // If the user typed a scheme, and it's HTTP or HTTPS, we know how to parse it
   // well enough that we can fall through to the heuristics below.  If it's
   // something else, we can just determine our action based on what we do with
diff --git a/components/omnibox/browser/autocomplete_input_unittest.cc b/components/omnibox/browser/autocomplete_input_unittest.cc
index 00bbc9a..5315f56 100644
--- a/components/omnibox/browser/autocomplete_input_unittest.cc
+++ b/components/omnibox/browser/autocomplete_input_unittest.cc
@@ -109,8 +109,17 @@
     // { ASCIIToUTF16("mailto:abuse@foo.com"), metrics::OmniboxInputType::URL },
     {ASCIIToUTF16("view-source:http://www.foo.com/"),
      metrics::OmniboxInputType::URL},
+    {ASCIIToUTF16("javascript"), metrics::OmniboxInputType::UNKNOWN},
     {ASCIIToUTF16("javascript:alert(\"Hi there\");"),
      metrics::OmniboxInputType::URL},
+    {ASCIIToUTF16("javascript:alert%28\"Hi there\"%29;"),
+     metrics::OmniboxInputType::URL},
+    {ASCIIToUTF16("javascript:foo;"), metrics::OmniboxInputType::URL},
+    {ASCIIToUTF16("javascript:"), metrics::OmniboxInputType::QUERY},
+    {ASCIIToUTF16("javascript:the cromulent parts"),
+     metrics::OmniboxInputType::QUERY},
+    {ASCIIToUTF16("javascript:foo.getter"), metrics::OmniboxInputType::URL},
+    {ASCIIToUTF16("JavaScript:Tutorials"), metrics::OmniboxInputType::QUERY},
 #if defined(OS_WIN)
     {ASCIIToUTF16("C:\\Program Files"), metrics::OmniboxInputType::URL},
     {ASCIIToUTF16("\\\\Server\\Folder\\File"), metrics::OmniboxInputType::URL},
diff --git a/components/omnibox/browser/location_bar_model_delegate.cc b/components/omnibox/browser/location_bar_model_delegate.cc
index 4f01f6c1..1ed20e6 100644
--- a/components/omnibox/browser/location_bar_model_delegate.cc
+++ b/components/omnibox/browser/location_bar_model_delegate.cc
@@ -12,9 +12,14 @@
   return true;
 }
 
-void LocationBarModelDelegate::GetSecurityInfo(
-    security_state::SecurityInfo* result) const {
-  return;
+security_state::SecurityLevel LocationBarModelDelegate::GetSecurityLevel()
+    const {
+  return security_state::NONE;
+}
+
+std::unique_ptr<security_state::VisibleSecurityState>
+LocationBarModelDelegate::GetVisibleSecurityState() const {
+  return std::make_unique<security_state::VisibleSecurityState>();
 }
 
 scoped_refptr<net::X509Certificate> LocationBarModelDelegate::GetCertificate()
diff --git a/components/omnibox/browser/location_bar_model_delegate.h b/components/omnibox/browser/location_bar_model_delegate.h
index 7de779b..fc5f6085 100644
--- a/components/omnibox/browser/location_bar_model_delegate.h
+++ b/components/omnibox/browser/location_bar_model_delegate.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_OMNIBOX_BROWSER_LOCATION_BAR_MODEL_DELEGATE_H_
 #define COMPONENTS_OMNIBOX_BROWSER_LOCATION_BAR_MODEL_DELEGATE_H_
 
+#include <memory>
 #include <string>
 
 #include "base/memory/ref_counted.h"
@@ -44,9 +45,14 @@
   // in the location bar.
   virtual bool ShouldDisplayURL() const;
 
-  // Returns the underlying security info of the page without regard to any
+  // Returns the underlying security level of the page without regard to any
   // user edits that may be in progress.
-  virtual void GetSecurityInfo(security_state::SecurityInfo* result) const;
+  virtual security_state::SecurityLevel GetSecurityLevel() const;
+
+  // Returns the underlying security state of the page without regard to any
+  // user edits that may be in progress. Should never return nullptr.
+  virtual std::unique_ptr<security_state::VisibleSecurityState>
+  GetVisibleSecurityState() const;
 
   // Returns the certificate for the current navigation entry.
   virtual scoped_refptr<net::X509Certificate> GetCertificate() const;
diff --git a/components/omnibox/browser/location_bar_model_impl.cc b/components/omnibox/browser/location_bar_model_impl.cc
index 232032f4..0e359fd1 100644
--- a/components/omnibox/browser/location_bar_model_impl.cc
+++ b/components/omnibox/browser/location_bar_model_impl.cc
@@ -102,9 +102,7 @@
   if ((input_in_progress() && !ignore_editing) || !ShouldDisplayURL())
     return security_state::NONE;
 
-  security_state::SecurityInfo info;
-  delegate_->GetSecurityInfo(&info);
-  return info.security_level;
+  return delegate_->GetSecurityLevel();
 }
 
 bool LocationBarModelImpl::GetDisplaySearchTerms(base::string16* search_terms) {
@@ -114,11 +112,12 @@
 
   // Only show the search terms if the site is secure. However, make an
   // exception before the security state is initialized to prevent a UI flicker.
-  security_state::SecurityInfo info;
-  delegate_->GetSecurityInfo(&info);
-  if (info.connection_info_initialized &&
-      info.security_level != security_state::SecurityLevel::SECURE &&
-      info.security_level != security_state::SecurityLevel::EV_SECURE) {
+  std::unique_ptr<security_state::VisibleSecurityState> visible_security_state =
+      delegate_->GetVisibleSecurityState();
+  security_state::SecurityLevel security_level = delegate_->GetSecurityLevel();
+  if (visible_security_state->connection_info_initialized &&
+      security_level != security_state::SecurityLevel::SECURE &&
+      security_level != security_state::SecurityLevel::EV_SECURE) {
     return false;
   }
 
@@ -220,12 +219,12 @@
       return SecureChipText(
           l10n_util::GetStringUTF16(IDS_SECURE_VERBOSE_STATE));
     case security_state::DANGEROUS: {
-      security_state::SecurityInfo security_info;
-      delegate_->GetSecurityInfo(&security_info);
+      std::unique_ptr<security_state::VisibleSecurityState>
+          visible_security_state = delegate_->GetVisibleSecurityState();
 
       // Don't show any text in the security indicator for sites on the billing
       // interstitial list.
-      if (security_info.malicious_content_status ==
+      if (visible_security_state->malicious_content_status ==
           security_state::MALICIOUS_CONTENT_STATUS_BILLING) {
 #if defined(OS_IOS)
         // On iOS, we never expect this status, because there are no billing
@@ -235,8 +234,9 @@
         return SecureChipText(base::string16());
       }
 
-      bool fails_malware_check = security_info.malicious_content_status !=
-                                 security_state::MALICIOUS_CONTENT_STATUS_NONE;
+      bool fails_malware_check =
+          visible_security_state->malicious_content_status !=
+          security_state::MALICIOUS_CONTENT_STATUS_NONE;
       return SecureChipText(l10n_util::GetStringUTF16(
           fails_malware_check ? IDS_DANGEROUS_VERBOSE_STATE
                               : IDS_NOT_SECURE_VERBOSE_STATE));
diff --git a/components/omnibox/browser/location_bar_model_impl_unittest.cc b/components/omnibox/browser/location_bar_model_impl_unittest.cc
index 2f987f4..3c0ab686 100644
--- a/components/omnibox/browser/location_bar_model_impl_unittest.cc
+++ b/components/omnibox/browser/location_bar_model_impl_unittest.cc
@@ -21,8 +21,11 @@
   void SetShouldPreventElision(bool should_prevent_elision) {
     should_prevent_elision_ = should_prevent_elision;
   }
-  void SetSecurityInfo(const security_state::SecurityInfo& info) {
-    security_info_ = info;
+  void SetSecurityLevel(security_state::SecurityLevel level) {
+    security_level_ = level;
+  }
+  void SetVisibleSecurityStateConnectionInfoUninitialized() {
+    connection_info_initialized_ = false;
   }
 
   // LocationBarModelDelegate:
@@ -39,8 +42,16 @@
 
   bool ShouldPreventElision() const override { return should_prevent_elision_; }
 
-  void GetSecurityInfo(security_state::SecurityInfo* result) const override {
-    *result = security_info_;
+  security_state::SecurityLevel GetSecurityLevel() const override {
+    return security_level_;
+  }
+
+  std::unique_ptr<security_state::VisibleSecurityState>
+  GetVisibleSecurityState() const override {
+    std::unique_ptr<security_state::VisibleSecurityState> state =
+        std::make_unique<security_state::VisibleSecurityState>();
+    state->connection_info_initialized = connection_info_initialized_;
+    return state;
   }
 
   AutocompleteClassifier* GetAutocompleteClassifier() override {
@@ -53,9 +64,10 @@
 
  private:
   GURL url_;
-  security_state::SecurityInfo security_info_;
+  security_state::SecurityLevel security_level_;
   TestOmniboxClient omnibox_client_;
   bool should_prevent_elision_ = false;
+  bool connection_info_initialized_ = true;
 };
 
 class LocationBarModelImplTest : public testing::Test {
@@ -107,19 +119,13 @@
             model()->GetURLForDisplay());
 
   // Verify that query in omnibox is turned off.
-  security_state::SecurityInfo info;
-  info.connection_info_initialized = true;
-  info.security_level = security_state::SecurityLevel::SECURE;
-  delegate()->SetSecurityInfo(info);
+  delegate()->SetSecurityLevel(security_state::SecurityLevel::SECURE);
   EXPECT_FALSE(model()->GetDisplaySearchTerms(nullptr));
 }
 
 TEST_F(LocationBarModelImplTest, QueryInOmniboxFeatureFlagWorks) {
   delegate()->SetURL(kValidSearchResultsPage);
-  security_state::SecurityInfo info;
-  info.connection_info_initialized = true;
-  info.security_level = security_state::SecurityLevel::SECURE;
-  delegate()->SetSecurityInfo(info);
+  delegate()->SetSecurityLevel(security_state::SecurityLevel::SECURE);
 
   EXPECT_FALSE(model()->GetDisplaySearchTerms(nullptr));
 
@@ -135,30 +141,22 @@
 
   delegate()->SetURL(kValidSearchResultsPage);
 
-  security_state::SecurityInfo info;
-  info.connection_info_initialized = true;
-
-  info.security_level = security_state::SecurityLevel::SECURE;
-  delegate()->SetSecurityInfo(info);
+  delegate()->SetSecurityLevel(security_state::SecurityLevel::SECURE);
   EXPECT_TRUE(model()->GetDisplaySearchTerms(nullptr));
 
-  info.security_level = security_state::SecurityLevel::EV_SECURE;
-  delegate()->SetSecurityInfo(info);
+  delegate()->SetSecurityLevel(security_state::SecurityLevel::EV_SECURE);
   EXPECT_TRUE(model()->GetDisplaySearchTerms(nullptr));
 
   // Insecure levels should not be allowed to display search terms.
-  info.security_level = security_state::SecurityLevel::NONE;
-  delegate()->SetSecurityInfo(info);
+  delegate()->SetSecurityLevel(security_state::SecurityLevel::NONE);
   EXPECT_FALSE(model()->GetDisplaySearchTerms(nullptr));
 
-  info.security_level = security_state::SecurityLevel::DANGEROUS;
-  delegate()->SetSecurityInfo(info);
+  delegate()->SetSecurityLevel(security_state::SecurityLevel::DANGEROUS);
   EXPECT_FALSE(model()->GetDisplaySearchTerms(nullptr));
 
   // But ignore the level if the connection info has not been initialized.
-  info.connection_info_initialized = false;
-  info.security_level = security_state::SecurityLevel::NONE;
-  delegate()->SetSecurityInfo(info);
+  delegate()->SetVisibleSecurityStateConnectionInfoUninitialized();
+  delegate()->SetSecurityLevel(security_state::SecurityLevel::NONE);
   EXPECT_TRUE(model()->GetDisplaySearchTerms(nullptr));
 }
 
@@ -166,11 +164,7 @@
        QueryInOmniboxDefaultSearchProviderWithAndWithoutQuery) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox);
-
-  security_state::SecurityInfo info;
-  info.connection_info_initialized = true;
-  info.security_level = security_state::SecurityLevel::SECURE;
-  delegate()->SetSecurityInfo(info);
+  delegate()->SetSecurityLevel(security_state::SecurityLevel::SECURE);
 
   delegate()->SetURL(kValidSearchResultsPage);
   base::string16 result;
@@ -192,10 +186,7 @@
   const GURL kNonDefaultSearchProvider(
       "https://search.yahoo.com/search?ei=UTF-8&fr=crmas&p=foo+query");
   delegate()->SetURL(kNonDefaultSearchProvider);
-  security_state::SecurityInfo info;
-  info.connection_info_initialized = true;
-  info.security_level = security_state::SecurityLevel::SECURE;
-  delegate()->SetSecurityInfo(info);
+  delegate()->SetSecurityLevel(security_state::SecurityLevel::SECURE);
 
   base::string16 result;
   EXPECT_FALSE(model()->GetDisplaySearchTerms(&result));
@@ -206,10 +197,7 @@
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox);
 
-  security_state::SecurityInfo info;
-  info.connection_info_initialized = true;
-  info.security_level = security_state::SecurityLevel::SECURE;
-  delegate()->SetSecurityInfo(info);
+  delegate()->SetSecurityLevel(security_state::SecurityLevel::SECURE);
 
   const GURL kLookalikeURLQuery(
       "https://www.google.com/search?q=lookalike.com");
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index e983645..b6852b7 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -186,6 +186,7 @@
     "//third_party/boringssl",
     "//third_party/brotli:dec",
     "//third_party/icu",
+    "//third_party/inspector_protocol:encoding",
     "//third_party/libyuv",
     "//third_party/re2",
     "//third_party/sqlite",
@@ -660,6 +661,8 @@
     "devtools/devtools_renderer_channel.h",
     "devtools/devtools_session.cc",
     "devtools/devtools_session.h",
+    "devtools/devtools_session_encoding.cc",
+    "devtools/devtools_session_encoding.h",
     "devtools/devtools_stream_blob.cc",
     "devtools/devtools_stream_blob.h",
     "devtools/devtools_stream_file.cc",
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 1ac6a2d..c964fa6 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -962,8 +962,11 @@
 
 int BrowserMainLoop::PreMainMessageLoopRun() {
 #if defined(OS_ANDROID)
+  bool use_display_wide_color_gamut =
+      GetContentClient()->browser()->GetWideColorGamutHeuristic() ==
+      ContentBrowserClient::WideColorGamutHeuristic::kUseDisplay;
   // Let screen instance be overridable by parts.
-  ui::SetScreenAndroid();
+  ui::SetScreenAndroid(use_display_wide_color_gamut);
 #endif
 
   if (parts_) {
diff --git a/content/browser/devtools/BUILD.gn b/content/browser/devtools/BUILD.gn
index f14e719..2250166 100644
--- a/content/browser/devtools/BUILD.gn
+++ b/content/browser/devtools/BUILD.gn
@@ -129,3 +129,16 @@
     "devtools_background_services.proto",
   ]
 }
+
+source_set("inspector_protocol_encoding_test") {
+  testonly = true
+  sources = [
+    "../../../third_party/inspector_protocol/encoding/encoding_test.cc",
+  ]
+  deps = [
+    "//base",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//third_party/inspector_protocol:encoding",
+  ]
+}
diff --git a/content/browser/devtools/DEPS b/content/browser/devtools/DEPS
index 93bf7150..962e548 100644
--- a/content/browser/devtools/DEPS
+++ b/content/browser/devtools/DEPS
@@ -3,4 +3,7 @@
   "+content/shell/browser/shell.h", # for access to web contents from devtools_protocol_test_support.cc
   # V8 version info
   "+v8/include/v8-version-string.h",
+
+  # For converting between JSON and CBOR in devtools_session_encoding.cc.
+  "+third_party/inspector_protocol/encoding",
 ]
diff --git a/content/browser/devtools/browser_devtools_agent_host.cc b/content/browser/devtools/browser_devtools_agent_host.cc
index 2862801..e491560 100644
--- a/content/browser/devtools/browser_devtools_agent_host.cc
+++ b/content/browser/devtools/browser_devtools_agent_host.cc
@@ -88,7 +88,7 @@
         socket_callback_, tethering_task_runner_));
   }
   session->AddHandler(std::make_unique<protocol::TracingHandler>(
-      nullptr, GetIOContext(), session->client()->UsesBinaryProtocol()));
+      nullptr, GetIOContext(), session->UsesBinaryProtocol()));
   return true;
 }
 
diff --git a/content/browser/devtools/devtools_session.cc b/content/browser/devtools/devtools_session.cc
index 75d2d42..c88086c 100644
--- a/content/browser/devtools/devtools_session.cc
+++ b/content/browser/devtools/devtools_session.cc
@@ -4,10 +4,11 @@
 
 #include "content/browser/devtools/devtools_session.h"
 
+#include <vector>
+
 #include "base/bind.h"
-#include "base/json/json_reader.h"
-#include "base/strings/stringprintf.h"
 #include "content/browser/devtools/devtools_manager.h"
+#include "content/browser/devtools/devtools_session_encoding.h"
 #include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/protocol.h"
 #include "content/browser/devtools/render_frame_devtools_agent_host.h"
@@ -34,7 +35,6 @@
 static const char kMethod[] = "method";
 static const char kResumeMethod[] = "Runtime.runIfWaitingForDebugger";
 static const char kSessionId[] = "sessionId";
-
 }  // namespace
 
 DevToolsSession::DevToolsSession(DevToolsAgentHostClient* client)
@@ -73,6 +73,11 @@
   return root_session_ ? root_session_ : this;
 }
 
+bool DevToolsSession::UsesBinaryProtocol() const {
+  return client_->UsesBinaryProtocol() ||
+         EnableInternalDevToolsBinaryProtocol();
+}
+
 void DevToolsSession::AddHandler(
     std::unique_ptr<protocol::DevToolsDomainHandler> handler) {
   DCHECK(agent_host_);
@@ -133,10 +138,27 @@
   io_session_ptr_.reset();
 }
 
+// The client of the devtools session will call this method to send a message
+// to handlers / agents that the session is connected with.
 bool DevToolsSession::DispatchProtocolMessage(const std::string& message) {
+  std::string converted_cbor_message;
+  const std::string* message_to_send = &message;
+  if (EnableInternalDevToolsBinaryProtocol()) {
+    if (client_->UsesBinaryProtocol()) {
+      // If the client uses the binary protocol, then |message| is already
+      // CBOR (it comes from the client).
+      DCHECK(IsCBOR(message));
+    } else {
+      converted_cbor_message = ConvertJSONToCBOR(message);
+      message_to_send = &converted_cbor_message;
+    }
+  }
   if (proxy_delegate_) {
-    // Note: we assume that child sessions are not forwarding.
-    proxy_delegate_->SendMessageToBackend(this, message);
+    // TODO(dgozman): revisit the proxy delegate.
+    // TODO(johannes): Should we send CBOR to an external backend? Maybe not!
+    // Revisit this when EnableInternalDevToolsBinaryProtocol() is on
+    // unconditionally.  Note: we assume that child sessions are not forwarding.
+    proxy_delegate_->SendMessageToBackend(this, *message_to_send);
     return true;
   }
 
@@ -146,14 +168,15 @@
 
   std::string session_id;
   if (!value || !value->getString(kSessionId, &session_id))
-    return DispatchProtocolMessageInternal(message, std::move(value));
+    return DispatchProtocolMessageInternal(*message_to_send, std::move(value));
 
   auto it = child_sessions_.find(session_id);
   if (it == child_sessions_.end())
     return false;
   DevToolsSession* session = it->second;
   DCHECK(!session->proxy_delegate_);
-  return session->DispatchProtocolMessageInternal(message, std::move(value));
+  return session->DispatchProtocolMessageInternal(*message_to_send,
+                                                  std::move(value));
 }
 
 bool DevToolsSession::DispatchProtocolMessageInternal(
@@ -242,34 +265,73 @@
   suspended_messages_.clear();
 }
 
+// The following methods handle responses or notifications coming from
+// the browser to the client.
+static void SendProtocolResponseOrNotification(
+    DevToolsAgentHostClient* client,
+    DevToolsAgentHostImpl* agent_host,
+    std::unique_ptr<protocol::Serializable> message) {
+  if (!EnableInternalDevToolsBinaryProtocol()) {
+    bool binary = client->UsesBinaryProtocol();
+    client->DispatchProtocolMessage(agent_host, message->serialize(binary));
+    return;
+  }
+  std::string cbor = message->serialize(/*binary=*/true);
+  DCHECK(IsCBOR(cbor));
+  client->DispatchProtocolMessage(agent_host, client->UsesBinaryProtocol()
+                                                  ? cbor
+                                                  : ConvertCBORToJSON(cbor));
+}
+
 void DevToolsSession::sendProtocolResponse(
     int call_id,
     std::unique_ptr<protocol::Serializable> message) {
-  bool binary = client_->UsesBinaryProtocol();
-  client_->DispatchProtocolMessage(agent_host_, message->serialize(binary));
+  SendProtocolResponseOrNotification(client_, agent_host_, std::move(message));
   // |this| may be deleted at this point.
 }
 
 void DevToolsSession::sendProtocolNotification(
     std::unique_ptr<protocol::Serializable> message) {
-  bool binary = client_->UsesBinaryProtocol();
-  client_->DispatchProtocolMessage(agent_host_, message->serialize(binary));
+  SendProtocolResponseOrNotification(client_, agent_host_, std::move(message));
   // |this| may be deleted at this point.
 }
 
 void DevToolsSession::flushProtocolNotifications() {
 }
 
+// The following methods handle responses or notifications coming from
+// the renderer (blink) to the client.
+static void DispatchProtocolResponseOrNotification(
+    DevToolsAgentHostClient* client,
+    DevToolsAgentHostImpl* agent_host,
+    blink::mojom::DevToolsMessagePtr message) {
+  // TODO(johannes): When eliminating the
+  // --enable-internal-devtools-binary-protocol flag, reconsider the similarity
+  // with SendProtocolResponseOrNotification above and either merge the methods
+  // or inline them again.
+  if (!EnableInternalDevToolsBinaryProtocol()) {
+    client->DispatchProtocolMessage(
+        agent_host,
+        std::string(reinterpret_cast<const char*>(message->data.data()),
+                    message->data.size()));
+    return;
+  }
+  std::string cbor(reinterpret_cast<const char*>(message->data.data()),
+                   message->data.size());
+  DCHECK(IsCBOR(cbor));
+  client->DispatchProtocolMessage(agent_host, client->UsesBinaryProtocol()
+                                                  ? cbor
+                                                  : ConvertCBORToJSON(cbor));
+}
+
 void DevToolsSession::DispatchProtocolResponse(
     blink::mojom::DevToolsMessagePtr message,
     int call_id,
     blink::mojom::DevToolsSessionStatePtr updates) {
   ApplySessionStateUpdates(std::move(updates));
   waiting_for_response_messages_.erase(call_id);
-  client_->DispatchProtocolMessage(
-      agent_host_,
-      std::string(reinterpret_cast<const char*>(message->data.data()),
-                  message->data.size()));
+  DispatchProtocolResponseOrNotification(client_, agent_host_,
+                                         std::move(message));
   // |this| may be deleted at this point.
 }
 
@@ -277,10 +339,8 @@
     blink::mojom::DevToolsMessagePtr message,
     blink::mojom::DevToolsSessionStatePtr updates) {
   ApplySessionStateUpdates(std::move(updates));
-  client_->DispatchProtocolMessage(
-      agent_host_,
-      std::string(reinterpret_cast<const char*>(message->data.data()),
-                  message->data.size()));
+  DispatchProtocolResponseOrNotification(client_, agent_host_,
+                                         std::move(message));
   // |this| may be deleted at this point.
 }
 
diff --git a/content/browser/devtools/devtools_session.h b/content/browser/devtools/devtools_session.h
index 413d757..619c96e 100644
--- a/content/browser/devtools/devtools_session.h
+++ b/content/browser/devtools/devtools_session.h
@@ -42,6 +42,11 @@
   DevToolsAgentHostClient* client() { return client_; }
   DevToolsSession* GetRootSession();
 
+  // Whether this session uses binary protocol. This is true if
+  // |client()->UsesBinaryProtocol()| or if the
+  // --enable-devtools-binary-protocol flag is set.
+  bool UsesBinaryProtocol() const;
+
   // Browser-only sessions do not talk to mojom::DevToolsAgent, but instead
   // handle all protocol messages locally in the browser process.
   void SetBrowserOnly(bool browser_only);
diff --git a/content/browser/devtools/devtools_session_encoding.cc b/content/browser/devtools/devtools_session_encoding.cc
new file mode 100644
index 0000000..a297b78e0
--- /dev/null
+++ b/content/browser/devtools/devtools_session_encoding.cc
@@ -0,0 +1,94 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/devtools/devtools_session_encoding.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
+#include "content/public/common/content_switches.h"
+#include "third_party/inspector_protocol/encoding/encoding.h"
+
+using inspector_protocol_encoding::span;
+using inspector_protocol_encoding::Status;
+using inspector_protocol_encoding::StreamingParserHandler;
+using inspector_protocol_encoding::cbor::NewCBOREncoder;
+using inspector_protocol_encoding::cbor::ParseCBOR;
+using inspector_protocol_encoding::json::NewJSONEncoder;
+using inspector_protocol_encoding::json::ParseJSON;
+using inspector_protocol_encoding::json::Platform;
+
+namespace content {
+namespace {
+// ContentShellPlatform allows us to inject the string<->double conversion
+// routines from base:: into the inspector_protocol JSON parser / serializer.
+class ContentShellPlatform : public Platform {
+ public:
+  bool StrToD(const char* str, double* result) const override {
+    return base::StringToDouble(str, result);
+  }
+
+  // Prints |value| in a format suitable for JSON.
+  std::unique_ptr<char[]> DToStr(double value) const override {
+    std::string str = base::NumberToString(value);
+    std::unique_ptr<char[]> result(new char[str.size() + 1]);
+    memcpy(result.get(), str.c_str(), str.size() + 1);
+    return result;
+  }
+};
+}  // namespace
+bool EnableInternalDevToolsBinaryProtocol() {
+  static bool enabled = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnableInternalDevToolsBinaryProtocol);
+  return enabled;
+}
+
+// TODO(johannes): Move this into the cbor library. Don't want to
+// do this just yet to first gain more experience about the most
+// appropriate API, including how to propagate errors.
+std::string ConvertCBORToJSON(const std::string& cbor) {
+  ContentShellPlatform platform;
+  std::string json_message;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(&platform, &json_message, &status);
+  ParseCBOR(
+      span<uint8_t>(reinterpret_cast<const uint8_t*>(cbor.data()), cbor.size()),
+      json_writer.get());
+  if (!status.ok()) {
+    LOG(ERROR) << "ConvertCBORToJSON error "
+               << static_cast<uint32_t>(status.error) << " position "
+               << static_cast<uint32_t>(status.pos);
+    return "";
+  }
+  return json_message;
+}
+
+std::string ConvertJSONToCBOR(const std::string& json) {
+  ContentShellPlatform platform;
+  std::vector<uint8_t> cbor;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> encoder =
+      NewCBOREncoder(&cbor, &status);
+  ParseJSON(
+      &platform,
+      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
+      encoder.get());
+  if (!status.ok()) {
+    LOG(ERROR) << "ConvertJSONToCBOR error "
+               << static_cast<uint32_t>(status.error) << " position "
+               << static_cast<uint32_t>(status.pos);
+    return "";
+  }
+  return std::string(cbor.begin(), cbor.end());
+}
+
+bool IsCBOR(const std::string& serialized) {
+  return serialized.size() >= 6 &&
+         reinterpret_cast<const uint8_t&>(serialized[0]) == 0xd8 &&
+         reinterpret_cast<const uint8_t&>(serialized[1]) == 0x5a;
+}
+}  // namespace content
diff --git a/content/browser/devtools/devtools_session_encoding.h b/content/browser/devtools/devtools_session_encoding.h
new file mode 100644
index 0000000..f4bb1ef
--- /dev/null
+++ b/content/browser/devtools/devtools_session_encoding.h
@@ -0,0 +1,29 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_SESSION_ENCODING_H_
+#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_SESSION_ENCODING_H_
+
+#include <string>
+
+namespace content {
+
+// Whether --enable-internal-devtools-binary-parotocol was passed on the command
+// line.  If so, the DevtoolsSession will convert all outgoing traffic to agents
+// / handlers / etc. to the CBOR-based binary protocol.
+bool EnableInternalDevToolsBinaryProtocol();
+
+// Conversion routines between the inspector protocol binary wire format
+// (based on CBOR RFC 7049) and JSON.
+std::string ConvertCBORToJSON(const std::string& cbor);
+std::string ConvertJSONToCBOR(const std::string& json);
+
+// Whether |serialized| is CBOR produced by the inspector protocol.
+// We always enclose messages with an envelope, that is, the 0xd8 tag
+// followed by the indicator for the byte string, followed by a 32 bit
+// length value (4 bytes).
+bool IsCBOR(const std::string& serialized);
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_SESSION_ENCODING_H_
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index d88e0a5..b4d72bc 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -306,8 +306,7 @@
   session->AddHandler(std::make_unique<protocol::SecurityHandler>());
   if (!frame_tree_node_ || !frame_tree_node_->parent()) {
     session->AddHandler(std::make_unique<protocol::TracingHandler>(
-        frame_tree_node_, GetIOContext(),
-        session->client()->UsesBinaryProtocol()));
+        frame_tree_node_, GetIOContext(), session->UsesBinaryProtocol()));
   }
 
   if (sessions().empty()) {
diff --git a/content/browser/frame_host/render_frame_message_filter_browsertest.cc b/content/browser/frame_host/render_frame_message_filter_browsertest.cc
index 1eb2cb7c..a061357 100644
--- a/content/browser/frame_host/render_frame_message_filter_browsertest.cc
+++ b/content/browser/frame_host/render_frame_message_filter_browsertest.cc
@@ -312,7 +312,7 @@
 
 class WaitingCookieStore : public net::CookieMonster {
  public:
-  WaitingCookieStore() : CookieMonster(nullptr, nullptr, nullptr) {}
+  WaitingCookieStore() : CookieMonster(nullptr, nullptr) {}
 
   void GetCookieListWithOptionsAsync(const GURL& url,
                                      const net::CookieOptions& options,
diff --git a/content/browser/indexed_db/indexed_db_backing_store.h b/content/browser/indexed_db/indexed_db_backing_store.h
index efc38bbf..81622e8 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.h
+++ b/content/browser/indexed_db/indexed_db_backing_store.h
@@ -569,6 +569,8 @@
   // an otherwise healthy backing store.
   leveldb::Status RevertSchemaToV2();
 
+  bool is_incognito() const { return !indexed_db_factory_; }
+
   base::WeakPtr<IndexedDBBackingStore> AsWeakPtr() {
     return weak_factory_.GetWeakPtr();
   }
@@ -579,7 +581,6 @@
   friend class base::RefCounted<IndexedDBBackingStore>;
   virtual ~IndexedDBBackingStore();
 
-  bool is_incognito() const { return !indexed_db_factory_; }
 
   leveldb::Status AnyDatabaseContainsBlobs(LevelDBTransaction* transaction,
                                            bool* blobs_exist);
diff --git a/content/browser/indexed_db/indexed_db_browsertest.cc b/content/browser/indexed_db/indexed_db_browsertest.cc
index 1306df4..9013eae 100644
--- a/content/browser/indexed_db/indexed_db_browsertest.cc
+++ b/content/browser/indexed_db/indexed_db_browsertest.cc
@@ -92,7 +92,9 @@
         failure_class, failure_method, fail_on_instance_num, fail_on_call_num);
   }
 
-  void SimpleTest(const GURL& test_url, bool incognito = false) {
+  void SimpleTest(const GURL& test_url,
+                  bool incognito = false,
+                  Shell** shell_out = nullptr) {
     // The test page will perform tests on IndexedDB, then navigate to either
     // a #pass or #fail ref.
     Shell* the_browser = incognito ? CreateOffTheRecordBrowser() : shell();
@@ -109,6 +111,8 @@
           &js_result));
       FAIL() << "Failed: " << js_result;
     }
+    if (shell_out)
+      *shell_out = the_browser;
   }
 
   void NavigateAndWaitForTitle(Shell* shell,
@@ -309,6 +313,21 @@
   NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
 }
 
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug941965Test) {
+  // Double-open an incognito window to test that saving & reading a blob from
+  // indexeddb works.
+  Shell* incognito_browser = nullptr;
+  SimpleTest(GetTestUrl("indexeddb", "simple_blob_read.html"), true,
+             &incognito_browser);
+  ASSERT_TRUE(incognito_browser);
+  incognito_browser->Close();
+  incognito_browser = nullptr;
+  SimpleTest(GetTestUrl("indexeddb", "simple_blob_read.html"), true,
+             &incognito_browser);
+  ASSERT_TRUE(incognito_browser);
+  incognito_browser->Close();
+}
+
 class IndexedDBBrowserTestWithLowQuota : public IndexedDBBrowserTest {
  public:
   IndexedDBBrowserTestWithLowQuota() {}
diff --git a/content/browser/indexed_db/indexed_db_factory_impl.cc b/content/browser/indexed_db/indexed_db_factory_impl.cc
index 8dc8432..f994f8cb 100644
--- a/content/browser/indexed_db/indexed_db_factory_impl.cc
+++ b/content/browser/indexed_db/indexed_db_factory_impl.cc
@@ -717,9 +717,14 @@
   if (!s.ok())
     return {std::move(backing_store), s, data_loss_info, disk_full};
 
-  backing_store = CreateBackingStore(origin, blob_path, std::move(database),
-                                     context_->TaskRunner());
-
+  if (data_directory.empty()) {
+    backing_store = base::MakeRefCounted<IndexedDBBackingStore>(
+        nullptr, origin, base::FilePath(), std::move(database),
+        context_->TaskRunner());
+  } else {
+    backing_store = CreateBackingStore(origin, blob_path, std::move(database),
+                                       context_->TaskRunner());
+  }
   bool first_open_since_startup =
       backends_opened_since_startup_.insert(origin).second;
   s = backing_store->Initialize(
diff --git a/content/browser/indexed_db/indexed_db_factory_unittest.cc b/content/browser/indexed_db/indexed_db_factory_unittest.cc
index 6cd3bf72..7f6b1e9 100644
--- a/content/browser/indexed_db/indexed_db_factory_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_factory_unittest.cc
@@ -386,6 +386,20 @@
   loop.Run();
 }
 
+TEST_F(IndexedDBFactoryTest, MemoryBackingStoreDetectedAsIncognito) {
+  base::RunLoop loop;
+  context()->TaskRunner()->PostTask(
+      FROM_HERE, base::BindLambdaForTesting([&]() {
+        auto factory = base::MakeRefCounted<MockIDBFactory>(context());
+        const Origin origin1 = Origin::Create(GURL("http://localhost:81"));
+        auto mem_store1 =
+            factory->TestOpenBackingStore(origin1, base::FilePath());
+        EXPECT_TRUE(mem_store1->is_incognito());
+        loop.Quit();
+      }));
+  loop.Run();
+}
+
 TEST_F(IndexedDBFactoryTest, RejectLongOrigins) {
   base::RunLoop loop;
   context()->TaskRunner()->PostTask(
diff --git a/content/browser/net/quota_policy_cookie_store.cc b/content/browser/net/quota_policy_cookie_store.cc
index 7416a86..bad8555 100644
--- a/content/browser/net/quota_policy_cookie_store.cc
+++ b/content/browser/net/quota_policy_cookie_store.cc
@@ -74,8 +74,8 @@
 
   if (config.path.empty()) {
     // Empty path means in-memory store.
-    cookie_monster = std::make_unique<net::CookieMonster>(
-        nullptr /* store */, nullptr /* channel_id_service */, net_log);
+    cookie_monster =
+        std::make_unique<net::CookieMonster>(nullptr /* store */, net_log);
   } else {
     scoped_refptr<base::SequencedTaskRunner> client_task_runner =
         config.client_task_runner;
@@ -103,8 +103,8 @@
             sqlite_store.get(),
             config.storage_policy.get());
 
-    cookie_monster = std::make_unique<net::CookieMonster>(
-        persistent_store, config.channel_id_service, net_log);
+    cookie_monster =
+        std::make_unique<net::CookieMonster>(persistent_store, net_log);
     if (config.persist_session_cookies)
       cookie_monster->SetPersistSessionCookies(true);
   }
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc
index e7d260d..fbdbf2d6 100644
--- a/content/browser/renderer_host/delegated_frame_host.cc
+++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -27,7 +27,6 @@
 #include "components/viz/service/surfaces/surface_hittest.h"
 #include "content/browser/compositor/surface_utils.h"
 #include "content/browser/gpu/compositor_util.h"
-#include "content/common/tab_switching_time_callback.h"
 #include "content/public/common/content_switches.h"
 #include "third_party/khronos/GLES2/gl2.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -93,14 +92,18 @@
 void DelegatedFrameHost::WasShown(
     const viz::LocalSurfaceId& new_local_surface_id,
     const gfx::Size& new_dip_size,
-    bool record_presentation_time) {
+    bool record_presentation_time,
+    base::TimeTicks tab_switch_start_time) {
   // Cancel any pending frame eviction and unpause it if paused.
   frame_eviction_state_ = FrameEvictionState::kNotStarted;
 
   frame_evictor_->SetVisible(true);
-  if (record_presentation_time && compositor_) {
+  if (record_presentation_time && compositor_ &&
+      !tab_switch_start_time.is_null()) {
     compositor_->RequestPresentationTimeForNextFrame(
-        CreateTabSwitchingTimeRecorder(base::TimeTicks::Now()));
+        tab_switch_time_recorder_.BeginTimeRecording(
+            tab_switch_start_time, true /* has_saved_frames */,
+            base::TimeTicks::Now()));
   }
 
   // Use the default deadline to synchronize web content with browser UI.
diff --git a/content/browser/renderer_host/delegated_frame_host.h b/content/browser/renderer_host/delegated_frame_host.h
index a765488..9accab42 100644
--- a/content/browser/renderer_host/delegated_frame_host.h
+++ b/content/browser/renderer_host/delegated_frame_host.h
@@ -11,6 +11,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
 #include "components/viz/client/frame_evictor.h"
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
@@ -21,6 +22,7 @@
 #include "content/browser/compositor/image_transport_factory.h"
 #include "content/browser/renderer_host/dip_util.h"
 #include "content/common/content_export.h"
+#include "content/common/tab_switch_time_recorder.h"
 #include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h"
 #include "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom.h"
 #include "ui/compositor/compositor.h"
@@ -110,7 +112,8 @@
   // TODO(ccameron): Include device scale factor here.
   void WasShown(const viz::LocalSurfaceId& local_surface_id,
                 const gfx::Size& dip_size,
-                bool record_presentation_time);
+                bool record_presentation_time,
+                base::TimeTicks tab_switch_start_time = base::TimeTicks());
   void EmbedSurface(const viz::LocalSurfaceId& local_surface_id,
                     const gfx::Size& dip_size,
                     cc::DeadlinePolicy deadline_policy);
@@ -254,6 +257,8 @@
   // compositor frame is submitted.
   std::unique_ptr<ui::Layer> stale_content_layer_;
 
+  TabSwitchTimeRecorder tab_switch_time_recorder_;
+
   base::WeakPtrFactory<DelegatedFrameHost> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(DelegatedFrameHost);
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 77882c7c2..798c104 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2833,7 +2833,7 @@
   if (!SiteInstanceImpl::IsOriginLockASite(lock_url))
     return;
 
-  GetRendererInterface()->SetIsLockedToSite(lock_url);
+  GetRendererInterface()->SetIsLockedToSite();
 }
 
 bool RenderProcessHostImpl::IsForGuestsOnly() {
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 098fbaa..4e3f74dd 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -792,7 +792,8 @@
     observer.RenderWidgetHostVisibilityChanged(this, false);
 }
 
-void RenderWidgetHostImpl::WasShown(bool record_presentation_time) {
+void RenderWidgetHostImpl::WasShown(bool record_presentation_time,
+                                    base::TimeTicks tab_switch_start_time) {
   if (!is_hidden_)
     return;
 
@@ -810,7 +811,7 @@
   Send(new WidgetMsg_WasShown(
       routing_id_,
       record_presentation_time ? base::TimeTicks::Now() : base::TimeTicks(),
-      view_->is_evicted()));
+      view_->is_evicted(), tab_switch_start_time));
   view_->reset_is_evicted();
 
   process_->UpdateClientPriority(this);
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 5a73c4db..ce8bfd8 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -308,7 +308,8 @@
   // Called to notify the RenderWidget that it has been hidden or restored from
   // having been hidden.
   void WasHidden();
-  void WasShown(bool record_presentation_time);
+  void WasShown(bool record_presentation_time,
+                base::TimeTicks tab_switch_start_time = base::TimeTicks());
 
 #if defined(OS_ANDROID)
   // Set the importance of widget. The importance is passed onto
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index 1492a21..78ae46d6c 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -688,7 +688,8 @@
         std::make_unique<TestImageTransportFactory>());
 #endif
 #if defined(OS_ANDROID)
-    ui::SetScreenAndroid();  // calls display::Screen::SetScreenInstance().
+    // calls display::Screen::SetScreenInstance().
+    ui::SetScreenAndroid(false /* use_display_wide_color_gamut */);
 #endif
 #if defined(USE_AURA)
     screen_.reset(aura::TestScreen::Create(gfx::Size()));
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index e605555..b72093a 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -65,9 +65,11 @@
 #include "content/public/browser/android/compositor.h"
 #include "content/public/browser/android/synchronous_compositor_client.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host_iterator.h"
+#include "content/public/common/content_client.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/use_zoom_for_dsf_policy.h"
@@ -2405,8 +2407,11 @@
 }
 
 void RenderWidgetHostViewAndroid::GetScreenInfo(ScreenInfo* screen_info) const {
+  bool use_window_wide_color_gamut =
+      GetContentClient()->browser()->GetWideColorGamutHeuristic() ==
+      ContentBrowserClient::WideColorGamutHeuristic::kUseWindow;
   auto* window = view_.GetWindowAndroid();
-  if (!window) {
+  if (!window || !use_window_wide_color_gamut) {
     RenderWidgetHostViewBase::GetScreenInfo(screen_info);
     return;
   }
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 5ffcf79..71044d1 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -676,11 +676,13 @@
   if (!host_->is_hidden())
     return;
 
+  auto tab_switch_start_time = GetAndResetLastTabChangeStartTime();
   bool has_saved_frame =
       delegated_frame_host_ ? delegated_frame_host_->HasSavedFrame() : false;
 
   const bool renderer_should_record_presentation_time = !has_saved_frame;
-  host()->WasShown(renderer_should_record_presentation_time);
+  host()->WasShown(renderer_should_record_presentation_time,
+                   tab_switch_start_time);
 
   aura::Window* root = window_->GetRootWindow();
   if (root) {
@@ -696,7 +698,8 @@
     const bool record_presentation_time = has_saved_frame;
     delegated_frame_host_->WasShown(
         GetLocalSurfaceIdAllocation().local_surface_id(),
-        window_->bounds().size(), record_presentation_time);
+        window_->bounds().size(), record_presentation_time,
+        tab_switch_start_time);
   }
 
 #if defined(OS_WIN)
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc
index e93471a..be38173 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -817,6 +817,17 @@
   return nullptr;
 }
 
+void RenderWidgetHostViewBase::SetLastTabChangeStartTime(
+    base::TimeTicks start_time) {
+  last_tab_switch_start_time_ = start_time;
+}
+
+base::TimeTicks RenderWidgetHostViewBase::GetAndResetLastTabChangeStartTime() {
+  auto stored_time = last_tab_switch_start_time_;
+  last_tab_switch_start_time_ = base::TimeTicks();
+  return stored_time;
+}
+
 #if defined(USE_AURA)
 void RenderWidgetHostViewBase::EmbedChildFrameRendererWindowTreeClient(
     RenderWidgetHostViewBase* root_view,
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h
index 104be412..6aa5e70 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -141,6 +141,7 @@
   float GetDeviceScaleFactor() const final;
   TouchSelectionControllerClientManager*
   GetTouchSelectionControllerClientManager() override;
+  void SetLastTabChangeStartTime(base::TimeTicks start_time) final;
 
   // This only needs to be overridden by RenderWidgetHostViewBase subclasses
   // that handle content embedded within other RenderWidgetHostViews.
@@ -200,6 +201,11 @@
   virtual viz::ScopedSurfaceIdAllocator DidUpdateVisualProperties(
       const cc::RenderFrameMetadata& metadata);
 
+  // Returns the time set by SetLastTabChangeStartTime. If this was not
+  // preceded by a call to SetLastTabChangeStartTime, this will return null.
+  // Calling this will reset the stored time to null.
+  base::TimeTicks GetAndResetLastTabChangeStartTime();
+
   base::WeakPtr<RenderWidgetHostViewBase> GetWeakPtr();
 
   //----------------------------------------------------------------------------
@@ -740,6 +746,11 @@
 
   base::Optional<blink::WebGestureEvent> pending_touchpad_pinch_begin_;
 
+  // The last tab switch processing start time. This should only be set and
+  // retrieved using SetLastTabChangeStartTime and
+  // GetAndResetLastTabChangeStartTime.
+  base::TimeTicks last_tab_switch_start_time_;
+
   // True when StopFlingingIfNecessary() calls StopFling().
   bool view_stopped_flinging_for_test_ = false;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
index 5340e6c..694b1f1 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
@@ -212,7 +212,8 @@
   // Hide the frame and make it visible again, to force it to record the
   // tab-switch time, which is generated from presentation-feedback.
   child_rwh_impl->WasHidden();
-  child_rwh_impl->WasShown(true /* record_presentation_time */);
+  child_rwh_impl->WasShown(true /* record_presentation_time */,
+                           base::TimeTicks::Now());
   // Force the child to submit a new frame.
   ASSERT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
                             "document.write('Force a new frame.');"));
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index f6937e3..cb067c0 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -471,8 +471,11 @@
   bool has_saved_frame =
       delegated_frame_host ? delegated_frame_host->HasSavedFrame() : false;
 
+  auto tab_switch_start_time = GetAndResetLastTabChangeStartTime();
+
   const bool renderer_should_record_presentation_time = !has_saved_frame;
-  host()->WasShown(renderer_should_record_presentation_time);
+  host()->WasShown(renderer_should_record_presentation_time,
+                   tab_switch_start_time);
 
   if (delegated_frame_host) {
     // If the frame for the renderer is already available, then the
@@ -481,7 +484,8 @@
     delegated_frame_host->WasShown(
         browser_compositor_->GetRendererLocalSurfaceIdAllocation()
             .local_surface_id(),
-        browser_compositor_->GetRendererSize(), record_presentation_time);
+        browser_compositor_->GetRendererSize(), record_presentation_time,
+        tab_switch_start_time);
   }
 }
 
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc
index fa59552..0fbce527 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -132,7 +132,7 @@
   }
   void SetSchedulerKeepActive(bool keep_active) override { NOTREACHED(); }
   void ProcessPurgeAndSuspend() override { NOTREACHED(); }
-  void SetIsLockedToSite(const GURL& lock_url) override { NOTREACHED(); }
+  void SetIsLockedToSite() override { NOTREACHED(); }
   void EnableV8LowMemoryMode() override { NOTREACHED(); }
 
   EmbeddedWorkerTestHelper* helper_;
diff --git a/content/browser/web_contents/web_contents_view_aura_browsertest.cc b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
index 83e4425..6b79a2b9 100644
--- a/content/browser/web_contents/web_contents_view_aura_browsertest.cc
+++ b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
@@ -71,13 +71,6 @@
  public:
   WebContentsViewAuraTest() = default;
 
-  // Executes the javascript synchronously and makes sure the returned value is
-  // freed properly.
-  void ExecuteSyncJSFunction(RenderFrameHost* rfh, const std::string& jscript) {
-    std::unique_ptr<base::Value> value =
-        content::ExecuteScriptAndGetValue(rfh, jscript);
-  }
-
   // Starts the test server and navigates to the given url. Sets a large enough
   // size to the root window.  Returns after the navigation to the url is
   // complete.
@@ -115,10 +108,10 @@
     EXPECT_EQ(0, index);
 
     if (touch_handler)
-      ExecuteSyncJSFunction(main_frame, "install_touch_handler()");
+      content::ExecuteScriptAndGetValue(main_frame, "install_touch_handler()");
 
-    ExecuteSyncJSFunction(main_frame, "navigate_next()");
-    ExecuteSyncJSFunction(main_frame, "navigate_next()");
+    content::ExecuteScriptAndGetValue(main_frame, "navigate_next()");
+    content::ExecuteScriptAndGetValue(main_frame, "navigate_next()");
     value = content::ExecuteScriptAndGetValue(main_frame, "get_current()");
     ASSERT_TRUE(value->GetAsInteger(&index));
     EXPECT_EQ(2, index);
@@ -323,7 +316,7 @@
   ASSERT_TRUE(value->GetAsInteger(&index));
   EXPECT_EQ(0, index);
 
-  ExecuteSyncJSFunction(main_frame, "navigate_next()");
+  content::ExecuteScriptAndGetValue(main_frame, "navigate_next()");
   value = content::ExecuteScriptAndGetValue(main_frame, "get_current()");
   ASSERT_TRUE(value->GetAsInteger(&index));
   EXPECT_EQ(1, index);
@@ -400,9 +393,9 @@
       ui::ScopedAnimationDurationScaleMode::FAST_DURATION);
 
   // Make sure the page has both back/forward history.
-  ExecuteSyncJSFunction(main_frame, "navigate_next()");
+  content::ExecuteScriptAndGetValue(main_frame, "navigate_next()");
   EXPECT_EQ(1, GetCurrentIndex());
-  ExecuteSyncJSFunction(main_frame, "navigate_next()");
+  content::ExecuteScriptAndGetValue(main_frame, "navigate_next()");
   EXPECT_EQ(2, GetCurrentIndex());
   web_contents->GetController().GoBack();
   EXPECT_EQ(1, GetCurrentIndex());
@@ -485,7 +478,8 @@
 
   WebContentsImpl* web_contents =
       static_cast<WebContentsImpl*>(shell()->web_contents());
-  ExecuteSyncJSFunction(web_contents->GetMainFrame(), "navigate_next()");
+  content::ExecuteScriptAndGetValue(web_contents->GetMainFrame(),
+                                    "navigate_next()");
   EXPECT_EQ(1, GetCurrentIndex());
 
   aura::Window* content = web_contents->GetContentNativeView();
@@ -505,7 +499,8 @@
 
   WebContentsImpl* web_contents =
       static_cast<WebContentsImpl*>(shell()->web_contents());
-  ExecuteSyncJSFunction(web_contents->GetMainFrame(), "navigate_next()");
+  content::ExecuteScriptAndGetValue(web_contents->GetMainFrame(),
+                                    "navigate_next()");
   EXPECT_EQ(1, GetCurrentIndex());
 
   aura::Window* content = web_contents->GetContentNativeView();
@@ -540,11 +535,11 @@
       static_cast<WebContentsImpl*>(shell()->web_contents());
   NavigationController& controller = web_contents->GetController();
   RenderFrameHost* main_frame = web_contents->GetMainFrame();
-  ExecuteSyncJSFunction(main_frame, "install_touch_handler()");
+  content::ExecuteScriptAndGetValue(main_frame, "install_touch_handler()");
 
   // Navigate twice, then navigate back in history once.
-  ExecuteSyncJSFunction(main_frame, "navigate_next()");
-  ExecuteSyncJSFunction(main_frame, "navigate_next()");
+  content::ExecuteScriptAndGetValue(main_frame, "navigate_next()");
+  content::ExecuteScriptAndGetValue(main_frame, "navigate_next()");
   EXPECT_EQ(2, GetCurrentIndex());
   EXPECT_TRUE(controller.CanGoBack());
   EXPECT_FALSE(controller.CanGoForward());
@@ -630,16 +625,17 @@
   gfx::Rect bounds = content->GetBoundsInRootWindow();
   const int dx = 20;
 
-  ExecuteSyncJSFunction(web_contents->GetMainFrame(),
-                        "install_touchmove_handler()");
+  content::ExecuteScriptAndGetValue(web_contents->GetMainFrame(),
+                                    "install_touchmove_handler()");
 
   WaitAFrame();
 
   for (int navigated = 0; navigated <= 1; ++navigated) {
     if (navigated) {
-      ExecuteSyncJSFunction(web_contents->GetMainFrame(), "navigate_next()");
-      ExecuteSyncJSFunction(web_contents->GetMainFrame(),
-                            "reset_touchmove_count()");
+      content::ExecuteScriptAndGetValue(web_contents->GetMainFrame(),
+                                        "navigate_next()");
+      content::ExecuteScriptAndGetValue(web_contents->GetMainFrame(),
+                                        "reset_touchmove_count()");
     }
     InputEventAckWaiter touch_start_waiter(
         GetRenderWidgetHost(),
diff --git a/content/browser/webrtc/webrtc_video_capture_browsertest.cc b/content/browser/webrtc/webrtc_video_capture_browsertest.cc
index 9e38210..a9eb78c 100644
--- a/content/browser/webrtc/webrtc_video_capture_browsertest.cc
+++ b/content/browser/webrtc/webrtc_video_capture_browsertest.cc
@@ -22,16 +22,6 @@
 
 namespace content {
 
-#if defined(OS_ANDROID)
-// Mojo video capture is currently not supported on Android
-// TODO(chfremer): Enable as soon as https://crbug.com/720500 is resolved.
-#define MAYBE_RecoverFromCrashInVideoCaptureProcess \
-  DISABLED_RecoverFromCrashInVideoCaptureProcess
-#else
-#define MAYBE_RecoverFromCrashInVideoCaptureProcess \
-  RecoverFromCrashInVideoCaptureProcess
-#endif  // defined(OS_ANDROID)
-
 namespace {
 
 static const char kVideoCaptureHtmlFile[] = "/media/video_capture_test.html";
@@ -63,6 +53,7 @@
   void SetUp() override {
     ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
     EnablePixelOutput();
+    embedded_test_server()->StartAcceptingConnections();
     ContentBrowserTest::SetUp();
   }
 
@@ -73,8 +64,12 @@
 };
 
 IN_PROC_BROWSER_TEST_F(WebRtcVideoCaptureBrowserTest,
-                       MAYBE_RecoverFromCrashInVideoCaptureProcess) {
-  embedded_test_server()->StartAcceptingConnections();
+                       RecoverFromCrashInVideoCaptureProcess) {
+  // This test only makes sense if the video capture service runs in a
+  // separate process.
+  if (!features::IsVideoCaptureServiceEnabledForOutOfProcess())
+    return;
+
   GURL url(embedded_test_server()->GetURL(kVideoCaptureHtmlFile));
   NavigateToURL(shell(), url);
 
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 573ac8a..b2edd8c 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -234,8 +234,8 @@
     "skia_utils.h",
     "swapped_out_messages.cc",
     "swapped_out_messages.h",
-    "tab_switching_time_callback.cc",
-    "tab_switching_time_callback.h",
+    "tab_switch_time_recorder.cc",
+    "tab_switch_time_recorder.h",
     "task_scheduler.cc",
     "task_scheduler.h",
     "text_input_client_messages.h",
diff --git a/content/common/origin_util.cc b/content/common/origin_util.cc
index 422c62e2..5869274 100644
--- a/content/common/origin_util.cc
+++ b/content/common/origin_util.cc
@@ -9,43 +9,31 @@
 #include "base/stl_util.h"
 #include "base/strings/pattern.h"
 #include "content/common/url_schemes.h"
-#include "net/base/url_util.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "url/gurl.h"
 #include "url/url_util.h"
 
-namespace {
-
-// This function partially reflects the result from SecurityOrigin::isUnique,
-// not its actual implementation. It takes into account how
-// SecurityOrigin::create might return unique origins for URLs whose schemes are
-// included in SchemeRegistry::shouldTreatURLSchemeAsNoAccess.
-bool IsOriginUnique(const url::Origin& origin) {
-  return origin.opaque() ||
-         base::ContainsValue(url::GetNoAccessSchemes(), origin.scheme());
-}
-
-}  // namespace
-
 namespace content {
 
 bool IsOriginSecure(const GURL& url) {
-  if (url.SchemeIsCryptographic() || url.SchemeIsFile())
+  // TODO(lukasza): data: URLs (and opaque origins associated with them) should
+  // be considered insecure according to
+  // https://www.w3.org/TR/powerful-features/#is-url-trustworthy.
+  // Unfortunately, changing this behavior of content::IsOriginSecure breaks
+  // quite a few tests for now (e.g. considering data: insecure makes us think
+  // that https + data = mixed content), so fixing this is postponed to a
+  // follow-up CL.  WIP CL @ https://crrev.com/c/1505897.
+  if (url.SchemeIs(url::kDataScheme))
     return true;
 
-  if (url.SchemeIsFileSystem() && url.inner_url() &&
-      IsOriginSecure(*url.inner_url())) {
-    return true;
-  }
+  // TODO(lukasza): trustworthiness of blob: URLs should depend on their inner
+  // origin (just as it does for filesystem: URLs).  Changing this behavior of
+  // content::IsOriginSecure breaks some tests, so fixing this is postponed to a
+  // follow-up CL.  WIP CL @ https://crrev.com/c/1506941.
+  if (url.SchemeIs(url::kBlobScheme))
+    return false;
 
-  if (net::IsLocalhost(url))
-    return true;
-
-  if (base::ContainsValue(url::GetSecureSchemes(), url.scheme()))
-    return true;
-
-  return network::IsAllowlistedAsSecureOrigin(
-      url::Origin::Create(url), network::GetSecureOriginAllowlist());
+  return network::IsUrlPotentiallyTrustworthy(url);
 }
 
 bool OriginCanAccessServiceWorkers(const GURL& url) {
@@ -60,22 +48,7 @@
 }
 
 bool IsPotentiallyTrustworthyOrigin(const url::Origin& origin) {
-  // Note: Considering this mirrors SecurityOrigin::isPotentiallyTrustworthy, it
-  // assumes m_isUniqueOriginPotentiallyTrustworthy is set to false. This
-  // implementation follows Blink's default behavior but in the renderer it can
-  // be changed per instance by calls to
-  // SecurityOrigin::setUniqueOriginIsPotentiallyTrustworthy.
-  if (IsOriginUnique(origin))
-    return false;
-
-  if (base::ContainsValue(url::GetSecureSchemes(), origin.scheme()) ||
-      base::ContainsValue(url::GetLocalSchemes(), origin.scheme()) ||
-      net::IsLocalhost(origin.GetURL())) {
-    return true;
-  }
-
-  return network::IsAllowlistedAsSecureOrigin(
-      origin, network::GetSecureOriginAllowlist());
+  return network::IsOriginPotentiallyTrustworthy(origin);
 }
 
 }  // namespace content
diff --git a/content/common/origin_util_unittest.cc b/content/common/origin_util_unittest.cc
index 3c2328b..365b937b 100644
--- a/content/common/origin_util_unittest.cc
+++ b/content/common/origin_util_unittest.cc
@@ -8,7 +8,7 @@
 
 namespace content {
 
-TEST(URLSchemesTest, IsOriginSecure) {
+TEST(OriginUtilTest, IsOriginSecure) {
   EXPECT_TRUE(IsOriginSecure(GURL("file:///test/fun.html")));
   EXPECT_TRUE(IsOriginSecure(GURL("file:///test/")));
 
@@ -45,6 +45,42 @@
   EXPECT_TRUE(IsOriginSecure(GURL("filesystem:ftp://127.0.0.1/temporary/")));
   EXPECT_TRUE(
       IsOriginSecure(GURL("filesystem:https://www.example.com/temporary/")));
+
+  EXPECT_TRUE(IsOriginSecure(GURL("about:blank")));
+  EXPECT_TRUE(IsOriginSecure(GURL("about:blank#ref")));
+  EXPECT_TRUE(IsOriginSecure(GURL("about:srcdoc")));
+
+  EXPECT_FALSE(IsOriginSecure(GURL("javascript:alert('blah')")));
+
+  // TODO(lukasza): data: URLs (and opaque origins associated with them) should
+  // be considered insecure according to
+  // https://www.w3.org/TR/powerful-features/#is-url-trustworthy.
+  // Unfortunately, changing the behavior of content::IsOriginSecure breaks
+  // quite a few tests for now (e.g. considering data: insecure makes us think
+  // that https + data = mixed content).
+  EXPECT_TRUE(IsOriginSecure(GURL("data:test/plain;blah")));
+
+  // TODO(lukasza): trustworthiness of blob: URLs should depend on their inner
+  // origin (just as it does for filesystem: URLs).  Changing this behavior of
+  // content::IsOriginSecure breaks some tests, so fixing this is postponed to a
+  // follow-up CL.
+  EXPECT_FALSE(
+      IsOriginSecure(GURL("blob:https://www.example.com/guid-goes-here")));
+}
+
+TEST(OriginUtilTest, IsPotentiallyTrustworthyOrigin) {
+  EXPECT_FALSE(
+      IsPotentiallyTrustworthyOrigin(url::Origin::Create(GURL("about:blank"))));
+  EXPECT_FALSE(IsPotentiallyTrustworthyOrigin(
+      url::Origin::Create(GURL("about:blank#ref"))));
+  EXPECT_FALSE(IsPotentiallyTrustworthyOrigin(
+      url::Origin::Create(GURL("about:srcdoc"))));
+
+  EXPECT_FALSE(IsPotentiallyTrustworthyOrigin(
+      url::Origin::Create(GURL("javascript:alert('blah')"))));
+
+  EXPECT_FALSE(IsPotentiallyTrustworthyOrigin(
+      url::Origin::Create(GURL("data:test/plain;blah"))));
 }
 
 }  // namespace content
diff --git a/content/common/renderer.mojom b/content/common/renderer.mojom
index 8bb126ba..2796abe 100644
--- a/content/common/renderer.mojom
+++ b/content/common/renderer.mojom
@@ -15,7 +15,6 @@
 import "third_party/blink/public/mojom/service_worker/embedded_worker.mojom";
 import "third_party/blink/public/mojom/user_agent/user_agent_metadata.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
-import "url/mojom/url.mojom";
 
 struct CreateViewParams {
   // Renderer-wide preferences.
@@ -268,9 +267,7 @@
   // Tells the renderer process that it has been locked to a site (i.e., a
   // scheme plus eTLD+1, such as https://google.com), or to a more specific
   // origin.
-  // TODO(nasko): Remove |lock_url| after we've gathered enough information to
-  // debug issues with browser-side security checks. https://crbug.com/931895.
-  SetIsLockedToSite(url.mojom.Url lock_url);
+  SetIsLockedToSite();
 
   // Tells the renderer to enable V8's memory saving mode when possible.
   // This is only used when site-per-process is enabled. If the process
diff --git a/content/common/tab_switch_time_recorder.cc b/content/common/tab_switch_time_recorder.cc
new file mode 100644
index 0000000..c404d4d
--- /dev/null
+++ b/content/common/tab_switch_time_recorder.cc
@@ -0,0 +1,68 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/tab_switch_time_recorder.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/trace_event/trace_event.h"
+#include "ui/gfx/presentation_feedback.h"
+
+namespace content {
+
+TabSwitchTimeRecorder::TabSwitchTimeRecorder() : weak_ptr_factory_(this) {}
+
+TabSwitchTimeRecorder::~TabSwitchTimeRecorder() {}
+
+base::OnceCallback<void(const gfx::PresentationFeedback&)>
+TabSwitchTimeRecorder::BeginTimeRecording(
+    const base::TimeTicks tab_switch_start_time,
+    bool has_saved_frames,
+    const base::TimeTicks render_widget_visibility_request_timestamp) {
+  TRACE_EVENT_ASYNC_BEGIN0("latency", "TabSwitching::Latency",
+                           TRACE_ID_LOCAL(this));
+
+  // Reset all previously generated callbacks to enforce matching
+  // BeginTimeRecording and DidPresentFrame calls. The reason to do this is
+  // because sometimes, we could generate the callback on a tab switch, but no
+  // frame submission occurs, potentially causing wrong metric to be uploaded on
+  // the next tab switch. See crbug.com/936858 for more detail.
+  weak_ptr_factory_.InvalidateWeakPtrs();
+  if (tab_switch_start_time.is_null())
+    return base::DoNothing();
+  else
+    return base::BindOnce(&TabSwitchTimeRecorder::DidPresentFrame, GetWeakPtr(),
+                          has_saved_frames, tab_switch_start_time,
+                          render_widget_visibility_request_timestamp);
+}
+
+void TabSwitchTimeRecorder::DidPresentFrame(
+    bool has_saved_frames,
+    base::TimeTicks tab_switch_start_time,
+    base::TimeTicks render_widget_visibility_request_timestamp,
+    const gfx::PresentationFeedback& feedback) {
+  const auto delta = feedback.timestamp - tab_switch_start_time;
+
+  if (has_saved_frames) {
+    UMA_HISTOGRAM_TIMES("Browser.Tabs.TotalSwitchDuration.WithSavedFrames",
+                        delta);
+  } else {
+    UMA_HISTOGRAM_TIMES("Browser.Tabs.TotalSwitchDuration.NoSavedFrames",
+                        delta);
+  }
+
+  if (!render_widget_visibility_request_timestamp.is_null()) {
+    TRACE_EVENT_ASYNC_END1("latency", "TabSwitching::Latency",
+                           TRACE_ID_LOCAL(this), "latency",
+                           delta.InMillisecondsF());
+    UMA_HISTOGRAM_TIMES(
+        "MPArch.RWH_TabSwitchPaintDuration",
+        feedback.timestamp - render_widget_visibility_request_timestamp);
+  }
+}
+
+}  // namespace content
diff --git a/content/common/tab_switch_time_recorder.h b/content/common/tab_switch_time_recorder.h
new file mode 100644
index 0000000..e5cf3a1
--- /dev/null
+++ b/content/common/tab_switch_time_recorder.h
@@ -0,0 +1,55 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_TAB_SWITCH_TIME_RECORDER_H_
+#define CONTENT_COMMON_TAB_SWITCH_TIME_RECORDER_H_
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+
+namespace gfx {
+struct PresentationFeedback;
+}
+
+namespace content {
+
+// Generates UMA metric to track the duration of tab switching from when the
+// active tab is changed until the frame presentation time. The metric will be
+// separated into two whether the tab switch has saved frames or not.
+class CONTENT_EXPORT TabSwitchTimeRecorder {
+ public:
+  TabSwitchTimeRecorder();
+  ~TabSwitchTimeRecorder();
+
+  // Begin recording time, ends when DidPresentFrame is called. Returns a
+  // matching callback to end the time recording that will call DidPresentFrame.
+  base::OnceCallback<void(const gfx::PresentationFeedback&)> BeginTimeRecording(
+      const base::TimeTicks tab_switch_start_time,
+      bool has_saved_frames,
+      const base::TimeTicks render_widget_visibility_request_timestamp =
+          base::TimeTicks());
+
+ private:
+  // End the time recording, and upload the result to histogram if it has a
+  // correct matching BeginTimeRecording preceding this call.
+  void DidPresentFrame(
+      bool has_saved_frame,
+      base::TimeTicks tab_switch_start_time,
+      base::TimeTicks render_widget_visibility_request_timestamp,
+      const gfx::PresentationFeedback& feedback);
+
+  base::WeakPtr<TabSwitchTimeRecorder> GetWeakPtr() {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
+  base::WeakPtrFactory<TabSwitchTimeRecorder> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabSwitchTimeRecorder);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_TAB_SWITCH_TIME_RECORDER_H_
diff --git a/content/common/tab_switch_time_recorder_unittest.cc b/content/common/tab_switch_time_recorder_unittest.cc
new file mode 100644
index 0000000..8f03eba
--- /dev/null
+++ b/content/common/tab_switch_time_recorder_unittest.cc
@@ -0,0 +1,104 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <utility>
+
+#include "base/test/metrics/histogram_tester.h"
+#include "content/common/tab_switch_time_recorder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/presentation_feedback.h"
+
+namespace content {
+
+class TabSwitchTimeRecorderTest : public testing::Test {
+ public:
+  ~TabSwitchTimeRecorderTest() override {}
+
+  void SetUp() override {
+    EXPECT_EQ(
+        histogram_tester
+            .GetAllSamples("Browser.Tabs.TotalSwitchDuration.WithSavedFrames")
+            .size(),
+        0ULL);
+    EXPECT_EQ(
+        histogram_tester
+            .GetAllSamples("Browser.Tabs.TotalSwitchDuration.NoSavedFrames")
+            .size(),
+        0ULL);
+  }
+
+ protected:
+  size_t GetHistogramSampleSize(bool has_saved_frames) {
+    if (has_saved_frames) {
+      return histogram_tester
+          .GetAllSamples("Browser.Tabs.TotalSwitchDuration.WithSavedFrames")
+          .size();
+    } else {
+      return histogram_tester
+          .GetAllSamples("Browser.Tabs.TotalSwitchDuration.NoSavedFrames")
+          .size();
+    }
+  }
+
+  TabSwitchTimeRecorder tab_switch_time_recorder_;
+  base::HistogramTester histogram_tester;
+};
+
+// Time is properly recorded to histogram when we have saved frames and if we
+// have a proper matching BeginTimeRecording and callback execution.
+TEST_F(TabSwitchTimeRecorderTest, TimeIsRecordedWithSavedFrames) {
+  const auto start = base::TimeTicks::Now();
+  auto callback = tab_switch_time_recorder_.BeginTimeRecording(
+      start, true /* has_saved_frames */);
+  const auto end = base::TimeTicks::Now();
+  auto presentation_feedback = gfx::PresentationFeedback(
+      end, end - start, gfx::PresentationFeedback::Flags::kHWCompletion);
+  std::move(callback).Run(presentation_feedback);
+  EXPECT_EQ(GetHistogramSampleSize(true /* has_saved_frames */), 1ULL);
+  EXPECT_EQ(GetHistogramSampleSize(false /* has_saved_frames */), 0ULL);
+}
+
+// Time is properly recorded to histogram when we have no saved frame and if we
+// have a proper matching BeginTimeRecording and callback execution.
+TEST_F(TabSwitchTimeRecorderTest, TimeIsRecordedNoSavedFrame) {
+  const auto start = base::TimeTicks::Now();
+  auto callback = tab_switch_time_recorder_.BeginTimeRecording(
+      start, false /* has_saved_frames */);
+  const auto end = base::TimeTicks::Now();
+  auto presentation_feedback = gfx::PresentationFeedback(
+      end, end - start, gfx::PresentationFeedback::Flags::kHWCompletion);
+  std::move(callback).Run(presentation_feedback);
+  EXPECT_EQ(GetHistogramSampleSize(true /* has_saved_frames */), 0ULL);
+  EXPECT_EQ(GetHistogramSampleSize(false /* has_saved_frames */), 1ULL);
+}
+
+// Two consecutive calls to BeginTimeRecording will invalidate the first
+// returned callback.
+TEST_F(TabSwitchTimeRecorderTest, InvalidateCallback) {
+  const auto start1 = base::TimeTicks::Now();
+  auto callback1 = tab_switch_time_recorder_.BeginTimeRecording(
+      start1, false /* has_saved_frames */);
+
+  const auto start2 = base::TimeTicks::Now();
+  auto callback2 = tab_switch_time_recorder_.BeginTimeRecording(
+      start2, false /* has_saved_frames */);
+
+  // callback1 should be invalid. Running it should not upload anything to
+  // histogram.
+  const auto end = base::TimeTicks::Now();
+  auto presentation_feedback1 = gfx::PresentationFeedback(
+      end, end - start1, gfx::PresentationFeedback::Flags::kHWCompletion);
+  std::move(callback1).Run(presentation_feedback1);
+  EXPECT_EQ(GetHistogramSampleSize(true /* has_saved_frames */), 0ULL);
+  EXPECT_EQ(GetHistogramSampleSize(false /* has_saved_frames */), 0ULL);
+
+  // callback2 should still be valid.
+  auto presentation_feedback2 = gfx::PresentationFeedback(
+      end, end - start2, gfx::PresentationFeedback::Flags::kHWCompletion);
+  std::move(callback2).Run(presentation_feedback2);
+  EXPECT_EQ(GetHistogramSampleSize(true /* has_saved_frames */), 0ULL);
+  EXPECT_EQ(GetHistogramSampleSize(false /* has_saved_frames */), 1ULL);
+}
+
+}  // namespace content
diff --git a/content/common/tab_switching_time_callback.cc b/content/common/tab_switching_time_callback.cc
deleted file mode 100644
index b15c4950..0000000
--- a/content/common/tab_switching_time_callback.cc
+++ /dev/null
@@ -1,32 +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/tab_switching_time_callback.h"
-
-#include "base/bind.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/trace_event/trace_event.h"
-#include "ui/gfx/presentation_feedback.h"
-
-namespace content {
-
-base::OnceCallback<void(const gfx::PresentationFeedback&)>
-CreateTabSwitchingTimeRecorder(base::TimeTicks request_time) {
-  static uint32_t trace_id = 0;
-  TRACE_EVENT_ASYNC_BEGIN0("latency", "TabSwitching::Latency",
-                           TRACE_ID_LOCAL(trace_id));
-  return base::BindOnce(
-      [](base::TimeTicks request_timestamp, uint32_t trace_id,
-         const gfx::PresentationFeedback& feedback) {
-        const auto delta = feedback.timestamp - request_timestamp;
-        UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration", delta);
-        TRACE_EVENT_ASYNC_END1("latency", "TabSwitching::Latency",
-                               TRACE_ID_LOCAL(trace_id), "latency",
-                               delta.InMillisecondsF());
-      },
-      request_time, trace_id);
-  ++trace_id;
-}
-
-}  // namespace content
diff --git a/content/common/tab_switching_time_callback.h b/content/common/tab_switching_time_callback.h
deleted file mode 100644
index 913e5cb..0000000
--- a/content/common/tab_switching_time_callback.h
+++ /dev/null
@@ -1,22 +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_TAB_SWITCHING_TIME_CALLBACK_H_
-#define CONTENT_COMMON_TAB_SWITCHING_TIME_CALLBACK_H_
-
-#include "base/callback_forward.h"
-#include "base/time/time.h"
-
-namespace gfx {
-struct PresentationFeedback;
-}
-
-namespace content {
-
-base::OnceCallback<void(const gfx::PresentationFeedback&)>
-CreateTabSwitchingTimeRecorder(base::TimeTicks request_time);
-
-}  // namespace content
-
-#endif  // CONTENT_COMMON_TAB_SWITCHING_TIME_CALLBACK_H_
diff --git a/content/common/throttling_url_loader_unittest.cc b/content/common/throttling_url_loader_unittest.cc
index f8507ff..3a589e4 100644
--- a/content/common/throttling_url_loader_unittest.cc
+++ b/content/common/throttling_url_loader_unittest.cc
@@ -503,6 +503,40 @@
   EXPECT_EQ(1u, throttle_->will_redirect_request_called());
 }
 
+// Regression test for crbug.com/933538
+TEST_F(ThrottlingURLLoaderTest, ModifyURLAndDeferRedirect) {
+  throttle_->set_modify_url_in_will_start(GURL("http://example.org/foo"));
+  throttle_->set_will_start_request_callback(
+      base::BindRepeating([](URLLoaderThrottle::Delegate* /* delegate */,
+                             bool* defer) { *defer = true; }));
+  throttle_->set_will_redirect_request_callback(base::BindRepeating(
+      [](URLLoaderThrottle::Delegate* /* delegate */, bool* defer,
+         std::vector<std::string>* /* removed_headers */,
+         net::HttpRequestHeaders* /* modified_headers */) { *defer = true; }));
+
+  CreateLoaderAndStart();
+
+  EXPECT_EQ(1u, throttle_->will_start_request_called());
+  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
+
+  throttle_->delegate()->Resume();
+
+  EXPECT_EQ(1u, throttle_->will_start_request_called());
+  EXPECT_EQ(1u, throttle_->will_redirect_request_called());
+  EXPECT_EQ(0u, client_.on_received_redirect_called());
+
+  throttle_->delegate()->Resume();
+
+  EXPECT_EQ(1u, throttle_->will_start_request_called());
+  EXPECT_EQ(1u, throttle_->will_redirect_request_called());
+  EXPECT_EQ(0u, throttle_->before_will_process_response_called());
+  EXPECT_EQ(0u, throttle_->will_process_response_called());
+  EXPECT_EQ(0u, factory_.create_loader_and_start_called());
+  EXPECT_EQ(0u, client_.on_received_response_called());
+  EXPECT_EQ(1u, client_.on_received_redirect_called());
+  EXPECT_EQ(0u, client_.on_complete_called());
+}
+
 TEST_F(ThrottlingURLLoaderTest, CancelBeforeRedirect) {
   throttle_->set_will_redirect_request_callback(base::BindRepeating(
       [](URLLoaderThrottle::Delegate* delegate, bool* /* defer */,
diff --git a/content/common/widget_messages.h b/content/common/widget_messages.h
index 8895b6f..84f6662a 100644
--- a/content/common/widget_messages.h
+++ b/content/common/widget_messages.h
@@ -156,9 +156,10 @@
 IPC_MESSAGE_ROUTED0(WidgetMsg_WasHidden)
 
 // Tells the render view that it is no longer hidden (see WasHidden).
-IPC_MESSAGE_ROUTED2(WidgetMsg_WasShown,
+IPC_MESSAGE_ROUTED3(WidgetMsg_WasShown,
                     base::TimeTicks /* show_request_timestamp */,
-                    bool /* was_evicted */)
+                    bool /* was_evicted */,
+                    base::TimeTicks /* tab_switch_start_time */)
 
 // Activate/deactivate the RenderWidget (i.e., set its controls' tint
 // accordingly, etc.).
diff --git a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java
index af36aed..1ec506c 100644
--- a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java
@@ -5,7 +5,6 @@
 package org.chromium.content.browser;
 
 import android.content.Context;
-import android.os.Handler;
 import android.os.StrictMode;
 import android.support.annotation.IntDef;
 
@@ -373,7 +372,7 @@
     // Queue the callbacks to run. Since running the callbacks clears the list it is safe to call
     // this more than once.
     private void enqueueCallbackExecution(final int startupFailure) {
-        new Handler().post(new Runnable() {
+        PostTask.postTask(UiThreadTaskTraits.BOOTSTRAP, new Runnable() {
             @Override
             public void run() {
                 executeEnqueuedCallbacks(startupFailure);
@@ -382,7 +381,7 @@
     }
 
     private void postStartupCompleted(final StartupCallback callback) {
-        new Handler().post(new Runnable() {
+        PostTask.postTask(UiThreadTaskTraits.BOOTSTRAP, new Runnable() {
             @Override
             public void run() {
                 if (mStartupSuccess) {
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 48d7499..2f68bc4e 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -975,4 +975,11 @@
   return BrowserAccessibilityState::GetInstance()->GetAccessibilityMode();
 }
 
+#if defined(OS_ANDROID)
+ContentBrowserClient::WideColorGamutHeuristic
+ContentBrowserClient::GetWideColorGamutHeuristic() const {
+  return WideColorGamutHeuristic::kNone;
+}
+#endif
+
 }  // namespace content
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index a657403..81583161 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -1529,6 +1529,18 @@
   // Returns the default accessibility mode for the given browser context.
   virtual ui::AXMode GetAXModeForBrowserContext(
       BrowserContext* browser_context);
+
+#if defined(OS_ANDROID)
+  // Defines the heuristics we can use to enable wide color gamut (WCG).
+  enum class WideColorGamutHeuristic {
+    kUseDisplay,  // Use WCG if display supports it.
+    kUseWindow,   // Use WCG if window is WCG.
+    kNone,        // Never use WCG.
+  };
+
+  // Returns kNone by default.
+  virtual WideColorGamutHeuristic GetWideColorGamutHeuristic() const;
+#endif
 };
 
 }  // namespace content
diff --git a/content/public/browser/render_widget_host_view.h b/content/public/browser/render_widget_host_view.h
index d02f832..300222fd 100644
--- a/content/public/browser/render_widget_host_view.h
+++ b/content/public/browser/render_widget_host_view.h
@@ -260,6 +260,10 @@
   // Indicates that this view should show the contents of |view| if it doesn't
   // have anything to show.
   virtual void TakeFallbackContentFrom(RenderWidgetHostView* view) = 0;
+
+  // Set the last time a tab change starts to be processed for this
+  // RenderWidgetHostView. Will overwrite any previously stored value.
+  virtual void SetLastTabChangeStartTime(base::TimeTicks start_time) = 0;
 };
 
 }  // namespace content
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 17465e8..13f529dd 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -5,10 +5,6 @@
 #include "content/public/common/content_features.h"
 #include "build/build_config.h"
 
-#if defined(OS_CHROMEOS)
-#include "media/capture/video/chromeos/public/cros_features.h"
-#endif
-
 namespace features {
 
 // All features in alphabetical order.
@@ -772,12 +768,11 @@
   if (!ShouldEnableVideoCaptureService())
     return VideoCaptureServiceConfiguration::kDisabled;
 
-#if defined(OS_ANDROID)
+// On ChromeOS the service must run in the browser process, because parts of the
+// code depend on global objects that are only available in the Browser process.
+// See https://crbug.com/891961.
+#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
   return VideoCaptureServiceConfiguration::kEnabledForBrowserProcess;
-#elif defined(OS_CHROMEOS)
-  return media::ShouldUseCrosCameraService()
-             ? VideoCaptureServiceConfiguration::kEnabledForBrowserProcess
-             : VideoCaptureServiceConfiguration::kEnabledForOutOfProcess;
 #else
   return base::FeatureList::IsEnabled(
              features::kRunVideoCaptureServiceInBrowserProcess)
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index a6e748b..6f34b5b 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -220,6 +220,12 @@
 // the use of persistent gpu memory buffers.
 const char kDisablePartialRaster[] = "disable-partial-raster";
 
+// Internally (in devtools_session.cc) switches the protocol to binary format
+// (CBOR). This setting is temporary; we plan to remove it after transition to
+// binary is sufficiently complete (2019-04-01).
+const char kEnableInternalDevToolsBinaryProtocol[] =
+    "enable-internal-devtools-binary-protocol";
+
 // Enable partial raster in the renderer.
 const char kEnablePartialRaster[] = "enable-partial-raster";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index b298c312..69ad632 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -75,6 +75,7 @@
 CONTENT_EXPORT extern const char kDisableNotifications[];
 CONTENT_EXPORT extern const char kDisableOriginTrialControlledBlinkFeatures[];
 CONTENT_EXPORT extern const char kDisablePartialRaster[];
+CONTENT_EXPORT extern const char kEnableInternalDevToolsBinaryProtocol[];
 CONTENT_EXPORT extern const char kEnablePartialRaster[];
 extern const char kDisablePepper3d[];
 CONTENT_EXPORT extern const char kDisablePepper3DImageChromium[];
diff --git a/content/public/common/origin_util.h b/content/public/common/origin_util.h
index bb4a389a..8f2a8a3 100644
--- a/content/public/common/origin_util.h
+++ b/content/public/common/origin_util.h
@@ -21,6 +21,9 @@
 // Note that this is not equivalent to checking if an entire site is secure
 // (i.e. no degraded security state UI is displayed to the user), since there
 // may be insecure iframes present even if this method returns true.
+//
+// TODO(lukasza): Remove this function and use
+// network::IsUrlPotentiallyTrustworthy instead.
 bool CONTENT_EXPORT IsOriginSecure(const GURL& url);
 
 // Returns true if the origin can register a service worker.  Scheme must be
@@ -29,6 +32,9 @@
 
 // This is based on SecurityOrigin::isPotentiallyTrustworthy and tries to mimic
 // its behavior.
+//
+// TODO(lukasza): Remove this function and use
+// network::IsOriginPotentiallyTrustworthy instead.
 bool CONTENT_EXPORT IsPotentiallyTrustworthyOrigin(const url::Origin& origin);
 
 }  // namespace content
diff --git a/content/public/test/web_test_support.h b/content/public/test/web_test_support.h
index 282725e7..0d76b43e 100644
--- a/content/public/test/web_test_support.h
+++ b/content/public/test/web_test_support.h
@@ -56,11 +56,6 @@
 // Turn a renderer into web test mode.
 void EnableRendererWebTestMode();
 
-// "Casts" |render_view| to |WebViewTestProxy|.  Caller has to ensure that
-// prior to construction of |render_view|, EnableWebTestProxyCreation was
-// called.
-test_runner::WebViewTestProxy* GetWebViewTestProxy(RenderView* render_view);
-
 // Gets WebWidgetTestProxy associated with |frame| (either the view's widget
 // or the local root's frame widget).  Caller has to ensure that prior to
 // construction of |render_frame|, EnableWebTestProxyCreation was called.
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 1741f151..18749bd4 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -6038,48 +6038,11 @@
   DCHECK(!(was_within_same_document && interface_params));
   UpdateStateForCommit(item, commit_type, transition);
 
-  auto params = MakeDidCommitProvisionalLoadParams(commit_type, transition);
-
-  // If this is a regular commit, not an error page, the URL that was just
-  // committed must match the process lock, if there is one. Verify it here, to
-  // get a stack trace for a bug where this seems to be occurring.
-  // TODO(nasko): Remove this check after we've gathered enough information to
-  // debug issues with browser-side security checks. https://crbug.com/931895.
-  RenderThreadImpl* render_thread = RenderThreadImpl::current();
-  const GURL* lock_url =
-      render_thread ? render_thread->site_lock_url() : nullptr;
-  if (frame_->GetDocumentLoader()->ErrorCode() != net::ERR_BLOCKED_BY_CLIENT &&
-      lock_url && lock_url->scheme() == params->url.scheme() &&
-      lock_url->SchemeIsHTTPOrHTTPS()) {
-    std::string lock_domain =
-        net::registry_controlled_domains::GetDomainAndRegistry(
-            lock_url->host(),
-            net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
-    std::string commit_domain =
-        net::registry_controlled_domains::GetDomainAndRegistry(
-            params->url.host(),
-            net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
-    if (lock_domain != commit_domain) {
-      base::debug::SetCrashKeyString(
-          base::debug::AllocateCrashKeyString(
-              "lock_domain", base::debug::CrashKeySize::Size64),
-          lock_domain);
-      base::debug::SetCrashKeyString(
-          base::debug::AllocateCrashKeyString(
-              "commit_domain", base::debug::CrashKeySize::Size64),
-          commit_domain);
-      base::debug::SetCrashKeyString(
-          base::debug::AllocateCrashKeyString(
-              "is_subframe", base::debug::CrashKeySize::Size32),
-          is_main_frame_ ? "true" : "false");
-      CHECK(false);
-    }
-  }
-
   // This invocation must precede any calls to allowScripts(), allowImages(), or
   // allowPlugins() for the new page. This ensures that when these functions
   // send ViewHostMsg_ContentBlocked messages, those arrive after the browser
   // process has already been informed of the provisional load committing.
+  auto params = MakeDidCommitProvisionalLoadParams(commit_type, transition);
   if (was_within_same_document) {
     GetFrameHost()->DidCommitSameDocumentNavigation(std::move(params));
   } else {
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc
index 70ad855..a4bb697 100644
--- a/content/renderer/render_frame_impl_browsertest.cc
+++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -228,8 +228,9 @@
 TEST_F(RenderFrameImplTest, FrameWasShown) {
   RenderFrameTestObserver observer(frame());
 
-  WidgetMsg_WasShown was_shown_message(0, base::TimeTicks(),
-                                       false /* was_evicted */);
+  WidgetMsg_WasShown was_shown_message(
+      0, base::TimeTicks(), false /* was_evicted */,
+      base::TimeTicks() /* tab_switch_start_time */);
   frame_widget()->OnMessageReceived(was_shown_message);
 
   EXPECT_FALSE(frame_widget()->is_hidden());
@@ -266,8 +267,9 @@
 
   RenderFrameTestObserver observer(grandchild);
 
-  WidgetMsg_WasShown was_shown_message(0, base::TimeTicks(),
-                                       false /* was_evicted */);
+  WidgetMsg_WasShown was_shown_message(
+      0, base::TimeTicks(), false /* was_evicted */,
+      base::TimeTicks() /* tab_switch_start_time */);
   frame_widget()->OnMessageReceived(was_shown_message);
 
   EXPECT_FALSE(frame_widget()->is_hidden());
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index c33da733..c899a26 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1711,10 +1711,9 @@
       base::TimeDelta::FromMinutes(90));
 }
 
-void RenderThreadImpl::SetIsLockedToSite(const GURL& lock_url) {
+void RenderThreadImpl::SetIsLockedToSite() {
   DCHECK(blink_platform_impl_);
   blink_platform_impl_->SetIsLockedToSite();
-  site_lock_url_ = std::make_unique<GURL>(lock_url);
 }
 
 void RenderThreadImpl::EnableV8LowMemoryMode() {
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 11d7639..afa96183 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -494,10 +494,6 @@
     video_frame_compositor_task_runner_ = task_runner;
   }
 
-  // TODO(nasko): Remove after we've gathered enough information to debug issues
-  // with browser-side security checks. https://crbug.com/931895.
-  const GURL* site_lock_url() { return site_lock_url_.get(); }
-
  private:
   friend class RenderThreadImplBrowserTest;
 
@@ -555,7 +551,7 @@
   void SetProcessState(mojom::RenderProcessState process_state) override;
   void SetSchedulerKeepActive(bool keep_active) override;
   void ProcessPurgeAndSuspend() override;
-  void SetIsLockedToSite(const GURL& lock_url) override;
+  void SetIsLockedToSite() override;
   void EnableV8LowMemoryMode() override;
 
   void OnMemoryPressure(
@@ -756,11 +752,6 @@
   mojo::Binding<viz::mojom::CompositingModeWatcher>
       compositing_mode_watcher_binding_;
 
-  // TODO(nasko): Temporary diagnostic member, holding the site URL this process
-  // is locked to. Remove after we've gathered enough information to
-  // debug issues with browser-side security checks. https://crbug.com/931895.
-  std::unique_ptr<GURL> site_lock_url_;
-
   base::WeakPtrFactory<RenderThreadImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderThreadImpl);
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index ca5e59c..7b063b1 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1080,10 +1080,6 @@
   return frame_widget_;
 }
 
-blink::WebWidgetClient* RenderViewImpl::GetWebWidgetClientForWidget() {
-  return WidgetClient();
-}
-
 bool RenderViewImpl::RenderWidgetWillHandleMouseEventForWidget(
     const blink::WebMouseEvent& event) {
   // If the mouse is locked, only the current owner of the mouse lock can
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 4b18b2f..9e388f03 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -395,7 +395,6 @@
   // RenderWidgetDelegate implementation ----------------------------------
 
   blink::WebWidget* GetWebWidgetForWidget() const override;
-  blink::WebWidgetClient* GetWebWidgetClientForWidget() override;
   bool RenderWidgetWillHandleMouseEventForWidget(
       const blink::WebMouseEvent& event) override;
   void SetActiveForWidget(bool active) override;
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index fe8a598..0f18c93 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -43,7 +43,6 @@
 #include "content/common/render_frame_metadata.mojom.h"
 #include "content/common/render_message_filter.mojom.h"
 #include "content/common/swapped_out_messages.h"
-#include "content/common/tab_switching_time_callback.h"
 #include "content/common/text_input_state.h"
 #include "content/common/widget_messages.h"
 #include "content/public/common/content_client.h"
@@ -939,7 +938,8 @@
 }
 
 void RenderWidget::OnWasShown(base::TimeTicks show_request_timestamp,
-                              bool was_evicted) {
+                              bool was_evicted,
+                              base::TimeTicks tab_switch_start_time) {
   // A frozen main frame widget does not become shown, since it has no frame
   // associated with it. It must be thawed before changing visibility.
   DCHECK(!is_frozen_);
@@ -952,7 +952,9 @@
   SetHidden(false);
   if (!show_request_timestamp.is_null()) {
     layer_tree_view_->layer_tree_host()->RequestPresentationTimeForNextFrame(
-        CreateTabSwitchingTimeRecorder(show_request_timestamp));
+        tab_switch_time_recorder_.BeginTimeRecording(
+            tab_switch_start_time, false /* has_saved_frames */,
+            show_request_timestamp));
   }
 
   for (auto& observer : render_frames_)
@@ -1007,11 +1009,7 @@
 }
 
 void RenderWidget::SetNeedsMainFrame() {
-  // The WebWidgetClient is not |this| if tests override it for the WebView and
-  // WebViewClient.
-  blink::WebWidgetClient* client =
-      delegate() ? delegate()->GetWebWidgetClientForWidget() : this;
-  client->ScheduleAnimation();
+  ScheduleAnimation();
 }
 
 scoped_refptr<MainThreadEventQueue> RenderWidget::GetInputEventQueue() {
@@ -1219,8 +1217,8 @@
     CHECK(!for_child_local_root_frame_ && !delegate_);
   }
   // This call is not needed in single thread mode for tests without a
-  // scheduler, but they need to override the WebWidgetClient and replace this
-  // method in order to schedule a synchronous composite task themselves.
+  // scheduler, but they override this method in order to schedule a synchronous
+  // composite task themselves.
   layer_tree_view_->SetNeedsBeginFrame();
 }
 
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 8d55faf..d79f871 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -34,6 +34,7 @@
 #include "content/common/cursors/webcursor.h"
 #include "content/common/drag_event_source_info.h"
 #include "content/common/edit_command.h"
+#include "content/common/tab_switch_time_recorder.h"
 #include "content/common/widget.mojom.h"
 #include "content/public/common/drop_data.h"
 #include "content/public/common/screen_info.h"
@@ -705,7 +706,9 @@
   void OnEnableDeviceEmulation(const blink::WebDeviceEmulationParams& params);
   void OnDisableDeviceEmulation();
   void OnWasHidden();
-  void OnWasShown(base::TimeTicks show_request_timestamp, bool was_evicted);
+  void OnWasShown(base::TimeTicks show_request_timestamp,
+                  bool was_evicted,
+                  base::TimeTicks tab_switch_start_time);
   void OnCreateVideoAck(int32_t video_id);
   void OnUpdateVideoAck(int32_t video_id);
   void OnRequestSetBoundsAck();
@@ -1093,6 +1096,9 @@
   bool first_update_visual_state_after_hidden_;
   base::TimeTicks was_shown_time_;
 
+  // Object to record tab switch time into this RenderWidget
+  TabSwitchTimeRecorder tab_switch_time_recorder_;
+
   // Whether or not Blink's viewport size should be shrunk by the height of the
   // URL-bar.
   bool browser_controls_shrink_blink_size_ = false;
diff --git a/content/renderer/render_widget_delegate.h b/content/renderer/render_widget_delegate.h
index 12293e9..9e70d3e2 100644
--- a/content/renderer/render_widget_delegate.h
+++ b/content/renderer/render_widget_delegate.h
@@ -29,10 +29,6 @@
   // and RenderWidget will fall back to its own WebWidget.
   virtual blink::WebWidget* GetWebWidgetForWidget() const = 0;
 
-  // Returns the WebWidgetClient being provided from the delegate. Usually this
-  // is the RenderWidget itself, but tests can override and change it.
-  virtual blink::WebWidgetClient* GetWebWidgetClientForWidget() = 0;
-
   // As in RenderWidgetInputHandlerDelegate. Return true if the event was
   // handled.
   virtual bool RenderWidgetWillHandleMouseEventForWidget(
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc
index 16be558..d0008a82 100644
--- a/content/renderer/render_widget_unittest.cc
+++ b/content/renderer/render_widget_unittest.cc
@@ -518,9 +518,6 @@
 class StubRenderWidgetDelegate : public RenderWidgetDelegate {
  public:
   blink::WebWidget* GetWebWidgetForWidget() const override { return nullptr; }
-  blink::WebWidgetClient* GetWebWidgetClientForWidget() override {
-    return nullptr;
-  }
   bool RenderWidgetWillHandleMouseEventForWidget(
       const blink::WebMouseEvent& event) override {
     return false;
diff --git a/content/shell/renderer/web_test/web_test_content_renderer_client.cc b/content/shell/renderer/web_test/web_test_content_renderer_client.cc
index 3d2b7ee..ee210da 100644
--- a/content/shell/renderer/web_test/web_test_content_renderer_client.cc
+++ b/content/shell/renderer/web_test/web_test_content_renderer_client.cc
@@ -30,7 +30,6 @@
 #include "content/shell/test_runner/web_frame_test_proxy.h"
 #include "content/shell/test_runner/web_test_interfaces.h"
 #include "content/shell/test_runner/web_test_runner.h"
-#include "content/shell/test_runner/web_view_test_proxy.h"
 #include "media/base/audio_latency.h"
 #include "media/base/mime_util.h"
 #include "media/media_buildflags.h"
@@ -77,12 +76,6 @@
 void WebTestContentRendererClient::RenderViewCreated(RenderView* render_view) {
   new ShellRenderViewObserver(render_view);
 
-  // TODO(https://crbug.com/545684): Does this function need to exist? Can
-  // this all just be in the CreateWebViewTestProxy() or does
-  // RenderViewCreated() get manually invoked by the test runner?
-  test_runner::WebViewTestProxy* proxy = GetWebViewTestProxy(render_view);
-  proxy->Reset();
-
   BlinkTestRunner* test_runner = BlinkTestRunner::Get(render_view);
   test_runner->Reset(false /* for_new_test */);
 }
diff --git a/content/shell/test_runner/web_test_delegate.h b/content/shell/test_runner/web_test_delegate.h
index 8b9a30b..7eb368e 100644
--- a/content/shell/test_runner/web_test_delegate.h
+++ b/content/shell/test_runner/web_test_delegate.h
@@ -43,6 +43,8 @@
 
 class WebTestDelegate {
  public:
+  virtual ~WebTestDelegate() = default;
+
   // Set and clear the edit command to execute on the next call to
   // WebViewClient::handleCurrentKeyboardEvent().
   virtual void ClearEditCommand() = 0;
@@ -253,9 +255,6 @@
   // Forces a text input state update for the client of WebFrameWidget
   // associated with |frame|.
   virtual void ForceTextInputStateUpdate(blink::WebLocalFrame* frame) = 0;
-
- protected:
-  virtual ~WebTestDelegate() {}
 };
 
 }  // namespace test_runner
diff --git a/content/shell/test_runner/web_view_test_proxy.cc b/content/shell/test_runner/web_view_test_proxy.cc
index 3039b3b..2c3eefc0 100644
--- a/content/shell/test_runner/web_view_test_proxy.cc
+++ b/content/shell/test_runner/web_view_test_proxy.cc
@@ -24,8 +24,8 @@
 namespace test_runner {
 
 void WebViewTestProxy::Initialize(WebTestInterfaces* interfaces,
-                                  WebTestDelegate* delegate) {
-  delegate_ = delegate;
+                                  std::unique_ptr<WebTestDelegate> delegate) {
+  delegate_ = std::move(delegate);
   test_interfaces_ = interfaces->GetTestInterfaces();
   test_interfaces()->WindowOpened(this);
 }
@@ -112,10 +112,8 @@
 
 WebViewTestProxy::~WebViewTestProxy() {
   test_interfaces_->WindowClosed(this);
-  if (test_interfaces_->GetDelegate() == delegate_)
+  if (test_interfaces_->GetDelegate() == delegate_.get())
     test_interfaces_->SetDelegate(nullptr);
-  // TODO(https://crbug.com/545684): This delegate seems unnecessarily leaked.
-  // Make |delegate_| a std::unique_ptr<>?
 }
 
 TestRunner* WebViewTestProxy::GetTestRunner() {
diff --git a/content/shell/test_runner/web_view_test_proxy.h b/content/shell/test_runner/web_view_test_proxy.h
index b56bd9c..5ddf1a3 100644
--- a/content/shell/test_runner/web_view_test_proxy.h
+++ b/content/shell/test_runner/web_view_test_proxy.h
@@ -67,7 +67,8 @@
   template <typename... Args>
   explicit WebViewTestProxy(Args&&... args)
       : RenderViewImpl(std::forward<Args>(args)...) {}
-  void Initialize(WebTestInterfaces* interfaces, WebTestDelegate* delegate);
+  void Initialize(WebTestInterfaces* interfaces,
+                  std::unique_ptr<WebTestDelegate> delegate);
 
   // WebViewClient implementation.
   blink::WebView* CreateView(blink::WebLocalFrame* creator,
@@ -88,7 +89,7 @@
   // Exposed for our TestRunner harness.
   using RenderViewImpl::ApplyPageHidden;
 
-  WebTestDelegate* delegate() { return delegate_; }
+  WebTestDelegate* delegate() { return delegate_.get(); }
   TestInterfaces* test_interfaces() { return test_interfaces_; }
   AccessibilityController* accessibility_controller() {
     return &accessibility_controller_;
@@ -107,7 +108,7 @@
   TestRunner* GetTestRunner();
 
   TestInterfaces* test_interfaces_ = nullptr;
-  WebTestDelegate* delegate_ = nullptr;
+  std::unique_ptr<WebTestDelegate> delegate_;
 
   AccessibilityController accessibility_controller_{this};
   TextInputController text_input_controller_{this};
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 659dd0c..2380506 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1744,6 +1744,7 @@
     "../common/service_manager/service_manager_connection_impl_unittest.cc",
     "../common/service_worker/service_worker_types_unittest.cc",
     "../common/service_worker/service_worker_utils_unittest.cc",
+    "../common/tab_switch_time_recorder_unittest.cc",
     "../common/throttling_url_loader_unittest.cc",
     "../common/unique_name_helper_unittest.cc",
     "../common/webplugininfo_unittest.cc",
@@ -1921,6 +1922,7 @@
     "//content/browser/background_fetch:background_fetch_proto",
     "//content/browser/cache_storage:cache_storage_proto",
     "//content/browser/devtools:devtools_background_services_proto",
+    "//content/browser/devtools:inspector_protocol_encoding_test",
     "//content/browser/dom_storage:local_storage_proto",
     "//content/browser/notifications:notification_proto",
     "//content/browser/service_worker:service_worker_proto",
diff --git a/content/test/data/indexeddb/simple_blob_read.html b/content/test/data/indexeddb/simple_blob_read.html
new file mode 100644
index 0000000..970600f
--- /dev/null
+++ b/content/test/data/indexeddb/simple_blob_read.html
@@ -0,0 +1,10 @@
+<html>
+  <head>
+    <title>IndexedDB simple blob reading test</title>
+    <script type="text/javascript" src="common.js"></script>
+    <script type="text/javascript" src="simple_blob_read.js"></script>
+  </head>
+  <body onLoad="test()">
+    <div id="status">Starting...</div>
+  </body>
+</html>
diff --git a/content/test/data/indexeddb/simple_blob_read.js b/content/test/data/indexeddb/simple_blob_read.js
new file mode 100644
index 0000000..e15eba5
--- /dev/null
+++ b/content/test/data/indexeddb/simple_blob_read.js
@@ -0,0 +1,68 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+const DB = 'db';
+const STORE = 'store';
+const DATA = 'blob value';
+run();
+
+function run() {
+  Object.assign(indexedDB.open(DB), {
+    unexpectedErrorCallback,
+    onupgradeneeded(e) {
+      debug("Created object store.");
+      e.target.result.createObjectStore(STORE, {
+        keyPath: 'id',
+      });
+    },
+    onsuccess(e) {
+      debug("Opened database.");
+      const idb = /** @type IDBDatabase */ e.target.result;
+      const op = idb
+        .transaction(STORE, 'readwrite')
+        .objectStore(STORE)
+        .put({
+          id: 'foo',
+          blob: new Blob([DATA]),
+        });
+      op.onerror = onerror;
+      op.onsuccess = () => {
+        debug("Wrote blob.");
+        idb.close();
+        setTimeout(verify);
+      }
+    },
+  });
+}
+
+function verify(e) {
+  debug("Reading blob.");
+  Object.assign(indexedDB.open(DB), {
+    onerror,
+    onsuccess(e) {
+      const idb = /** @type IDBDatabase */ e.target.result;
+      const op = idb
+        .transaction(STORE, 'readonly')
+        .objectStore(STORE)
+        .get('foo');
+      op.onerror = onerror;
+      op.onsuccess = async e => {
+        debug("Got blob.");
+        idb.close();
+        const entry = e.target.result;
+        if (!entry) {
+          fail('BAD: nothing was written');
+        } else {
+          const text = await (
+              await fetch(URL.createObjectURL(entry.blob))).text();
+          if (text === DATA) {
+            done();
+          } else {
+            fail(`BAD: written "${DATA}", got "${text}"`)
+          }
+        }
+      }
+    },
+  });
+}
\ No newline at end of file
diff --git a/content/test/data/media/image_capture_test.html b/content/test/data/media/image_capture_test.html
index 23cdff3..66e0e12 100644
--- a/content/test/data/media/image_capture_test.html
+++ b/content/test/data/media/image_capture_test.html
@@ -21,10 +21,8 @@
   navigator.mediaDevices.getUserMedia({"video" : CONSTRAINTS})
       .then(stream => {
         assertEquals('video', stream.getVideoTracks()[0].kind);
-        return new ImageCapture(stream.getVideoTracks()[0]);
-      })
-      .then(capturer => {
-        return capturer.getPhotoCapabilities();
+        let imageCapturer = new ImageCapture(stream.getVideoTracks()[0]);
+        return imageCapturer.getPhotoCapabilities();
       })
       .then(capabilities => {
         // There's nothing to check here since |capabilities| vary per device.
@@ -40,10 +38,8 @@
   navigator.mediaDevices.getUserMedia({"video" : CONSTRAINTS})
       .then(stream => {
         assertEquals('video', stream.getVideoTracks()[0].kind);
-        return new ImageCapture(stream.getVideoTracks()[0]);
-      })
-      .then(capturer => {
-        return capturer.getPhotoSettings();
+        let imageCapturer = new ImageCapture(stream.getVideoTracks()[0]);
+        return imageCapturer.getPhotoSettings();
       })
       .then(settings => {
         // There's nothing to check here since |settings| vary per device.
@@ -59,10 +55,8 @@
   navigator.mediaDevices.getUserMedia({"video" : CONSTRAINTS})
       .then(stream => {
         assertEquals('video', stream.getVideoTracks()[0].kind);
-        return new ImageCapture(stream.getVideoTracks()[0]);
-      })
-      .then(capturer => {
-        return capturer.takePhoto();
+        let imageCapturer = new ImageCapture(stream.getVideoTracks()[0]);
+        return imageCapturer.takePhoto();
       })
       .then(blob => {
         assertTrue(blob.type != undefined);
@@ -80,10 +74,8 @@
   navigator.mediaDevices.getUserMedia({"video" : CONSTRAINTS})
       .then(stream => {
         assertEquals('video', stream.getVideoTracks()[0].kind);
-        return new ImageCapture(stream.getVideoTracks()[0]);
-      })
-      .then(capturer => {
-        return capturer.takePhoto();
+        let imageCapturer = new ImageCapture(stream.getVideoTracks()[0]);
+        return imageCapturer.takePhoto();
       })
       .then(blob => {
         failTest('Expected promise to get rejected but it was fulfilled');
@@ -100,10 +92,8 @@
   navigator.mediaDevices.getUserMedia({"video" : CONSTRAINTS})
       .then(stream => {
         assertEquals('video', stream.getVideoTracks()[0].kind);
-        return new ImageCapture(stream.getVideoTracks()[0]);
-      })
-      .then(capturer => {
-        return capturer.grabFrame();
+        let imageCapturer = new ImageCapture(stream.getVideoTracks()[0]);
+        return imageCapturer.grabFrame();
       })
       .then(imageBitmap => {
         // On Android, depending on the device orientation, |imageBitmap| might
@@ -123,13 +113,10 @@
   navigator.mediaDevices.getUserMedia({"video" : CONSTRAINTS})
       .then(stream => {
         assertEquals('video', stream.getVideoTracks()[0].kind);
-        return new ImageCapture(stream.getVideoTracks()[0]);
-      })
-      .then(capturer => {
-        imageCapturer = capturer;
+        imageCapturer = new ImageCapture(stream.getVideoTracks()[0]);
         // TODO(mcasas): Before accesing synchronous track APIs we need a delay,
         // use instead a round trip of capabilities: https://crbug.com/711524.
-        return capturer.getPhotoCapabilities();
+        return imageCapturer.getPhotoCapabilities();
       })
       .then(capabilities => {
         imageCapturer.track.getCapabilities();
@@ -147,13 +134,10 @@
   navigator.mediaDevices.getUserMedia({"video" : CONSTRAINTS})
       .then(stream => {
         assertEquals('video', stream.getVideoTracks()[0].kind);
-        return new ImageCapture(stream.getVideoTracks()[0]);
-      })
-      .then(capturer => {
-        imageCapturer = capturer;
+        imageCapturer = new ImageCapture(stream.getVideoTracks()[0]);
         // TODO(mcasas): Before accesing synchronous track APIs we need a delay,
         // use instead a round trip of capabilities: https://crbug.com/711524.
-        return capturer.getPhotoCapabilities();
+        return imageCapturer.getPhotoCapabilities();
       })
       .then(capabilities => {
         imageCapturer.track.getSettings();
@@ -173,13 +157,10 @@
   navigator.mediaDevices.getUserMedia({"video" : CONSTRAINTS})
       .then(stream => {
         assertEquals('video', stream.getVideoTracks()[0].kind);
-        return new ImageCapture(stream.getVideoTracks()[0]);
-      })
-      .then(capturer => {
-        imageCapturer = capturer;
+        imageCapturer = new ImageCapture(stream.getVideoTracks()[0]);
         // TODO(mcasas): Before accesing synchronous track APIs we need a delay,
         // use instead a round trip of capabilities: https://crbug.com/711524.
-        return capturer.getPhotoCapabilities();
+        return imageCapturer.getPhotoCapabilities();
       })
       .then(capabilities => {
         const trackCapabilities = imageCapturer.track.getCapabilities();
@@ -217,13 +198,10 @@
     navigator.mediaDevices.getUserMedia({"video": CONSTRAINTS})
         .then(stream => {
             assertEquals('video', stream.getVideoTracks()[0].kind);
-            return new ImageCapture(stream.getVideoTracks()[0]);
-        })
-        .then(capturer => {
-            imageCapturer = capturer;
+            imageCapturer = new ImageCapture(stream.getVideoTracks()[0]);
             // TODO(mcasas): Before accesing synchronous track APIs we need a delay,
             // use instead a round trip of capabilities: https://crbug.com/711524.
-            return capturer.getPhotoCapabilities();
+            return imageCapturer.getPhotoCapabilities();
         })
         .then(capabilities => {
             const trackCapabilities = imageCapturer.track.getCapabilities();
@@ -279,13 +257,10 @@
     navigator.mediaDevices.getUserMedia({"video": CONSTRAINTS})
         .then(stream => {
             assertEquals('video', stream.getVideoTracks()[0].kind);
-            return new ImageCapture(stream.getVideoTracks()[0]);
-        })
-        .then(capturer => {
-            imageCapturer = capturer;
+            imageCapturer = new ImageCapture(stream.getVideoTracks()[0]);
             // TODO(mcasas): Before accesing synchronous track APIs we need a delay,
             // use instead a round trip of capabilities: https://crbug.com/711524.
-            return capturer.getPhotoCapabilities();
+            return imageCapturer.getPhotoCapabilities();
         })
         .then(capabilities => {
             const trackCapabilities = imageCapturer.track.getCapabilities();
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 4a757c5..80455c2 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -311,6 +311,19 @@
     self.Flaky('deqp/functional/gles3/textureformat/unsized_3d.html',
         ['win', 'intel', 'd3d11'], bug=614418)
 
+    # This is an OpenGL driver bug on Intel platform and it is fixed in
+    # Intel Driver 25.20.100.6444.
+    # Case no-over-optimization-on-uniform-array-09 always fail if run
+    # case biuDepthRange_001_to_002 first.
+    # Temporarily skip these two cases now because this issue blocks
+    # WEBGL_video_texture implementation.
+    self.Skip(
+        'conformance/ogles/GL/biuDepthRange/biuDepthRange_001_to_002.html',
+        ['win', 'intel', 'opengl', 'passthrough'], bug=907195)
+    self.Skip(
+        'conformance/uniforms/no-over-optimization-on-uniform-array-09.html',
+        ['win', 'intel', 'opengl', 'passthrough'], bug=907195)
+
     # It's unfortunate that these suppressions need to be so broad, but it
     # looks like the D3D11 device can be lost spontaneously on this
     # configuration while running basically any test.
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index 0f6bbda4..fb6e43f 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -259,6 +259,19 @@
     self.Fail('conformance/rendering/rendering-stencil-large-viewport.html',
         ['win', 'intel', 'd3d11'], bug=782317)
 
+    # This is an OpenGL driver bug on Intel platform and it is fixed in
+    # Intel Driver 25.20.100.6444.
+    # Case no-over-optimization-on-uniform-array-09 always fail if run
+    # case biuDepthRange_001_to_002 first.
+    # Temporarily skip these two cases now because this issue blocks
+    # WEBGL_video_texture implementation.
+    self.Skip(
+        'conformance/ogles/GL/biuDepthRange/biuDepthRange_001_to_002.html',
+        ['win', 'intel', 'opengl', 'passthrough'], bug=907195)
+    self.Skip(
+        'conformance/uniforms/no-over-optimization-on-uniform-array-09.html',
+        ['win', 'intel', 'opengl', 'passthrough'], bug=907195)
+
     # Win7 / Intel failures
     self.Fail('conformance/textures/misc/' +
               'copy-tex-image-and-sub-image-2d.html',
@@ -404,6 +417,11 @@
         ['win', 'passthrough', 'vulkan'], bug=2708) # ANGLE bug ID
     self.Fail('conformance/canvas/canvas-test.html',
         ['win', 'passthrough', 'vulkan'], bug=2929) # ANGLE bug ID
+    self.Fail('conformance/canvas/' +
+        'draw-static-webgl-to-multiple-canvas-test.html',
+        ['win', 'passthrough', 'vulkan'], bug=2918) # ANGLE bug ID
+    self.Fail('conformance/canvas/draw-webgl-to-canvas-test.html',
+        ['win', 'passthrough', 'vulkan'], bug=2918) # ANGLE bug ID
     self.Fail('conformance/context/' +
         'context-attribute-preserve-drawing-buffer.html',
         ['win', 'passthrough', 'vulkan'], bug=2913) # ANGLE bug ID
@@ -489,11 +507,6 @@
         ['win', 'passthrough', 'vulkan'], bug=3111) # ANGLE bug ID
 
     # Vulkan / Win / NVIDIA / Passthough command decoder
-    self.Fail('conformance/canvas/' +
-        'draw-static-webgl-to-multiple-canvas-test.html',
-        ['win', 'passthrough', 'vulkan', 'nvidia'], bug=2918) # ANGLE bug ID
-    self.Fail('conformance/canvas/draw-webgl-to-canvas-test.html',
-        ['win', 'passthrough', 'vulkan', 'nvidia'], bug=2918) # ANGLE bug ID
     self.Fail('conformance/canvas/to-data-url-test.html',
         ['win', 'passthrough', 'vulkan', 'nvidia'], bug=2918) # ANGLE bug ID
     self.Fail('conformance/context/premultiplyalpha-test.html',
diff --git a/content/test/web_test_support.cc b/content/test/web_test_support.cc
index bd92504..f0a0d6a3c 100644
--- a/content/test/web_test_support.cc
+++ b/content/test/web_test_support.cc
@@ -90,7 +90,7 @@
   auto* render_view_proxy =
       new test_runner::WebViewTestProxy(compositor_deps, params);
 
-  BlinkTestRunner* test_runner = new BlinkTestRunner(render_view_proxy);
+  auto test_runner = std::make_unique<BlinkTestRunner>(render_view_proxy);
   // TODO(lukasza): Using the 1st BlinkTestRunner as the main delegate is wrong,
   // but it is difficult to change because this behavior has been baked for a
   // long time into test assumptions (i.e. which PrintMessage gets delivered to
@@ -98,10 +98,10 @@
   static bool first_test_runner = true;
   if (first_test_runner) {
     first_test_runner = false;
-    interfaces->SetDelegate(test_runner);
+    interfaces->SetDelegate(test_runner.get());
   }
 
-  render_view_proxy->Initialize(interfaces, test_runner);
+  render_view_proxy->Initialize(interfaces, std::move(test_runner));
   return render_view_proxy;
 }
 
@@ -151,10 +151,6 @@
 
 }  // namespace
 
-test_runner::WebViewTestProxy* GetWebViewTestProxy(RenderView* render_view) {
-  return static_cast<test_runner::WebViewTestProxy*>(render_view);
-}
-
 test_runner::WebWidgetTestProxy* GetWebWidgetTestProxy(
     blink::WebLocalFrame* frame) {
   DCHECK(frame);
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index 17cf3299..b71a53f 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -563,6 +563,7 @@
     "api/declarative/deduping_factory_unittest.cc",
     "api/declarative/rules_registry_unittest.cc",
     "api/declarative_net_request/composite_matcher_unittest.cc",
+    "api/declarative_net_request/file_sequence_helper_unittest.cc",
     "api/declarative_net_request/flat_ruleset_indexer_unittest.cc",
     "api/declarative_net_request/indexed_rule_unittest.cc",
     "api/declarative_net_request/indexed_ruleset_format_version_unittest.cc",
diff --git a/extensions/browser/api/declarative_net_request/file_sequence_helper.cc b/extensions/browser/api/declarative_net_request/file_sequence_helper.cc
index 1dad27d9..60b00d6 100644
--- a/extensions/browser/api/declarative_net_request/file_sequence_helper.cc
+++ b/extensions/browser/api/declarative_net_request/file_sequence_helper.cc
@@ -19,6 +19,108 @@
 namespace extensions {
 namespace declarative_net_request {
 
+namespace {
+
+// A class to help in re-indexing multiple rulesets.
+class ReindexHelper {
+ public:
+  // Starts re-indexing rulesets. Must be called on the extension file task
+  // runner.
+  using ReindexCallback = base::OnceCallback<void(LoadRequestData)>;
+  static void Start(service_manager::Connector* connector,
+                    LoadRequestData data,
+                    ReindexCallback callback) {
+    auto* helper = new ReindexHelper(std::move(data), std::move(callback));
+    helper->Start(connector);
+  }
+
+ private:
+  // We manage our own lifetime.
+  ReindexHelper(LoadRequestData data, ReindexCallback callback)
+      : data_(std::move(data)), callback_(std::move(callback)) {}
+  ~ReindexHelper() = default;
+
+  void Start(service_manager::Connector* connector) {
+    DCHECK(GetExtensionFileTaskRunner()->RunsTasksInCurrentSequence());
+
+    base::Token token = base::Token::CreateRandom();
+
+    // Post tasks to reindex individual rulesets.
+    bool did_post_task = false;
+    for (auto& ruleset : data_.rulesets) {
+      if (ruleset.did_load_successfully())
+        continue;
+
+      // Using Unretained is safe since this class manages its own lifetime and
+      // |this| won't be deleted until the |callback| returns.
+      auto callback = base::BindOnce(&ReindexHelper::OnReindexCompleted,
+                                     base::Unretained(this), &ruleset);
+      callback_count_++;
+      did_post_task = true;
+      ruleset.source().IndexAndPersistRules(connector, token,
+                                            std::move(callback));
+    }
+
+    // It's possible that the callbacks return synchronously and we are deleted
+    // at this point. Hence don't use any member variables here. Also, if we
+    // don't post any task, we'll leak. Ensure that's not the case.
+    DCHECK(did_post_task);
+  }
+
+  // Callback invoked when a single ruleset is re-indexed.
+  void OnReindexCompleted(RulesetInfo* ruleset,
+                          IndexAndPersistRulesResult result) {
+    DCHECK(ruleset);
+
+    // The checksum of the reindexed ruleset should have been the same as the
+    // expected checksum obtained from prefs, in all cases except when the
+    // ruleset version changes. If this is not the case, then there is some
+    // other issue (like the JSON rules file has been modified from the one used
+    // during installation or preferences are corrupted). But taking care of
+    // these is beyond our scope here, so simply signal a failure.
+    bool reindexing_success = result.success && ruleset->expected_checksum() ==
+                                                    result.ruleset_checksum;
+
+    // In case of updates to the ruleset version, the change of ruleset checksum
+    // is expected.
+    if (result.success &&
+        ruleset->load_ruleset_result() ==
+            RulesetMatcher::LoadRulesetResult::kLoadErrorVersionMismatch) {
+      ruleset->set_new_checksum(result.ruleset_checksum);
+
+      // Also change the |expected_checksum| so that any subsequent load
+      // succeeds.
+      ruleset->set_expected_checksum(result.ruleset_checksum);
+      reindexing_success = true;
+    }
+
+    ruleset->set_reindexing_successful(reindexing_success);
+
+    // TODO(karandeepb): Update this histogram once we start supporting multiple
+    // rulesets per extension.
+    UMA_HISTOGRAM_BOOLEAN(
+        "Extensions.DeclarativeNetRequest.RulesetReindexSuccessful",
+        reindexing_success);
+
+    callback_count_--;
+    DCHECK_GE(callback_count_, 0);
+
+    if (callback_count_ == 0) {
+      // Our job is done.
+      std::move(callback_).Run(std::move(data_));
+      delete this;
+    }
+  }
+
+  LoadRequestData data_;
+  ReindexCallback callback_;
+  int callback_count_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(ReindexHelper);
+};
+
+}  // namespace
+
 RulesetInfo::RulesetInfo(RulesetSource source) : source_(std::move(source)) {}
 RulesetInfo::~RulesetInfo() = default;
 RulesetInfo::RulesetInfo(RulesetInfo&&) = default;
@@ -48,8 +150,8 @@
       load_ruleset_result(), RulesetMatcher::kLoadResultMax);
 }
 
-LoadRequestData::LoadRequestData(ExtensionId extension_id, RulesetInfo ruleset)
-    : extension_id(std::move(extension_id)), ruleset(std::move(ruleset)) {}
+LoadRequestData::LoadRequestData(ExtensionId extension_id)
+    : extension_id(std::move(extension_id)) {}
 LoadRequestData::~LoadRequestData() = default;
 LoadRequestData::LoadRequestData(LoadRequestData&&) = default;
 LoadRequestData& LoadRequestData::operator=(LoadRequestData&&) = default;
@@ -64,73 +166,49 @@
   DCHECK(GetExtensionFileTaskRunner()->RunsTasksInCurrentSequence());
 }
 
-void FileSequenceHelper::LoadRuleset(LoadRequestData load_data,
-                                     LoadRulesetUICallback ui_callback) const {
+void FileSequenceHelper::LoadRulesets(
+    LoadRequestData load_data,
+    LoadRulesetsUICallback ui_callback) const {
   DCHECK(GetExtensionFileTaskRunner()->RunsTasksInCurrentSequence());
+  DCHECK(!load_data.rulesets.empty());
 
-  load_data.ruleset.CreateVerifiedMatcher();
+  bool success = true;
+  for (auto& ruleset : load_data.rulesets) {
+    ruleset.CreateVerifiedMatcher();
+    success &= ruleset.did_load_successfully();
+  }
 
-  if (load_data.ruleset.did_load_successfully()) {
+  if (success) {
     base::PostTaskWithTraits(
         FROM_HERE, {content::BrowserThread::UI},
         base::BindOnce(std::move(ui_callback), std::move(load_data)));
     return;
   }
 
-  // Clone the RulesetSource before moving |load_data|.
-  RulesetSource source_copy = load_data.ruleset.source().Clone();
+  // Loading one or more rulesets failed. Re-index them.
 
-  // Attempt to reindex the extension ruleset.
-  // Using a weak pointer here is safe since |ruleset_reindexed_callback| will
-  // be called on this sequence itself.
-  RulesetSource::IndexAndPersistRulesCallback ruleset_reindexed_callback =
-      base::BindOnce(&FileSequenceHelper::OnRulesetReindexed,
-                     weak_factory_.GetWeakPtr(), std::move(load_data),
-                     std::move(ui_callback));
-  source_copy.IndexAndPersistRules(connector_.get(),
-                                   base::nullopt /* decoder_batch_id */,
-                                   std::move(ruleset_reindexed_callback));
+  // Using a WeakPtr is safe since |reindex_callback| will be called on this
+  // sequence itself.
+  auto reindex_callback =
+      base::BindOnce(&FileSequenceHelper::OnRulesetsReindexed,
+                     weak_factory_.GetWeakPtr(), std::move(ui_callback));
+  ReindexHelper::Start(connector_.get(), std::move(load_data),
+                       std::move(reindex_callback));
 }
 
-void FileSequenceHelper::OnRulesetReindexed(
-    LoadRequestData load_data,
-    LoadRulesetUICallback ui_callback,
-    IndexAndPersistRulesResult result) const {
+void FileSequenceHelper::OnRulesetsReindexed(LoadRulesetsUICallback ui_callback,
+                                             LoadRequestData load_data) const {
   DCHECK(GetExtensionFileTaskRunner()->RunsTasksInCurrentSequence());
 
-  // Only ruleset which can't be loaded are reindexed.
-  DCHECK(!load_data.ruleset.did_load_successfully());
-
-  // The checksum of the reindexed ruleset should have been the same as the
-  // expected checksum obtained from prefs, in all cases except when the
-  // ruleset version changes. If this is not the case, then there is some
-  // other issue (like the JSON rules file has been modified from the one used
-  // during installation or preferences are corrupted). But taking care of
-  // these is beyond our scope here, so simply signal a failure.
-  bool reindexing_success =
-      result.success &&
-      load_data.ruleset.expected_checksum() == result.ruleset_checksum;
-
-  // In case of updates to the ruleset version, the change of ruleset checksum
-  // is expected.
-  if (result.success &&
-      load_data.ruleset.load_ruleset_result() ==
-          RulesetMatcher::LoadRulesetResult::kLoadErrorVersionMismatch) {
-    load_data.ruleset.set_new_checksum(result.ruleset_checksum);
-    // Also change the |expected_checksum| so that the subsequent load
-    // succeeds.
-    load_data.ruleset.set_expected_checksum(result.ruleset_checksum);
-    reindexing_success = true;
+  // Load rulesets for which reindexing succeeded.
+  for (auto& ruleset : load_data.rulesets) {
+    if (ruleset.reindexing_successful().value_or(false)) {
+      // Only rulesets which can't be loaded are re-indexed.
+      DCHECK(!ruleset.did_load_successfully());
+      ruleset.CreateVerifiedMatcher();
+    }
   }
 
-  UMA_HISTOGRAM_BOOLEAN(
-      "Extensions.DeclarativeNetRequest.RulesetReindexSuccessful",
-      reindexing_success);
-
-  // If the reindexing was successful, try to load the ruleset again.
-  if (reindexing_success)
-    load_data.ruleset.CreateVerifiedMatcher();
-
   // The UI thread will handle success or failure.
   base::PostTaskWithTraits(
       FROM_HERE, {content::BrowserThread::UI},
diff --git a/extensions/browser/api/declarative_net_request/file_sequence_helper.h b/extensions/browser/api/declarative_net_request/file_sequence_helper.h
index 3809f874..cf4a2ab1 100644
--- a/extensions/browser/api/declarative_net_request/file_sequence_helper.h
+++ b/extensions/browser/api/declarative_net_request/file_sequence_helper.h
@@ -6,6 +6,7 @@
 #define EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_FILE_SEQUENCE_HELPER_H_
 
 #include <memory>
+#include <vector>
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
@@ -45,6 +46,12 @@
   void set_expected_checksum(int checksum) { expected_checksum_ = checksum; }
   base::Optional<int> expected_checksum() const { return expected_checksum_; }
 
+  // Whether re-indexing of the ruleset was successful.
+  void set_reindexing_successful(bool val) { reindexing_successful_ = val; }
+  base::Optional<bool> reindexing_successful() const {
+    return reindexing_successful_;
+  }
+
   // Must be called after CreateVerifiedMatcher.
   RulesetMatcher::LoadRulesetResult load_ruleset_result() const;
 
@@ -71,18 +78,21 @@
   // set in case of flatbuffer version mismatch.
   base::Optional<int> new_checksum_;
 
+  // Whether the reindexing of this ruleset was successful.
+  base::Optional<bool> reindexing_successful_;
+
   DISALLOW_COPY_AND_ASSIGN(RulesetInfo);
 };
 
 // Helper to pass information related to the ruleset being loaded.
 struct LoadRequestData {
-  LoadRequestData(ExtensionId extension_id, RulesetInfo ruleset);
+  explicit LoadRequestData(ExtensionId extension_id);
   ~LoadRequestData();
   LoadRequestData(LoadRequestData&&);
   LoadRequestData& operator=(LoadRequestData&&);
 
   ExtensionId extension_id;
-  RulesetInfo ruleset;
+  std::vector<RulesetInfo> rulesets;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(LoadRequestData);
@@ -96,17 +106,16 @@
   FileSequenceHelper();
   ~FileSequenceHelper();
 
-  // Loads ruleset for |load_data|. Invokes |ui_callback| on the UI thread once
+  // Loads rulesets for |load_data|. Invokes |ui_callback| on the UI thread once
   // loading is done.
-  using LoadRulesetUICallback = base::OnceCallback<void(LoadRequestData)>;
-  void LoadRuleset(LoadRequestData load_data,
-                   LoadRulesetUICallback ui_callback) const;
+  using LoadRulesetsUICallback = base::OnceCallback<void(LoadRequestData)>;
+  void LoadRulesets(LoadRequestData load_data,
+                    LoadRulesetsUICallback ui_callback) const;
 
  private:
-  // Callback invoked when the JSON ruleset is reindexed.
-  void OnRulesetReindexed(LoadRequestData load_data,
-                          LoadRulesetUICallback ui_callback,
-                          IndexAndPersistRulesResult result) const;
+  // Callback invoked when the JSON rulesets are reindexed.
+  void OnRulesetsReindexed(LoadRulesetsUICallback ui_callback,
+                           LoadRequestData load_data) const;
 
   const std::unique_ptr<service_manager::Connector> connector_;
 
diff --git a/extensions/browser/api/declarative_net_request/file_sequence_helper_unittest.cc b/extensions/browser/api/declarative_net_request/file_sequence_helper_unittest.cc
new file mode 100644
index 0000000..48a3da45
--- /dev/null
+++ b/extensions/browser/api/declarative_net_request/file_sequence_helper_unittest.cc
@@ -0,0 +1,189 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/api/declarative_net_request/file_sequence_helper.h"
+
+#include <functional>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/run_loop.h"
+#include "base/task/post_task.h"
+#include "components/crx_file/id_util.h"
+#include "components/version_info/version_info.h"
+#include "content/public/test/test_service_manager_context.h"
+#include "extensions/browser/api/declarative_net_request/ruleset_source.h"
+#include "extensions/browser/api/declarative_net_request/test_utils.h"
+#include "extensions/browser/api/declarative_net_request/utils.h"
+#include "extensions/browser/extension_file_task_runner.h"
+#include "extensions/browser/extensions_test.h"
+#include "extensions/common/api/declarative_net_request/test_utils.h"
+#include "extensions/common/features/feature_channel.h"
+#include "services/data_decoder/public/cpp/testing_json_parser.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+namespace declarative_net_request {
+namespace {
+
+struct LoadRulesetResult {
+  bool has_new_checksum = false;
+  base::Optional<bool> reindexing_successful;
+  RulesetMatcher::LoadRulesetResult load_result =
+      RulesetMatcher::kLoadResultMax;
+};
+
+struct TestCase {
+  explicit TestCase(RulesetSource source) : source(std::move(source)) {}
+  int checksum;
+  RulesetSource source;
+  LoadRulesetResult expected_result;
+};
+
+class FileSequenceHelperTest : public ExtensionsTest {
+ public:
+  FileSequenceHelperTest() : channel_(::version_info::Channel::UNKNOWN) {}
+
+  // ExtensonsTest overrides:
+  void SetUp() override {
+    ExtensionsTest::SetUp();
+    helper_ = std::make_unique<FileSequenceHelper>();
+  }
+  void TearDown() override {
+    GetExtensionFileTaskRunner()->DeleteSoon(FROM_HERE, std::move(helper_));
+    base::RunLoop().RunUntilIdle();
+    ExtensionsTest::TearDown();
+  }
+
+  void TestLoadRulesets(const std::vector<TestCase>& test_cases) {
+    ExtensionId extension_id = crx_file::id_util::GenerateId("dummy_extension");
+
+    LoadRequestData data(extension_id);
+    for (const auto& test_case : test_cases) {
+      data.rulesets.emplace_back(test_case.source.Clone());
+      data.rulesets.back().set_expected_checksum(test_case.checksum);
+    }
+
+    base::RunLoop run_loop;
+    auto load_ruleset_callback = base::BindOnce(
+        [](base::RunLoop* run_loop, const std::vector<TestCase>& test_cases,
+           LoadRequestData data) {
+          // Verify |data| is as expected.
+          ASSERT_EQ(data.rulesets.size(), test_cases.size());
+
+          for (size_t i = 0; i < data.rulesets.size(); i++) {
+            const RulesetInfo& ruleset = data.rulesets[i];
+            const LoadRulesetResult& expected_result =
+                test_cases[i].expected_result;
+
+            EXPECT_EQ(expected_result.has_new_checksum,
+                      ruleset.new_checksum().has_value());
+            EXPECT_EQ(expected_result.reindexing_successful,
+                      ruleset.reindexing_successful());
+            EXPECT_EQ(expected_result.load_result,
+                      ruleset.load_ruleset_result());
+          }
+
+          run_loop->Quit();
+        },
+        &run_loop, std::cref(test_cases));
+
+    // Unretained is safe because |helper_| outlives the |load_ruleset_task|.
+    auto load_ruleset_task = base::BindOnce(
+        &FileSequenceHelper::LoadRulesets, base::Unretained(helper_.get()),
+        std::move(data), std::move(load_ruleset_callback));
+    GetExtensionFileTaskRunner()->PostTask(FROM_HERE,
+                                           std::move(load_ruleset_task));
+    run_loop.Run();
+  }
+
+ private:
+  // Run this on the trunk channel to ensure the API is available.
+  ScopedCurrentChannel channel_;
+
+  std::unique_ptr<FileSequenceHelper> helper_;
+
+  // Required to use SafeJSONParser for re-indexing.
+  content::TestServiceManagerContext service_manager_context_;
+  data_decoder::TestingJsonParser::ScopedFactoryOverride factory_override_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileSequenceHelperTest);
+};
+
+// Tests loading and reindexing multiple rulesets.
+TEST_F(FileSequenceHelperTest, MultipleRulesets) {
+  const int kNumRulesets = 3;
+  std::vector<TestCase> test_cases;
+
+  // First create |kNumRulesets| indexed rulesets.
+  for (size_t i = 0; i < kNumRulesets; i++) {
+    test_cases.emplace_back(CreateTemporarySource());
+
+    auto& test_case = test_cases.back();
+
+    std::unique_ptr<RulesetMatcher> matcher;
+    ASSERT_TRUE(CreateVerifiedMatcher({CreateGenericRule()}, test_case.source,
+                                      &matcher, &test_case.checksum));
+
+    // Initially loading all the rulesets should succeed.
+    test_case.expected_result.load_result = RulesetMatcher::kLoadSuccess;
+  }
+
+  TestLoadRulesets(test_cases);
+
+  // Now delete the first and third indexed rulesets. This would cause a
+  // re-index.
+  base::DeleteFile(test_cases[0].source.indexed_path(), false /* recursive */);
+  base::DeleteFile(test_cases[2].source.indexed_path(), false /* recursive */);
+  test_cases[0].expected_result.reindexing_successful = true;
+  test_cases[2].expected_result.reindexing_successful = true;
+
+  TestLoadRulesets(test_cases);
+
+  // The files should have been re-indexed.
+  EXPECT_TRUE(base::PathExists(test_cases[0].source.indexed_path()));
+  EXPECT_TRUE(base::PathExists(test_cases[2].source.indexed_path()));
+
+  // Reset state.
+  test_cases[0].expected_result.reindexing_successful = base::nullopt;
+  test_cases[2].expected_result.reindexing_successful = base::nullopt;
+
+  // Change the expected checksum for rulesets 2 and 3. Loading both of the
+  // rulesets should now fail due to a checksum mismatch.
+  test_cases[1].checksum--;
+  test_cases[2].checksum--;
+  test_cases[1].expected_result.load_result =
+      RulesetMatcher::kLoadErrorChecksumMismatch;
+  test_cases[2].expected_result.load_result =
+      RulesetMatcher::kLoadErrorChecksumMismatch;
+  test_cases[1].expected_result.reindexing_successful = false;
+  test_cases[2].expected_result.reindexing_successful = false;
+
+  TestLoadRulesets(test_cases);
+
+  // Reset checksums.
+  test_cases[1].checksum++;
+  test_cases[2].checksum++;
+
+  // Now simulate a flatbuffer version mismatch.
+  const int kIndexedRulesetFormatVersion = 100;
+  std::string old_version_header = GetVersionHeaderForTesting();
+  SetIndexedRulesetFormatVersionForTesting(kIndexedRulesetFormatVersion);
+  ASSERT_NE(old_version_header, GetVersionHeaderForTesting());
+
+  // Version mismatch will cause reindexing and updated checksums.
+  for (auto& test_case : test_cases) {
+    test_case.expected_result.reindexing_successful = true;
+    test_case.expected_result.has_new_checksum = true;
+    test_case.expected_result.load_result = RulesetMatcher::kLoadSuccess;
+  }
+
+  TestLoadRulesets(test_cases);
+}
+
+}  // namespace
+}  // namespace declarative_net_request
+}  // namespace extensions
diff --git a/extensions/browser/api/declarative_net_request/rules_monitor_service.cc b/extensions/browser/api/declarative_net_request/rules_monitor_service.cc
index 424d5eae..e1c41ba 100644
--- a/extensions/browser/api/declarative_net_request/rules_monitor_service.cc
+++ b/extensions/browser/api/declarative_net_request/rules_monitor_service.cc
@@ -105,16 +105,16 @@
     file_task_runner_->DeleteSoon(FROM_HERE, std::move(file_sequence_helper_));
   }
 
-  void LoadRuleset(
+  void LoadRulesets(
       LoadRequestData load_data,
-      FileSequenceHelper::LoadRulesetUICallback load_ruleset_callback) const {
+      FileSequenceHelper::LoadRulesetsUICallback ui_callback) const {
     // base::Unretained is safe here because we trigger the destruction of
     // |file_sequence_helper_| on |file_task_runner_| from our destructor. Hence
     // it is guaranteed to be alive when |load_ruleset_task| is run.
     base::OnceClosure load_ruleset_task =
-        base::BindOnce(&FileSequenceHelper::LoadRuleset,
+        base::BindOnce(&FileSequenceHelper::LoadRulesets,
                        base::Unretained(file_sequence_helper_.get()),
-                       std::move(load_data), std::move(load_ruleset_callback));
+                       std::move(load_data), std::move(ui_callback));
     file_task_runner_->PostTask(FROM_HERE, std::move(load_ruleset_task));
   }
 
@@ -167,14 +167,15 @@
   RulesetInfo ruleset(RulesetSource::Create(*extension));
   ruleset.set_expected_checksum(expected_ruleset_checksum);
 
-  LoadRequestData load_data(extension->id(), std::move(ruleset));
+  // TODO(crbug.com/930961): Currently we only support a single ruleset per
+  // extension.
+  LoadRequestData load_data(extension->id());
+  load_data.rulesets.push_back(std::move(ruleset));
 
-  FileSequenceHelper::LoadRulesetUICallback load_ruleset_callback =
-      base::BindOnce(&RulesMonitorService::OnRulesetLoaded,
-                     weak_factory_.GetWeakPtr());
-
-  file_sequence_bridge_->LoadRuleset(std::move(load_data),
-                                     std::move(load_ruleset_callback));
+  auto load_ruleset_callback = base::BindOnce(
+      &RulesMonitorService::OnRulesetLoaded, weak_factory_.GetWeakPtr());
+  file_sequence_bridge_->LoadRulesets(std::move(load_data),
+                                      std::move(load_ruleset_callback));
 }
 
 void RulesMonitorService::OnExtensionUnloaded(
@@ -194,10 +195,15 @@
 }
 
 void RulesMonitorService::OnRulesetLoaded(LoadRequestData load_data) {
-  // Update the ruleset checksum if needed.
-  if (load_data.ruleset.new_checksum()) {
+  // TODO(crbug.com/930961): Currently we only support a single ruleset per
+  // extension.
+  DCHECK_EQ(1u, load_data.rulesets.size());
+  RulesetInfo& ruleset = load_data.rulesets[0];
+
+  // Update the ruleset checksums if needed.
+  if (ruleset.new_checksum()) {
     prefs_->SetDNRRulesetChecksum(load_data.extension_id,
-                                  *load_data.ruleset.new_checksum());
+                                  *(ruleset.new_checksum()));
   }
 
   // It's possible that the extension has been disabled since the initial load
@@ -206,7 +212,7 @@
           load_data.extension_id))
     return;
 
-  if (!load_data.ruleset.did_load_successfully()) {
+  if (!ruleset.did_load_successfully()) {
     // The ruleset failed to load. Notify the user.
     warning_service_->AddWarnings(
         {Warning::CreateRulesetFailedToLoadWarning(load_data.extension_id)});
@@ -217,11 +223,10 @@
   for (auto& observer : observers_)
     observer.OnRulesetLoaded();
 
-  base::OnceClosure load_ruleset_on_io =
-      base::BindOnce(&LoadRulesetOnIOThread, load_data.extension_id,
-                     load_data.ruleset.TakeMatcher(),
-                     prefs_->GetDNRAllowedPages(load_data.extension_id),
-                     base::RetainedRef(info_map_));
+  base::OnceClosure load_ruleset_on_io = base::BindOnce(
+      &LoadRulesetOnIOThread, load_data.extension_id, ruleset.TakeMatcher(),
+      prefs_->GetDNRAllowedPages(load_data.extension_id),
+      base::RetainedRef(info_map_));
   base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
                            std::move(load_ruleset_on_io));
 }
diff --git a/extensions/browser/url_loader_factory_manager.cc b/extensions/browser/url_loader_factory_manager.cc
index c64516f0..0beb4e7 100644
--- a/extensions/browser/url_loader_factory_manager.cc
+++ b/extensions/browser/url_loader_factory_manager.cc
@@ -65,22 +65,27 @@
     "072D729E856B1F2C9894AEEC3A5DF65E519D6BEE",
     "07333481B7B8D7F57A9BA64FB98CF86EA87455FC",
     "086E69ED9071DCB20C93A081A68360963AB09385",
+    "0CB16BAEE070B7617E9188B387C44964FB705D79",
     "0EAEA2FDEE025D95B3ABB37014EFF5A98AC4BEAE",
     "109A37B889E7C8AEA7B0103559C3EB6AF73B7832",
     "16A81AEA09A67B03F7AEA5B957D24A4095E764BE",
     "177508B365CBF1610CC2B53707749D79272F2F0B",
     "1AB9CC404876117F49135E67BAD813F935AAE9BA",
+    "1CDDF7436E5F891E1D5E37164F7EB992AECA0E2D",
     "1DB115A4344B58C0B7CC1595662E86C9E92C0848",
     "1E37F1A19C1C528E616637B105CFC4838ECF52B4",
     "260871EABEDE6F2D07D0D9450096093EDAFCBF34",
     "29427534E31BB1820714C7CAEDF9C54B47BE154F",
     "2AA94E2D3F4DA33F0D3BCF5DD48F69B8BDB26F52",
+    "2C116B242B7425D359E188AB053B3F88DB78F78D",
     "2E2D8A405430172AB15ADCC09740F3EEE990D605",
     "31E6100DC7B4EAB4ABF6CA2A4E191D3945D3C731",
     "3230014EA01150A27C1887B700E019B27A6DBA08",
     "3334952C8387B357A41DD8349D39AD9E7C423943",
     "34FB670464B5F16EF5ABD6CD53E26030E97C26B3",
     "360D8A88545D0C21CBDE2B55EA9E4E4285282B4C",
+    "37AC33A3A46D271CCE57DD6CB3FACE6B01F5A347",
+    "3CD98763C80D86E00CB1C4CAA56CEA8F3B0BA4F1",
     "3EB17C39F8B6B28FAF34E2406E57A76013A2E066",
     "3FDD3DB17F3B686F5A05204700ABA13DF20AE957",
     "41536C3554CD9458EB2F05F1B58CF84BB7BF83BC",
@@ -91,26 +96,36 @@
     "505F2C1E723731B2C8C9182FEAA73D00525B2048",
     "50DDD8734521B61564FCE273F8E60547F88BBCBE",
     "52865B2087D0ABCD195A83DFD4BD041A3B4EBC34",
+    "52C94AC7680C3A03CCB6EA31445DD42BD0D5CA8E",
     "58BCF05A42C8ECED4E6D76F51E2E1A64AC4F7E7C",
+    "5E052881B4847F68CFC8ED1A00C341FC14009C1E",
     "5F0C47BC039BEDC1B29B68918F75370C292076A6",
     "61E581B10D83C0AEF8366BB64C18C6615884B3D2",
     "6357533CAFFB94A9EA5268ED110079E15561E469",
+    "65C20C06ED10E6F39EED527AC736D87B0390DE70",
     "67528F9B47BE454EC46809C33D24F2C199BE408D",
     "6AE81EF3B13B15080A2DDB23A205A24C65CCC10B",
     "6BA5F75FFF75B69507BC4B09B7094926EF93DBD2",
     "6E49449D56D031B87835CC767734AF5A064E1A13",
+    "71CB78C3334D5122E7F23C8525AD24100CDE7D4A",
     "71EE66C0F71CD89BEE340F8568A44101D4C3A9A7",
     "77D83E0A4157A0E77B51AD60BAB69A346CD4FEA3",
+    "7879DB88205D880B64D55E51B9726E1D12F7261F",
     "7BFE588B209A15260DE12777B4BBB738DE98FE6C",
     "808FA9BB3CD501D7801D1CD6D5A3DBA088FDD46F",
     "82FDBBF79F3517C3946BD89EAAF90C46DFDA4681",
+    "83B6C75264D5D2F81FDEFD681EDD2076DD8F0B9B",
     "88C372CE52E21560C17BFD52556E60D694E12CAC",
     "88F5F459139892C0F5DF3022676726BB3F01FB5C",
+    "89C9B32115F19A18E9BE4906DC59F24A934CB9F0",
     "89F40D84C0C72C6B02B320716E877FB1671218E9",
+    "8A0634388BCBB6D073E1C97B14C024396ED32D12",
     "8CDD303D6C341D9CAB16713C3CD7587B90A7A84A",
     "8CE6227B4E53DF42FF93B24F49D15EDE31E97E79",
     "934B8F5753A3E5A276FC7D0EE5E575B335A0CC76",
     "973E35633030AD27DABEC99609424A61386C7309",
+    "97E04C5632954E778306CAC40B3F95C470B463B6",
+    "98EF7B1601119AEE1FCC28EE5CE247DED5676539",
     "99E06C364BBB2D1F82A9D20BC1645BF21E478259",
     "A30E526CF62131BFBFD7CD9B56253A8F3F171777",
     "A3660FA31A0DBF07C9F80D5342FF215DBC962719",
@@ -125,11 +140,15 @@
     "BF5224FB246A6B67EA986EFF77A43F6C1BCA9672",
     "C5539F4EBECABA792CC40D03A56144AAD3BF9D19",
     "C5BCB9E2E47C3F6FD3F7F83ED982872F77852BA7",
+    "C86D546CA47034163C12DC2C912910C3A12C3B07",
+    "C940F83135D9612865F4A44391DDDFE3B7BE1393",
     "CA89BD35059845F2DB4B4398FD339B9F210E9337",
     "CC74B2408753932B5D49C81EC073E3E4CA766EE6",
     "CD8AF9C47DDE6327F8D9A3EFA81F34C6B6C26EBB",
     "CF40F6289951CBFA3B83B792EFA774E2EA06E4C0",
     "D0537B1BADCE856227CE76E31B3772F6B68F653C",
+    "D9A97CD75380C697C65D37512E53DBECDFA45FB9",
+    "DDA21167F058A65D878DF84C3CF3FCC60B053E80",
     "E178D4F4D6617C0B880C36F192DA3B18422C5064",
     "E6B12430B6166B31BE20E13941C22569EA75B0F2",
     "E7036E906DBFB77C46EDDEB003A72C0B5CC9BE7F",
@@ -143,7 +162,9 @@
     "F59AB261280AB3AE9826D9359507838B90B07431",
     "F73F9EF0207603992CA3C00A7A0CB223D5571B3F",
     "F9287A33E15038F2591F23E6E9C486717C7202DD",
+    "FEE3DC8C722657A4A5B0F72CA48CF950DC956148",
     "FF0DA4BD87A88469B10709B99E79D4B0E11C0CA6",
+    "FF8257C73304BA655E10F324C962504BA6691DF2",
 };
 
 constexpr size_t kHashedExtensionIdLength = base::kSHA1Length * 2;
diff --git a/extensions/common/api/test.json b/extensions/common/api/test.json
index 7e046cf3..5772972 100644
--- a/extensions/common/api/test.json
+++ b/extensions/common/api/test.json
@@ -61,11 +61,6 @@
                     "minimum": 0,
                     "maximum": 65535
                   },
-                  "nativeCrxBindingsEnabled": {
-                    "type": "boolean",
-                    "optional": true,
-                    "description": "Whether native extension bindings are enabled."
-                  },
                   "loginStatus": {
                     "type": "object",
                     "optional": true,
diff --git a/extensions/renderer/BUILD.gn b/extensions/renderer/BUILD.gn
index d29dd5b..d98ea1d 100644
--- a/extensions/renderer/BUILD.gn
+++ b/extensions/renderer/BUILD.gn
@@ -110,8 +110,6 @@
     "extension_injection_host.h",
     "extension_js_runner.cc",
     "extension_js_runner.h",
-    "extension_port.cc",
-    "extension_port.h",
     "extension_throttle_entry.cc",
     "extension_throttle_entry.h",
     "extension_throttle_manager.cc",
@@ -158,8 +156,6 @@
     "injection_host.h",
     "ipc_message_sender.cc",
     "ipc_message_sender.h",
-    "js_renderer_messaging_service.cc",
-    "js_renderer_messaging_service.h",
     "lazy_background_page_native_handler.cc",
     "lazy_background_page_native_handler.h",
     "logging_native_handler.cc",
diff --git a/extensions/renderer/extension_port.cc b/extensions/renderer/extension_port.cc
deleted file mode 100644
index 05cd0e5..0000000
--- a/extensions/renderer/extension_port.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extensions/renderer/extension_port.h"
-
-#include "content/public/renderer/render_frame.h"
-#include "content/public/renderer/worker_thread.h"
-#include "extensions/common/api/messaging/message.h"
-#include "extensions/common/api/messaging/port_context.h"
-#include "extensions/common/api/messaging/port_id.h"
-#include "extensions/common/extension_messages.h"
-#include "extensions/renderer/extension_bindings_system.h"
-#include "extensions/renderer/ipc_message_sender.h"
-#include "extensions/renderer/script_context.h"
-#include "extensions/renderer/worker_thread_dispatcher.h"
-#include "extensions/renderer/worker_thread_util.h"
-
-namespace extensions {
-
-ExtensionPort::ExtensionPort(ScriptContext* script_context,
-                             const PortId& id,
-                             int js_id)
-    : script_context_(script_context), id_(id), js_id_(js_id) {}
-
-ExtensionPort::~ExtensionPort() {}
-
-void ExtensionPort::PostExtensionMessage(std::unique_ptr<Message> message) {
-  if (worker_thread_util::IsWorkerThread()) {
-    DCHECK(!script_context_->GetRenderFrame());
-    WorkerThreadDispatcher::GetBindingsSystem()
-        ->GetIPCMessageSender()
-        ->SendPostMessageToPort(id_, *message);
-  } else {
-    content::RenderFrame* render_frame = script_context_->GetRenderFrame();
-    if (!render_frame)
-      return;
-    render_frame->Send(new ExtensionHostMsg_PostMessage(id_, *message));
-  }
-}
-
-void ExtensionPort::Close(bool close_channel) {
-  if (worker_thread_util::IsWorkerThread()) {
-    DCHECK(!script_context_->GetRenderFrame());
-    WorkerThreadDispatcher::GetBindingsSystem()
-        ->GetIPCMessageSender()
-        ->SendCloseMessagePort(MSG_ROUTING_NONE, id_, close_channel);
-  } else {
-    content::RenderFrame* render_frame = script_context_->GetRenderFrame();
-    if (!render_frame)
-      return;
-    render_frame->Send(new ExtensionHostMsg_CloseMessagePort(
-        PortContext::ForFrame(render_frame->GetRoutingID()), id_,
-        close_channel));
-  }
-}
-
-}  // namespace extensions
diff --git a/extensions/renderer/extension_port.h b/extensions/renderer/extension_port.h
deleted file mode 100644
index aa584a9..0000000
--- a/extensions/renderer/extension_port.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef EXTENSIONS_RENDERER_EXTENSION_PORT_H_
-#define EXTENSIONS_RENDERER_EXTENSION_PORT_H_
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/macros.h"
-#include "extensions/common/api/messaging/port_id.h"
-
-namespace extensions {
-struct Message;
-struct PortId;
-class ScriptContext;
-
-// A class representing information about a specific extension message port that
-// handles sending related IPCs to the browser. This consists of a port id and
-// a separate js_id which is exposed only to the JavaScript context.
-class ExtensionPort {
- public:
-  ExtensionPort(ScriptContext* script_context, const PortId& id, int js_id);
-  ~ExtensionPort();
-
-  // Posts a new message to the port. If the port is not initialized, the
-  // message will be queued until it is.
-  void PostExtensionMessage(std::unique_ptr<Message> message);
-
-  // Closes the port. If there are pending messages, they will still be sent
-  // assuming initialization completes (after which, the port will close).
-  void Close(bool close_channel);
-
-  const PortId& id() const { return id_; }
-  int js_id() const { return js_id_; }
-
- private:
-  // The associated ScriptContext for this port. Since these objects are owned
-  // by a NativeHandler, this should always be valid.
-  ScriptContext* script_context_ = nullptr;
-
-  const PortId id_;
-
-  // The id used in the JS bindings. If this is a receiver port, this is not the
-  // same as the port_number in the PortId. This should be used only as an
-  // identifier in the JS context this port is from.
-  int js_id_ = 0;
-
-  DISALLOW_COPY_AND_ASSIGN(ExtensionPort);
-};
-
-}  // namespace extensions
-
-#endif  // EXTENSIONS_RENDERER_EXTENSION_PORT_H_
diff --git a/extensions/renderer/js_renderer_messaging_service.cc b/extensions/renderer/js_renderer_messaging_service.cc
deleted file mode 100644
index 21aeabf..0000000
--- a/extensions/renderer/js_renderer_messaging_service.cc
+++ /dev/null
@@ -1,189 +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 "extensions/renderer/js_renderer_messaging_service.h"
-
-#include <stdint.h>
-
-#include <string>
-
-#include "base/stl_util.h"
-#include "content/public/common/child_process_host.h"
-#include "content/public/renderer/v8_value_converter.h"
-#include "extensions/common/api/messaging/message.h"
-#include "extensions/common/api/messaging/messaging_endpoint.h"
-#include "extensions/common/api/messaging/port_id.h"
-#include "extensions/common/extension_messages.h"
-#include "extensions/common/manifest_handlers/externally_connectable.h"
-#include "extensions/renderer/extension_port.h"
-#include "extensions/renderer/messaging_bindings.h"
-#include "extensions/renderer/script_context.h"
-#include "extensions/renderer/v8_helpers.h"
-#include "v8/include/v8.h"
-
-namespace extensions {
-
-using v8_helpers::ToV8String;
-
-JSRendererMessagingService::JSRendererMessagingService(
-    ExtensionBindingsSystem* bindings_system)
-    : RendererMessagingService(bindings_system) {}
-JSRendererMessagingService::~JSRendererMessagingService() {}
-
-bool JSRendererMessagingService::ContextHasMessagePort(
-    ScriptContext* script_context,
-    const PortId& port_id) {
-  MessagingBindings* bindings = MessagingBindings::ForContext(script_context);
-  DCHECK(bindings);
-  return bindings->GetPortWithId(port_id) != nullptr;
-}
-
-void JSRendererMessagingService::DispatchOnConnectToListeners(
-    ScriptContext* script_context,
-    const PortId& target_port_id,
-    const ExtensionId& target_extension_id,
-    const std::string& channel_name,
-    const ExtensionMsg_TabConnectionInfo* source,
-    const ExtensionMsg_ExternalConnectionInfo& info,
-    const std::string& event_name) {
-  MessagingBindings* bindings = MessagingBindings::ForContext(script_context);
-  ExtensionPort* port = bindings->CreateNewPortWithId(target_port_id);
-
-  v8::Isolate* isolate = script_context->isolate();
-  v8::HandleScope handle_scope(isolate);
-
-  const std::string& source_url_spec = info.source_url.spec();
-  const Extension* extension = script_context->extension();
-
-  v8::Local<v8::Value> tab = v8::Null(isolate);
-  v8::Local<v8::Value> tls_channel_id_value = v8::Undefined(isolate);
-  v8::Local<v8::Value> guest_process_id = v8::Undefined(isolate);
-  v8::Local<v8::Value> guest_render_frame_routing_id = v8::Undefined(isolate);
-
-  if (extension) {
-    if (!source->tab.empty() && !extension->is_platform_app()) {
-      tab = content::V8ValueConverter::Create()->ToV8Value(
-          &source->tab, script_context->v8_context());
-    }
-
-    ExternallyConnectableInfo* externally_connectable =
-        ExternallyConnectableInfo::Get(extension);
-
-    if (externally_connectable &&
-        externally_connectable->accepts_tls_channel_id) {
-      tls_channel_id_value = v8::String::Empty(isolate);
-    }
-
-    if (info.guest_process_id != content::ChildProcessHost::kInvalidUniqueID) {
-      guest_process_id = v8::Integer::New(isolate, info.guest_process_id);
-      guest_render_frame_routing_id =
-          v8::Integer::New(isolate, info.guest_render_frame_routing_id);
-    }
-  }
-
-  v8::Local<v8::String> v8_channel_name;
-  v8::Local<v8::String> v8_source_extension_id;
-  v8::Local<v8::String> v8_source_native_app_name;
-  v8::Local<v8::String> v8_target_extension_id;
-  v8::Local<v8::String> v8_source_url_spec;
-  if (!ToV8String(isolate, channel_name.c_str(), &v8_channel_name) ||
-      !ToV8String(isolate,
-                  info.source_endpoint.extension_id
-                      ? *info.source_endpoint.extension_id
-                      : ExtensionId(),
-                  &v8_source_extension_id) ||
-      !ToV8String(isolate,
-                  info.source_endpoint.native_app_name
-                      ? *info.source_endpoint.native_app_name
-                      : std::string(),
-                  &v8_source_native_app_name) ||
-      !ToV8String(isolate, target_extension_id.c_str(),
-                  &v8_target_extension_id) ||
-      !ToV8String(isolate, source_url_spec.c_str(), &v8_source_url_spec)) {
-    NOTREACHED() << "dispatchOnConnect() passed non-string argument";
-    return;
-  }
-
-  v8::Local<v8::Value> arguments[] = {
-      // portId
-      v8::Integer::New(isolate, port->js_id()),
-      // channelName
-      v8_channel_name,
-      // sourceTab
-      tab,
-      // source_frame_id
-      v8::Integer::New(isolate, source->frame_id),
-      // guestProcessId
-      guest_process_id,
-      // guestRenderFrameRoutingId
-      guest_render_frame_routing_id,
-      // sourceExtensionId
-      v8_source_extension_id,
-      // sourceNativeAppName
-      v8_source_native_app_name,
-      // targetExtensionId
-      v8_target_extension_id,
-      // sourceUrl
-      v8_source_url_spec,
-      // tlsChannelId
-      tls_channel_id_value,
-  };
-
-  // Note: this can execute asynchronously if JS is suspended.
-  script_context->module_system()->CallModuleMethodSafe(
-      "messaging", "dispatchOnConnect", base::size(arguments), arguments);
-}
-
-void JSRendererMessagingService::DispatchOnMessageToListeners(
-    ScriptContext* script_context,
-    const Message& message,
-    const PortId& target_port_id) {
-  MessagingBindings* bindings = MessagingBindings::ForContext(script_context);
-  ExtensionPort* port = bindings->GetPortWithId(target_port_id);
-  DCHECK(port);
-
-  v8::Isolate* isolate = script_context->isolate();
-  v8::HandleScope handle_scope(isolate);
-
-  v8::Local<v8::Value> port_id_handle =
-      v8::Integer::New(isolate, port->js_id());
-
-  v8::Local<v8::String> v8_data;
-  if (!ToV8String(isolate, message.data.c_str(), &v8_data))
-    return;
-  std::vector<v8::Local<v8::Value>> arguments;
-  arguments.push_back(v8_data);
-  arguments.push_back(port_id_handle);
-
-  script_context->module_system()->CallModuleMethodSafe(
-      "messaging", "dispatchOnMessage", &arguments);
-}
-
-void JSRendererMessagingService::DispatchOnDisconnectToListeners(
-    ScriptContext* script_context,
-    const PortId& port_id,
-    const std::string& error_message) {
-  MessagingBindings* bindings = MessagingBindings::ForContext(script_context);
-  ExtensionPort* port = bindings->GetPortWithId(port_id);
-  DCHECK(port);
-
-  v8::Isolate* isolate = script_context->isolate();
-  v8::HandleScope handle_scope(isolate);
-
-  std::vector<v8::Local<v8::Value>> arguments;
-  arguments.push_back(v8::Integer::New(isolate, port->js_id()));
-  v8::Local<v8::String> v8_error_message;
-  if (!error_message.empty())
-    ToV8String(isolate, error_message.c_str(), &v8_error_message);
-  if (!v8_error_message.IsEmpty()) {
-    arguments.push_back(v8_error_message);
-  } else {
-    arguments.push_back(v8::Null(isolate));
-  }
-
-  script_context->module_system()->CallModuleMethodSafe(
-      "messaging", "dispatchOnDisconnect", &arguments);
-}
-
-}  // namespace extensions
diff --git a/extensions/renderer/js_renderer_messaging_service.h b/extensions/renderer/js_renderer_messaging_service.h
deleted file mode 100644
index df10881..0000000
--- a/extensions/renderer/js_renderer_messaging_service.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef EXTENSIONS_RENDERER_JS_RENDERER_MESSAGING_SERVICE_H_
-#define EXTENSIONS_RENDERER_JS_RENDERER_MESSAGING_SERVICE_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "extensions/renderer/renderer_messaging_service.h"
-
-struct ExtensionMsg_ExternalConnectionInfo;
-struct ExtensionMsg_TabConnectionInfo;
-
-namespace extensions {
-struct Message;
-struct PortId;
-
-// The messaging service to handle dispatching extension messages and connection
-// events to different contexts.
-class JSRendererMessagingService : public RendererMessagingService {
- public:
-  explicit JSRendererMessagingService(ExtensionBindingsSystem* bindings_system);
-  ~JSRendererMessagingService() override;
-
- private:
-  // RendererMessagingService:
-  bool ContextHasMessagePort(ScriptContext* script_context,
-                             const PortId& port_id) override;
-  void DispatchOnConnectToListeners(
-      ScriptContext* script_context,
-      const PortId& target_port_id,
-      const ExtensionId& target_extension_id,
-      const std::string& channel_name,
-      const ExtensionMsg_TabConnectionInfo* source,
-      const ExtensionMsg_ExternalConnectionInfo& info,
-      const std::string& event_name) override;
-  void DispatchOnMessageToListeners(ScriptContext* script_context,
-                                    const Message& message,
-                                    const PortId& target_port_id) override;
-  void DispatchOnDisconnectToListeners(ScriptContext* script_context,
-                                       const PortId& port_id,
-                                       const std::string& error) override;
-
-  DISALLOW_COPY_AND_ASSIGN(JSRendererMessagingService);
-};
-
-}  // namespace extensions
-
-#endif  // EXTENSIONS_RENDERER_JS_RENDERER_MESSAGING_SERVICE_H_
diff --git a/extensions/renderer/messaging_bindings.cc b/extensions/renderer/messaging_bindings.cc
index 2f8d03e..6dd256b 100644
--- a/extensions/renderer/messaging_bindings.cc
+++ b/extensions/renderer/messaging_bindings.cc
@@ -6,154 +6,26 @@
 
 #include <stdint.h>
 
-#include <map>
-#include <string>
-
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
-#include "base/lazy_instance.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/values.h"
-#include "content/public/renderer/render_frame.h"
-#include "content/public/renderer/worker_thread.h"
-#include "extensions/common/api/messaging/message.h"
-#include "extensions/common/api/messaging/messaging_endpoint.h"
-#include "extensions/common/api/messaging/port_context.h"
-#include "extensions/common/api/messaging/port_id.h"
-#include "extensions/common/extension_messages.h"
-#include "extensions/renderer/extension_bindings_system.h"
-#include "extensions/renderer/extension_frame_helper.h"
-#include "extensions/renderer/extension_port.h"
 #include "extensions/renderer/gc_callback.h"
-#include "extensions/renderer/ipc_message_sender.h"
-#include "extensions/renderer/message_target.h"
-#include "extensions/renderer/messaging_util.h"
 #include "extensions/renderer/script_context.h"
-#include "extensions/renderer/script_context_set.h"
-#include "extensions/renderer/v8_helpers.h"
-#include "extensions/renderer/worker_thread_dispatcher.h"
-#include "extensions/renderer/worker_thread_util.h"
-#include "gin/converter.h"
-#include "third_party/blink/public/web/web_user_gesture_indicator.h"
 #include "v8/include/v8.h"
 
-// Message passing API example (in a content script):
-// var port = runtime.connect();
-// port.postMessage('Can you hear me now?');
-// port.onmessage.addListener(function(msg, port) {
-//   alert('response=' + msg);
-//   port.postMessage('I got your reponse');
-// });
-
 namespace extensions {
 
-using v8_helpers::ToV8String;
-
-namespace {
-
-// A global map between ScriptContext and MessagingBindings.
-base::LazyInstance<std::map<ScriptContext*, MessagingBindings*>>::
-    DestructorAtExit g_messaging_map = LAZY_INSTANCE_INITIALIZER;
-
-}  // namespace
-
 MessagingBindings::MessagingBindings(ScriptContext* context)
-    : ObjectBackedNativeHandler(context),
-      weak_ptr_factory_(this) {
-  g_messaging_map.Get()[context] = this;
-}
+    : ObjectBackedNativeHandler(context) {}
 
-MessagingBindings::~MessagingBindings() {
-  g_messaging_map.Get().erase(context());
-  if (num_extension_ports_ > 0) {
-    UMA_HISTOGRAM_COUNTS_1000(
-        "Extensions.Messaging.ExtensionPortsCreated.Total", next_js_id_);
-  }
-}
+MessagingBindings::~MessagingBindings() {}
 
 void MessagingBindings::AddRoutes() {
-  RouteHandlerFunction("CloseChannel",
-                       base::BindRepeating(&MessagingBindings::CloseChannel,
-                                           base::Unretained(this)));
-  RouteHandlerFunction("PostMessage",
-                       base::BindRepeating(&MessagingBindings::PostMessage,
-                                           base::Unretained(this)));
   // TODO(fsamuel, kalman): Move BindToGC out of messaging natives.
   RouteHandlerFunction("BindToGC",
                        base::BindRepeating(&MessagingBindings::BindToGC,
                                            base::Unretained(this)));
-  RouteHandlerFunction(
-      "OpenChannelToExtension", "runtime.connect",
-      base::BindRepeating(&MessagingBindings::OpenChannelToExtension,
-                          base::Unretained(this)));
-  RouteHandlerFunction(
-      "OpenChannelToNativeApp", "runtime.connectNative",
-      base::BindRepeating(&MessagingBindings::OpenChannelToNativeApp,
-                          base::Unretained(this)));
-  RouteHandlerFunction("OpenChannelToTab",
-                       base::BindRepeating(&MessagingBindings::OpenChannelToTab,
-                                           base::Unretained(this)));
-}
-
-// static
-MessagingBindings* MessagingBindings::ForContext(ScriptContext* context) {
-  return g_messaging_map.Get()[context];
-}
-
-ExtensionPort* MessagingBindings::GetPortWithId(const PortId& id) {
-  for (const auto& key_value : ports_) {
-    if (key_value.second->id() == id)
-      return key_value.second.get();
-  }
-  return nullptr;
-}
-
-ExtensionPort* MessagingBindings::CreateNewPortWithId(const PortId& id) {
-  int js_id = GetNextJsId();
-  auto port = std::make_unique<ExtensionPort>(context(), id, js_id);
-  return ports_.insert(std::make_pair(js_id, std::move(port)))
-      .first->second.get();
-}
-
-void MessagingBindings::PostMessage(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  // Arguments are (int32_t port_id, string message).
-  CHECK(args.Length() == 2);
-  CHECK(args[0]->IsInt32());
-  CHECK(args[1]->IsString());
-
-  int js_port_id = args[0].As<v8::Int32>()->Value();
-  auto iter = ports_.find(js_port_id);
-
-  if (iter == ports_.end())
-    return;
-
-  ExtensionPort& port = *iter->second;
-
-  v8::Isolate* isolate = args.GetIsolate();
-  std::string error;
-  std::unique_ptr<Message> message = messaging_util::MessageFromJSONString(
-      isolate, args[1].As<v8::String>(), &error, context()->web_frame());
-  if (!message) {
-    args.GetReturnValue().Set(gin::StringToV8(isolate, error));
-    return;
-  }
-
-  port.PostExtensionMessage(std::move(message));
-}
-
-void MessagingBindings::CloseChannel(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  // Arguments are (int32_t port_id, bool force_close).
-  CHECK_EQ(2, args.Length());
-  CHECK(args[0]->IsInt32());
-  CHECK(args[1]->IsBoolean());
-
-  int js_port_id = args[0].As<v8::Int32>()->Value();
-  bool force_close = args[1].As<v8::Boolean>()->Value();
-  ClosePort(js_port_id, force_close);
 }
 
 void MessagingBindings::BindToGC(
@@ -162,194 +34,12 @@
   CHECK(args[0]->IsObject());
   CHECK(args[1]->IsFunction());
   CHECK(args[2]->IsInt32());
-  int js_port_id = args[2].As<v8::Int32>()->Value();
+  // TODO(devlin): Update callers to not pass a port ID.
+  // int js_port_id = args[2].As<v8::Int32>()->Value();
   base::Closure fallback = base::DoNothing();
-  if (js_port_id >= 0) {
-    // TODO(robwu): Falling back to closing the port shouldn't be needed. If
-    // the script context is destroyed, then the frame has navigated. But that
-    // is already detected by the browser, so this logic is redundant. Remove
-    // this fallback (and move BindToGC out of messaging because it is also
-    // used in other places that have nothing to do with messaging...).
-    fallback = base::Bind(&MessagingBindings::ClosePort,
-                          weak_ptr_factory_.GetWeakPtr(), js_port_id,
-                          false /* force_close */);
-  }
   // Destroys itself when the object is GC'd or context is invalidated.
   new GCCallback(context(), args[0].As<v8::Object>(),
                  args[1].As<v8::Function>(), fallback);
 }
 
-void MessagingBindings::OpenChannelToExtension(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  content::RenderFrame* render_frame = context()->GetRenderFrame();
-  bool is_for_service_worker = false;
-  if (!render_frame &&
-      !(is_for_service_worker = worker_thread_util::IsWorkerThread()))
-    return;
-
-  // The Javascript code should validate/fill the arguments.
-  CHECK_EQ(args.Length(), 3);
-  CHECK(args[0]->IsString());
-  CHECK(args[1]->IsString());
-  CHECK(args[2]->IsBoolean());
-
-  int js_id = GetNextJsId();
-  PortId port_id(context()->context_id(), js_id, true);
-  ports_[js_id] = std::make_unique<ExtensionPort>(context(), port_id, js_id);
-
-  ExtensionMsg_ExternalConnectionInfo info;
-
-  // For messaging APIs, hosted apps should be considered a web page so hide
-  // its extension ID.
-  const Extension* extension = context()->extension();
-  if (extension && !extension->is_hosted_app()) {
-    info.source_endpoint =
-        context()->context_type() == Feature::CONTENT_SCRIPT_CONTEXT
-            ? MessagingEndpoint::ForContentScript(extension->id())
-            : MessagingEndpoint::ForExtension(extension->id());
-  } else {
-    info.source_endpoint = MessagingEndpoint::ForWebPage();
-  }
-
-  v8::Isolate* isolate = args.GetIsolate();
-  info.target_id = *v8::String::Utf8Value(isolate, args[0]);
-
-  info.source_url = context()->url();
-  std::string channel_name = *v8::String::Utf8Value(isolate, args[1]);
-
-  {
-    SCOPED_UMA_HISTOGRAM_TIMER(
-        "Extensions.Messaging.SetPortIdTime.Extension");
-    if (is_for_service_worker) {
-      WorkerThreadDispatcher::GetBindingsSystem()
-          ->GetIPCMessageSender()
-          ->SendOpenMessageChannel(
-              context(), port_id, MessageTarget::ForExtension(info.target_id),
-              channel_name, false /* include_tls_channel_id */);
-    } else {
-      render_frame->Send(new ExtensionHostMsg_OpenChannelToExtension(
-          PortContext::ForFrame(render_frame->GetRoutingID()), info,
-          channel_name, port_id));
-    }
-  }
-
-  ++num_extension_ports_;
-  args.GetReturnValue().Set(static_cast<int32_t>(js_id));
-}
-
-void MessagingBindings::OpenChannelToNativeApp(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  // The Javascript code should validate/fill the arguments.
-  CHECK_EQ(args.Length(), 1);
-  CHECK(args[0]->IsString());
-  // This should be checked by our function routing code.
-  CHECK(context()->GetAvailability("runtime.connectNative").is_available());
-
-  content::RenderFrame* render_frame = context()->GetRenderFrame();
-  bool is_for_service_worker = false;
-  if (!render_frame &&
-      !(is_for_service_worker = worker_thread_util::IsWorkerThread()))
-    return;
-
-  std::string native_app_name =
-      *v8::String::Utf8Value(args.GetIsolate(), args[0]);
-
-  int js_id = GetNextJsId();
-  PortId port_id(context()->context_id(), js_id, true);
-  ports_[js_id] = std::make_unique<ExtensionPort>(context(), port_id, js_id);
-
-  {
-    SCOPED_UMA_HISTOGRAM_TIMER(
-        "Extensions.Messaging.SetPortIdTime.NativeApp");
-    if (is_for_service_worker) {
-      WorkerThreadDispatcher::GetBindingsSystem()
-          ->GetIPCMessageSender()
-          ->SendOpenMessageChannel(context(), port_id,
-                                   MessageTarget::ForNativeApp(native_app_name),
-                                   "", false /* include_tls_channel_id */);
-    } else {
-      render_frame->Send(new ExtensionHostMsg_OpenChannelToNativeApp(
-          PortContext::ForFrame(render_frame->GetRoutingID()), native_app_name,
-          port_id));
-    }
-  }
-
-  args.GetReturnValue().Set(static_cast<int32_t>(js_id));
-}
-
-void MessagingBindings::OpenChannelToTab(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  content::RenderFrame* render_frame = context()->GetRenderFrame();
-  bool is_for_service_worker = false;
-  if (!render_frame &&
-      !(is_for_service_worker = worker_thread_util::IsWorkerThread()))
-    return;
-
-  DCHECK_NE(context()->context_type(), Feature::CONTENT_SCRIPT_CONTEXT);
-
-  // tabs_custom_bindings.js unwraps arguments to tabs.connect/sendMessage and
-  // passes them to OpenChannelToTab, in the following order:
-  // - |tab_id| - Positive number that specifies the destination of the channel.
-  // - |frame_id| - Target frame(s) in the tab where onConnect is dispatched:
-  //   -1 for all frames, 0 for the main frame, >0 for a child frame.
-  // - |extension_id| - ID of the initiating extension.
-  // - |channel_name| - A user-defined channel name.
-  CHECK(args.Length() == 4);
-  CHECK(args[0]->IsInt32());
-  CHECK(args[1]->IsInt32());
-  CHECK(args[2]->IsString());
-  CHECK(args[3]->IsString());
-
-  int js_id = GetNextJsId();
-  PortId port_id(context()->context_id(), js_id, true);
-  ports_[js_id] = std::make_unique<ExtensionPort>(context(), port_id, js_id);
-
-  ExtensionMsg_TabTargetConnectionInfo info;
-  info.tab_id = args[0].As<v8::Int32>()->Value();
-  info.frame_id = args[1].As<v8::Int32>()->Value();
-  // TODO(devlin): Why is this not part of info?
-  v8::Isolate* isolate = args.GetIsolate();
-  std::string extension_id = *v8::String::Utf8Value(isolate, args[2]);
-  std::string channel_name = *v8::String::Utf8Value(isolate, args[3]);
-
-  if (!is_for_service_worker) {
-    ExtensionFrameHelper* frame_helper =
-        ExtensionFrameHelper::Get(render_frame);
-    DCHECK(frame_helper);
-  }
-
-  {
-    SCOPED_UMA_HISTOGRAM_TIMER("Extensions.Messaging.SetPortIdTime.Tab");
-    if (is_for_service_worker) {
-      WorkerThreadDispatcher::GetBindingsSystem()
-          ->GetIPCMessageSender()
-          ->SendOpenMessageChannel(
-              context(), port_id,
-              MessageTarget::ForTab(info.tab_id, info.frame_id), channel_name,
-              false /* include_tls_channel_id */);
-    } else {
-      render_frame->Send(new ExtensionHostMsg_OpenChannelToTab(
-          PortContext::ForFrame(render_frame->GetRoutingID()), info,
-          extension_id, channel_name, port_id));
-    }
-  }
-
-  args.GetReturnValue().Set(static_cast<int32_t>(js_id));
-}
-
-void MessagingBindings::ClosePort(int js_port_id, bool force_close) {
-  // TODO(robwu): Merge this logic with CloseChannel once the TODO in BindToGC
-  // has been addressed.
-  auto iter = ports_.find(js_port_id);
-  if (iter != ports_.end()) {
-    std::unique_ptr<ExtensionPort> port = std::move(iter->second);
-    ports_.erase(iter);
-    port->Close(force_close);
-  }
-}
-
-int MessagingBindings::GetNextJsId() {
-  return next_js_id_++;
-}
-
 }  // namespace extensions
diff --git a/extensions/renderer/messaging_bindings.h b/extensions/renderer/messaging_bindings.h
index 3a2a599..d6d2ec1 100644
--- a/extensions/renderer/messaging_bindings.h
+++ b/extensions/renderer/messaging_bindings.h
@@ -8,15 +8,14 @@
 #include <string>
 
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
 #include "extensions/renderer/object_backed_native_handler.h"
 
 namespace extensions {
-class ExtensionPort;
 class ScriptContext;
-struct PortId;
 
-// Manually implements JavaScript bindings for extension messaging.
+// Provides the BindToGC native handler.
+// TODO(devlin): Rename this from messaging bindings - it's no longer remotely
+// messaging related.
 class MessagingBindings : public ObjectBackedNativeHandler {
  public:
   explicit MessagingBindings(ScriptContext* script_context);
@@ -25,59 +24,9 @@
   // ObjectBackedNativeHandler:
   void AddRoutes() override;
 
-  // Returns the MessagingBindings associated with the given |context|.
-  static MessagingBindings* ForContext(ScriptContext* context);
-
-  // Returns an existing port with the given |id|, or null.
-  ExtensionPort* GetPortWithId(const PortId& id);
-
-  // Creates a new port with the given |id|. MessagingBindings owns the
-  // returned port.
-  ExtensionPort* CreateNewPortWithId(const PortId& id);
-
  private:
-  using PortMap = std::map<int, std::unique_ptr<ExtensionPort>>;
-
-  // JS Exposed Function: Sends a message along the given channel. If an error
-  // occurs, returns the error, else returns nothing.
-  void PostMessage(const v8::FunctionCallbackInfo<v8::Value>& args);
-
-  // JS Exposed Function: Close a port, optionally forcefully (i.e. close the
-  // whole channel instead of just the given port).
-  void CloseChannel(const v8::FunctionCallbackInfo<v8::Value>& args);
-
-  // JS Exposed Function: Binds |callback| to be invoked *sometime after*
-  // |object| is garbage collected. We don't call the method re-entrantly so as
-  // to avoid executing JS in some bizarro undefined mid-GC state, nor do we
-  // then call into the script context if it's been invalidated.
   void BindToGC(const v8::FunctionCallbackInfo<v8::Value>& args);
 
-  // JS Exposed Function: Opens a new channel to an extension.
-  void OpenChannelToExtension(const v8::FunctionCallbackInfo<v8::Value>& args);
-
-  // JS Exposed Function: Opens a new channel to a native application.
-  void OpenChannelToNativeApp(const v8::FunctionCallbackInfo<v8::Value>& args);
-
-  // JS Exposed Function: Opens a new channel to a tab.
-  void OpenChannelToTab(const v8::FunctionCallbackInfo<v8::Value>& args);
-
-  // Helper function to close a port. See CloseChannel() for |force_close|
-  // documentation.
-  void ClosePort(int local_port_id, bool force_close);
-
-  int GetNextJsId();
-
-  // Active ports, mapped by local port id.
-  PortMap ports_;
-
-  // The next available js id for a port.
-  size_t next_js_id_ = 0;
-
-  // The number of extension ports created.
-  size_t num_extension_ports_ = 0;
-
-  base::WeakPtrFactory<MessagingBindings> weak_ptr_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(MessagingBindings);
 };
 
diff --git a/extensions/renderer/renderer_messaging_service.cc b/extensions/renderer/renderer_messaging_service.cc
index efcd2ca..e1a888ac 100644
--- a/extensions/renderer/renderer_messaging_service.cc
+++ b/extensions/renderer/renderer_messaging_service.cc
@@ -20,7 +20,6 @@
 #include "extensions/common/api/messaging/port_id.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/renderer/extension_bindings_system.h"
-#include "extensions/renderer/extension_port.h"
 #include "extensions/renderer/ipc_message_sender.h"
 #include "extensions/renderer/messaging_util.h"
 #include "extensions/renderer/script_context.h"
diff --git a/extensions/renderer/renderer_messaging_service.h b/extensions/renderer/renderer_messaging_service.h
index a18371f3..69d137d 100644
--- a/extensions/renderer/renderer_messaging_service.h
+++ b/extensions/renderer/renderer_messaging_service.h
@@ -24,6 +24,8 @@
 struct Message;
 struct PortId;
 
+// TODO(devlin): There is now only one RendererMessagingService (the
+// NativeRendererMessagingService); consolidate the classes.
 class RendererMessagingService {
  public:
   explicit RendererMessagingService(ExtensionBindingsSystem* bindings_system);
diff --git a/fuchsia/BUILD.gn b/fuchsia/BUILD.gn
index 8096362..5b40e7b 100644
--- a/fuchsia/BUILD.gn
+++ b/fuchsia/BUILD.gn
@@ -109,15 +109,22 @@
   # Location where debug symbol tarballs are placed.
   _symbol_artifact_root = "$root_out_dir/symbol_artifacts"
 
+  # Create a manifest of symbol archives for downstream consumption.
+  _symbol_tarballs = [
+    "$root_gen_dir/fuchsia/engine/chromium/chromium.symbols.tar.bz2",
+    "$root_gen_dir/fuchsia/http/http/http.symbols.tar.bz2",
+    "$root_gen_dir/fuchsia/runners/cast_runner/cast_runner.symbols.tar.bz2",
+    "$root_gen_dir/fuchsia/runners/web_runner/web_runner.symbols.tar.bz2",
+  ]
+  _symbol_manifest = "$target_gen_dir/debug_symbols.json"
+  write_file(_symbol_manifest, _symbol_tarballs, "json")
+
   copy("symbol_tarballs") {
     sources = [
+      _symbol_manifest,
       "$_release_artifact_root/build_id.txt",
-      "$root_gen_dir/fuchsia/engine/chromium/chromium.symbols.tar.bz2",
-      "$root_gen_dir/fuchsia/http/http/http.symbols.tar.bz2",
-      "$root_gen_dir/fuchsia/runners/cast_runner/cast_runner.symbols.tar.bz2",
-      "$root_gen_dir/fuchsia/runners/web_runner/web_runner.symbols.tar.bz2",
       _license_path,
-    ]
+    ] + _symbol_tarballs
     outputs = [
       "$_symbol_artifact_root/{{source_file_part}}",
     ]
diff --git a/fuchsia/engine/context_provider_impl_unittest.cc b/fuchsia/engine/context_provider_impl_unittest.cc
index f9ac8e2..1f1aa778 100644
--- a/fuchsia/engine/context_provider_impl_unittest.cc
+++ b/fuchsia/engine/context_provider_impl_unittest.cc
@@ -273,10 +273,7 @@
 
   // Pass a handle data dir to the context.
   create_params.set_data_directory(
-      fidl::InterfaceHandle<fuchsia::io::Directory>(
-          zx::channel(base::fuchsia::GetHandleFromFile(
-              base::File(profile_temp_dir.GetPath(),
-                         base::File::FLAG_OPEN | base::File::FLAG_READ)))));
+      base::fuchsia::OpenDirectory(profile_temp_dir.GetPath()));
 
   provider_ptr_->Create(std::move(create_params), context.NewRequest());
 
@@ -305,10 +302,7 @@
 
   // Pass a handle data dir to the context.
   create_params.set_data_directory(
-      fidl::InterfaceHandle<fuchsia::io::Directory>(
-          zx::channel(base::fuchsia::GetHandleFromFile(
-              base::File(profile_temp_dir.GetPath(),
-                         base::File::FLAG_OPEN | base::File::FLAG_READ)))));
+      base::fuchsia::OpenDirectory(profile_temp_dir.GetPath()));
 
   provider_ptr_->Create2(std::move(create_params), context.NewRequest());
 
@@ -329,10 +323,7 @@
   // Pass in a handle to a file instead of a directory.
   CHECK(base::CreateTemporaryFile(&temp_file_path));
   create_params.set_data_directory(
-      fidl::InterfaceHandle<fuchsia::io::Directory>(
-          zx::channel(base::fuchsia::GetHandleFromFile(
-              base::File(temp_file_path,
-                         base::File::FLAG_OPEN | base::File::FLAG_READ)))));
+      base::fuchsia::OpenDirectory(temp_file_path));
 
   provider_ptr_->Create(std::move(create_params), context.NewRequest());
 
diff --git a/fuchsia/runners/common/web_content_runner.cc b/fuchsia/runners/common/web_content_runner.cc
index f5889f0..80b9a91 100644
--- a/fuchsia/runners/common/web_content_runner.cc
+++ b/fuchsia/runners/common/web_content_runner.cc
@@ -23,11 +23,9 @@
 
 namespace {
 
-fidl::InterfaceHandle<fuchsia::io::Directory> OpenDirectory(
+fidl::InterfaceHandle<fuchsia::io::Directory> OpenDirectoryOrFail(
     const base::FilePath& path) {
-  fidl::InterfaceHandle<fuchsia::io::Directory> directory(
-      zx::channel(base::fuchsia::GetHandleFromFile(
-          base::File(path, base::File::FLAG_OPEN | base::File::FLAG_READ))));
+  auto directory = base::fuchsia::OpenDirectory(path);
   CHECK(directory) << "Failed to open " << path;
   return directory;
 }
@@ -41,8 +39,8 @@
   chromium::web::CreateContextParams2 create_params;
 
   // Pass /svc and /data to the context.
-  create_params.set_service_directory(
-      OpenDirectory(base::FilePath(base::fuchsia::kServiceDirectoryPath)));
+  create_params.set_service_directory(OpenDirectoryOrFail(
+      base::FilePath(base::fuchsia::kServiceDirectoryPath)));
   if (data_directory)
     create_params.set_data_directory(std::move(data_directory));
 
@@ -62,8 +60,8 @@
 
 // static
 chromium::web::ContextPtr WebContentRunner::CreateDefaultWebContext() {
-  return CreateWebContextWithDataDirectory(
-      OpenDirectory(base::FilePath("/data")));
+  return CreateWebContextWithDataDirectory(OpenDirectoryOrFail(
+      base::FilePath(base::fuchsia::kPersistedDataDirectoryPath)));
 }
 
 // static
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc
index bfb51bc..c269604 100644
--- a/gpu/command_buffer/service/webgpu_decoder_impl.cc
+++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -346,7 +346,14 @@
                                              dawn_procs_,
                                              wire_serializer_.get())) {}
 
-WebGPUDecoderImpl::~WebGPUDecoderImpl() {}
+WebGPUDecoderImpl::~WebGPUDecoderImpl() {
+  // Reset the wire server first so all objects are destroyed before the device.
+  // TODO(enga): Handle Device/Context lost.
+  wire_server_ = nullptr;
+  if (dawn_device_ != nullptr) {
+    dawn_procs_.deviceRelease(dawn_device_);
+  }
+}
 
 DawnDevice WebGPUDecoderImpl::CreateDefaultDevice() {
   dawn_instance_->DiscoverDefaultAdapters();
diff --git a/gpu/command_buffer/tests/fuzzer_main.cc b/gpu/command_buffer/tests/fuzzer_main.cc
index 3fa7dad..32411622 100644
--- a/gpu/command_buffer/tests/fuzzer_main.cc
+++ b/gpu/command_buffer/tests/fuzzer_main.cc
@@ -422,6 +422,7 @@
                                        config_.attrib_helper);
     if (result != gpu::ContextResult::kSuccess)
       return false;
+    decoder_initialized_ = true;
 
     command_buffer_->set_handler(decoder_.get());
     InitializeInitialCommandBuffer();
@@ -430,7 +431,6 @@
 #if !defined(GPU_FUZZER_USE_RASTER_DECODER)
     context_group->buffer_manager()->set_max_buffer_size(8 << 20);
 #endif
-    decoder_initialized_ = true;
     return decoder_->MakeCurrent();
   }
 
@@ -454,10 +454,16 @@
       if (!context_lost)
         context_lost = decoder_initialized_ && decoder_->CheckResetStatus();
 
-      shared_image_factory_->DestroyAllSharedImages(!context_lost);
-      decoder_->Destroy(!context_lost);
+      // If |decoder_->Initialize(...)| was unsuccessful, |decoder_| would have
+      // already called Destroy.
+      if (decoder_initialized_)
+        decoder_->Destroy(!context_lost);
       decoder_.reset();
 
+      if (!context_lost)
+        context_state_->MakeCurrent(nullptr);
+      shared_image_factory_->DestroyAllSharedImages(!context_lost);
+
       shared_image_factory_.reset();
       shared_image_manager_.reset();
       context_state_.reset();
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json
index fc78b4d4..c02208ca 100644
--- a/gpu/config/gpu_driver_bug_list.json
+++ b/gpu/config/gpu_driver_bug_list.json
@@ -3245,6 +3245,19 @@
       "features": [
         "disable_aimagereader"
       ]
+    },
+    {
+      "id": 299,
+      "description": "Context lost recovery often fails on PowerVR Rogue GE8* GPUs on Android.",
+      "cr_bugs": [942106],
+      "os": {
+        "type": "android"
+      },
+      "gl_vendor": "Imagination.*",
+      "gl_renderer": "PowerVR Rogue GE8.*",
+      "features": [
+        "exit_on_context_lost"
+      ]
     }
   ]
 }
diff --git a/gpu/ipc/common/gpu_memory_buffer_support.cc b/gpu/ipc/common/gpu_memory_buffer_support.cc
index e2b9183..d3c752c 100644
--- a/gpu/ipc/common/gpu_memory_buffer_support.cc
+++ b/gpu/ipc/common/gpu_memory_buffer_support.cc
@@ -95,7 +95,8 @@
     case gfx::BufferUsage::GPU_READ:
     case gfx::BufferUsage::SCANOUT:
       return format == gfx::BufferFormat::RGBA_8888 ||
-             format == gfx::BufferFormat::RGBX_8888;
+             format == gfx::BufferFormat::RGBX_8888 ||
+             format == gfx::BufferFormat::BGR_565;
     case gfx::BufferUsage::SCANOUT_CPU_READ_WRITE:
     case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE:
     case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT:
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index 6602352..b9fbbb3 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -783,6 +783,13 @@
     }
 
     builders {
+      name: "Android FYI Release (Pixel 2)"
+      mixins: "android-gpu-fyi-ci"
+      # Increase timeout to allow tryjobs against small number of phones.
+      mixins: "gpu-slow-bot"
+    }
+
+    builders {
       name: "Android Release (Nexus 5X)"
       mixins: "android-gpu-ci"
     }
@@ -1049,6 +1056,14 @@
     }
 
     builders {
+      name: "linux-chromeos-code-coverage"
+      mixins: "code-coverage"
+      mixins: "fyi-ci"
+      mixins: "linux"
+      dimensions: "cores:32"
+    }
+
+    builders {
       name: "linux-chromeos-dbg"
       mixins: "chromeos-ci"
     }
@@ -3164,6 +3179,10 @@
     }
     builders {
       mixins: "android-gpu-manual-try"
+      name: "gpu-manual-try-android-p-pixel-2-32"
+    }
+    builders {
+      mixins: "android-gpu-manual-try"
       name: "gpu-manual-try-android-p-pixel-2-32-vk"
     }
     builders {
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index be523174..d16f2570 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -2489,6 +2489,11 @@
     short_name: "vm"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/linux-chromeos-code-coverage"
+    category: "code_coverage"
+    short_name: "lcr"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/mac-code-coverage-generation"
     category: "code_coverage"
     short_name: "mac"
@@ -3327,6 +3332,11 @@
     short_name: "STV"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/Android FYI Release (Pixel 2)"
+    category: "Android|P64|QCOM"
+    short_name: "P2"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/Android FYI 32 Vk Release (Nexus 5X)"
     category: "Android|vk|O32"
     short_name: "N5X"
@@ -3900,6 +3910,9 @@
     name: "buildbucket/luci.chromium.try/gpu-manual-try-android-n-nvidia-shield-tv-64"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-2-32"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-2-32-vk"
   }
   builders {
@@ -4497,25 +4510,28 @@
     name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-2-32"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-2-32-deqp"
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-2-32-vk"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-2-64"
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-2-32-deqp-vk"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-2-64-deqp"
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-2-64-vk"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-32"
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-2-64-deqp-vk"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-32-deqp"
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-32-vk"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-64"
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-32-deqp-vk"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-64-deqp"
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-64-vk"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.try/gpu-manual-try-android-p-pixel-xl-64-deqp-vk"
   }
   builders {
     name: "buildbucket/luci.chromium.try/gpu_manual_try_win7_nvidia_rel"
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg
index d25de57..bfbcf49 100644
--- a/infra/config/luci-scheduler.cfg
+++ b/infra/config/luci-scheduler.cfg
@@ -91,6 +91,7 @@
   triggers: "Android FYI Release (Nexus 6)"
   triggers: "Android FYI Release (Nexus 6P)"
   triggers: "Android FYI Release (Nexus 9)"
+  triggers: "Android FYI Release (Pixel 2)"
   triggers: "Android FYI dEQP Release (Nexus 5X)"
   triggers: "Android Release (Nexus 5X)"
   triggers: "Android arm Builder (dbg)"
@@ -333,6 +334,7 @@
   triggers: "linux-blink-animation-use-time-delta"
   triggers: "linux-blink-heap-incremental-marking"
   triggers: "linux-blink-heap-verification"
+  triggers: "linux-chromeos-code-coverage"
   triggers: "linux-chromeos-dbg"
   triggers: "linux-chromeos-rel"
   triggers: "linux-chromium-tests-staging-builder"
@@ -631,6 +633,16 @@
 }
 
 job {
+  id: "Android FYI Release (Pixel 2)"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Android FYI Release (Pixel 2)"
+  }
+}
+
+job {
   id: "Android Release (Nexus 5X)"
   acl_sets: "default"
   buildbucket: {
@@ -1161,6 +1173,16 @@
 }
 
 job {
+  id: "linux-chromeos-code-coverage"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "linux-chromeos-code-coverage"
+  }
+}
+
+job {
   id: "linux-chromeos-dbg"
   acl_sets: "default"
   buildbucket: {
diff --git a/ios/build/bots/scripts/test_runner.py b/ios/build/bots/scripts/test_runner.py
index 0e832685..6a98159 100644
--- a/ios/build/bots/scripts/test_runner.py
+++ b/ios/build/bots/scripts/test_runner.py
@@ -166,7 +166,9 @@
         LOGGER.info(
             'Process iossim is still alive! Xcodebuild process might block it.')
         xcodebuild_processes = [
-            p for p in psutil.process_iter() if 'xcodebuild' == p.info['name']]
+            p for p in psutil.process_iter()
+            # Use as_dict() to avoid API changes across versions of psutil.
+            if 'xcodebuild' == p.as_dict(attrs=['name'])['name']]
         if not xcodebuild_processes:
           LOGGER.debug('There are no running xcodebuild processes.')
           break
diff --git a/ios/chrome/app/chrome_exe_main.mm b/ios/chrome/app/chrome_exe_main.mm
index dff54905..a81cc5c2 100644
--- a/ios/chrome/app/chrome_exe_main.mm
+++ b/ios/chrome/app/chrome_exe_main.mm
@@ -43,6 +43,18 @@
   }
 }
 
+void SetUILanguageIfLanguageIsSelected() {
+  @autoreleasepool {
+    NSUserDefaults* standard_defaults = [NSUserDefaults standardUserDefaults];
+    NSString* language = [standard_defaults valueForKey:@"UILanguageOverride"];
+    if (!language || [language length] == 0) {
+      [standard_defaults removeObjectForKey:@"AppleLanguages"];
+    } else {
+      [standard_defaults setObject:@[ language ] forKey:@"AppleLanguages"];
+    }
+  }
+}
+
 int RunUIApplicationMain(int argc, char* argv[]) {
   @autoreleasepool {
     // Fetch the name of the UIApplication delegate stored in the application
@@ -64,6 +76,9 @@
   // Set NSUserDefaults keys to force pseudo-RTL if needed.
   SetTextDirectionIfPseudoRTLEnabled();
 
+  // Set NSUserDefaults keys to force the UI language if needed.
+  SetUILanguageIfLanguageIsSelected();
+
   // Create this here since it's needed to start the crash handler.
   base::AtExitManager at_exit;
 
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 185b7aa..d68a31c5 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -123,7 +123,6 @@
     "//ios/chrome/browser/browsing_data:feature_flags",
     "//ios/chrome/browser/crash_report:flags",
     "//ios/chrome/browser/download",
-    "//ios/chrome/browser/download:features",
     "//ios/chrome/browser/drag_and_drop",
     "//ios/chrome/browser/find_in_page:feature_flags",
     "//ios/chrome/browser/itunes_urls",
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index 0975282..5f25107 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -49,7 +49,6 @@
 #include "ios/chrome/browser/browsing_data/browsing_data_features.h"
 #include "ios/chrome/browser/chrome_switches.h"
 #include "ios/chrome/browser/crash_report/crash_report_flags.h"
-#include "ios/chrome/browser/download/features.h"
 #include "ios/chrome/browser/drag_and_drop/drag_and_drop_flag.h"
 #include "ios/chrome/browser/find_in_page/features.h"
 #include "ios/chrome/browser/ios_chrome_flag_descriptions.h"
@@ -233,9 +232,6 @@
          feature_engagement::kIPHDemoMode,
          feature_engagement::kIPHDemoModeChoiceVariations,
          "IPH_DemoMode")},
-    {"preview-usdz", flag_descriptions::kUsdzPreviewName,
-     flag_descriptions::kUsdzPreviewDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(download::kUsdzPreview)},
     {"use-ddljson-api", flag_descriptions::kUseDdljsonApiName,
      flag_descriptions::kUseDdljsonApiDescription, flags_ui::kOsIos,
      MULTI_VALUE_TYPE(kUseDdljsonApiChoices)},
diff --git a/ios/chrome/browser/download/browser_download_service_unittest.mm b/ios/chrome/browser/download/browser_download_service_unittest.mm
index 755fa5e..9e12991fa 100644
--- a/ios/chrome/browser/download/browser_download_service_unittest.mm
+++ b/ios/chrome/browser/download/browser_download_service_unittest.mm
@@ -8,7 +8,6 @@
 
 #include "base/macros.h"
 #include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #import "ios/chrome/browser/download/ar_quick_look_tab_helper.h"
 #import "ios/chrome/browser/download/download_manager_tab_helper.h"
@@ -92,8 +91,6 @@
  protected:
   BrowserDownloadServiceTest()
       : browser_state_(browser_state_builder_.Build()) {
-    scoped_feature_list_.InitAndEnableFeature(download::kUsdzPreview);
-
     StubTabHelper<PassKitTabHelper>::CreateForWebState(&web_state_);
     TestARQuickLookTabHelper::CreateForWebState(&web_state_);
     StubTabHelper<DownloadManagerTabHelper>::CreateForWebState(&web_state_);
@@ -140,7 +137,6 @@
   std::unique_ptr<BrowserDownloadService> service_;
   web::TestWebState web_state_;
   base::HistogramTester histogram_tester_;
-  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 // Tests that BrowserDownloadService downloads the task using
diff --git a/ios/chrome/browser/download/features.h b/ios/chrome/browser/download/features.h
index aabd567..091010a 100644
--- a/ios/chrome/browser/download/features.h
+++ b/ios/chrome/browser/download/features.h
@@ -5,12 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_DOWNLOAD_FEATURES_H_
 #define IOS_CHROME_BROWSER_DOWNLOAD_FEATURES_H_
 
-#include "base/feature_list.h"
-
 namespace download {
 
-extern const base::Feature kUsdzPreview;
-
 // Returns whether USDZ AR Quick Look is enabled.
 bool IsUsdzPreviewEnabled();
 
diff --git a/ios/chrome/browser/download/features.mm b/ios/chrome/browser/download/features.mm
index f2701e21..97a0fa7 100644
--- a/ios/chrome/browser/download/features.mm
+++ b/ios/chrome/browser/download/features.mm
@@ -12,14 +12,10 @@
 
 namespace download {
 
-// Controls previewing USDZ format 3D models in AR Quick Look.
-const base::Feature kUsdzPreview{"USDZPreview",
-                                 base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Returns whether AR Quick Look in enabled.
 bool IsUsdzPreviewEnabled() {
   if (@available(iOS 12, *)) {
-    return base::FeatureList::IsEnabled(kUsdzPreview);
+    return true;
   }
   return false;
 }
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
index f34b61c..3e771ce 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -410,10 +410,6 @@
 const char kUseNSURLSessionForGaiaSigninRequestsDescription[] =
     "Use NSURLSession to make sign-in requests to Gaia";
 
-const char kUsdzPreviewName[] = "Preview USDZ format 3D models";
-const char kUsdzPreviewDescription[] =
-    "Enables previewing USDZ format 3D models in AR Quick Look.";
-
 const char kUseDdljsonApiName[] = "Use new ddljson API for Doodles";
 const char kUseDdljsonApiDescription[] =
     "Enables the new ddljson API to fetch Doodles for the NTP.";
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h
index 06ca48d..ee15099 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -340,10 +340,6 @@
 extern const char kUseNSURLSessionForGaiaSigninRequestsName[];
 extern const char kUseNSURLSessionForGaiaSigninRequestsDescription[];
 
-// Title and description for the flag to enable previewing USDZ 3 model files.
-extern const char kUsdzPreviewName[];
-extern const char kUsdzPreviewDescription[];
-
 // Title and description for the flag to enable the ddljson Doodle API.
 extern const char kUseDdljsonApiName[];
 extern const char kUseDdljsonApiDescription[];
diff --git a/ios/chrome/browser/net/cookie_util.mm b/ios/chrome/browser/net/cookie_util.mm
index 3192182..2e30e56 100644
--- a/ios/chrome/browser/net/cookie_util.mm
+++ b/ios/chrome/browser/net/cookie_util.mm
@@ -58,8 +58,7 @@
     net::NetLog* net_log) {
   if (config.path.empty()) {
     // Empty path means in-memory store.
-    return std::make_unique<net::CookieMonster>(
-        nullptr /* store */, nullptr /* channel_id_service */, net_log);
+    return std::make_unique<net::CookieMonster>(nullptr /* store */, net_log);
   }
 
   const bool restore_old_session_cookies =
@@ -67,8 +66,8 @@
   scoped_refptr<net::SQLitePersistentCookieStore> persistent_store =
       CreatePersistentCookieStore(config.path, restore_old_session_cookies,
                                   config.crypto_delegate);
-  std::unique_ptr<net::CookieMonster> cookie_monster(new net::CookieMonster(
-      persistent_store.get(), nullptr /* channel_id_service */, net_log));
+  std::unique_ptr<net::CookieMonster> cookie_monster(
+      new net::CookieMonster(persistent_store.get(), net_log));
   if (restore_old_session_cookies)
     cookie_monster->SetPersistSessionCookies(true);
   return cookie_monster;
diff --git a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
index 752b7a4..d4bc3147 100644
--- a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
+++ b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
@@ -54,6 +54,34 @@
 		</dict>
 		<dict>
 			<key>Type</key>
+			<string>PSMultiValueSpecifier</string>
+			<key>Title</key>
+			<string>Force Language</string>
+			<key>Key</key>
+			<string>UILanguageOverride</string>
+			<key>DefaultValue</key>
+			<string></string>
+			<key>Values</key>
+			<array>
+				<string></string>
+				<string>ar</string>
+				<string>en</string>
+				<string>fr</string>
+				<string>he</string>
+				<string>hi</string>
+			</array>
+			<key>Titles</key>
+			<array>
+				<string>Default</string>
+				<string>Arabic</string>
+				<string>English</string>
+				<string>French</string>
+				<string>Hebrew</string>
+				<string>Hindi</string>
+			</array>
+		</dict>
+		<dict>
+			<key>Type</key>
 			<string>PSGroupSpecifier</string>
 			<key>Title</key>
 			<string>Debug Settings</string>
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
index 7e3dd78..39aa1e6 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
@@ -270,10 +270,12 @@
 - (void)focusOmniboxFromSearchButton {
   // TODO(crbug.com/931284): Temporary workaround for intermediate broken state
   // in the NTP.  Remove this once crbug.com/899827 is fixed.
-  NewTabPageTabHelper* NTPHelper =
-      NewTabPageTabHelper::FromWebState(self.webState);
-  if (NTPHelper && NTPHelper->IsActive() && NTPHelper->IgnoreLoadRequests()) {
-    return;
+  if (self.webState) {
+    NewTabPageTabHelper* NTPHelper =
+        NewTabPageTabHelper::FromWebState(self.webState);
+    if (NTPHelper && NTPHelper->IsActive() && NTPHelper->IgnoreLoadRequests()) {
+      return;
+    }
   }
   [self.omniboxCoordinator setNextFocusSourceAsSearchButton];
   [self focusOmnibox];
@@ -286,10 +288,12 @@
 - (void)focusOmnibox {
   // TODO(crbug.com/931284): Temporary workaround for intermediate broken state
   // in the NTP.  Remove this once crbug.com/899827 is fixed.
-  NewTabPageTabHelper* NTPHelper =
-      NewTabPageTabHelper::FromWebState(self.webState);
-  if (NTPHelper && NTPHelper->IsActive() && NTPHelper->IgnoreLoadRequests()) {
-    return;
+  if (self.webState) {
+    NewTabPageTabHelper* NTPHelper =
+        NewTabPageTabHelper::FromWebState(self.webState);
+    if (NTPHelper && NTPHelper->IsActive() && NTPHelper->IgnoreLoadRequests()) {
+      return;
+    }
   }
   // Dismiss the edit menu.
   [[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO];
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.h b/ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.h
index 79970af..63d484a0 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.h
+++ b/ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.h
@@ -29,7 +29,9 @@
       const base::string16& formatted_url) const override;
   bool GetURL(GURL* url) const override;
   bool ShouldDisplayURL() const override;
-  void GetSecurityInfo(security_state::SecurityInfo* result) const override;
+  security_state::SecurityLevel GetSecurityLevel() const override;
+  std::unique_ptr<security_state::VisibleSecurityState>
+  GetVisibleSecurityState() const override;
   scoped_refptr<net::X509Certificate> GetCertificate() const override;
   const gfx::VectorIcon* GetVectorIconOverride() const override;
   bool IsOfflinePage() const override;
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.mm b/ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.mm
index 6c3002f..c3753085 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.mm
@@ -76,17 +76,28 @@
   return true;
 }
 
-void LocationBarModelDelegateIOS::GetSecurityInfo(
-    security_state::SecurityInfo* result) const {
+security_state::SecurityLevel LocationBarModelDelegateIOS::GetSecurityLevel()
+    const {
   web::WebState* web_state = GetActiveWebState();
   // If there is no active WebState (which can happen during toolbar
   // initialization), assume no security style.
   if (!web_state) {
-    *result = security_state::SecurityInfo();
-    return;
+    return security_state::NONE;
   }
   auto* client = IOSSecurityStateTabHelper::FromWebState(web_state);
-  client->GetSecurityInfo(result);
+  return client->GetSecurityLevel();
+}
+
+std::unique_ptr<security_state::VisibleSecurityState>
+LocationBarModelDelegateIOS::GetVisibleSecurityState() const {
+  web::WebState* web_state = GetActiveWebState();
+  // If there is no active WebState (which can happen during toolbar
+  // initialization), assume no security style.
+  if (!web_state) {
+    return std::make_unique<security_state::VisibleSecurityState>();
+  }
+  auto* client = IOSSecurityStateTabHelper::FromWebState(web_state);
+  return client->GetVisibleSecurityState();
 }
 
 scoped_refptr<net::X509Certificate>
diff --git a/ios/components/io_thread/ios_io_thread.mm b/ios/components/io_thread/ios_io_thread.mm
index a795a6a..2e85b7d 100644
--- a/ios/components/io_thread/ios_io_thread.mm
+++ b/ios/components/io_thread/ios_io_thread.mm
@@ -258,9 +258,8 @@
   globals_->http_server_properties.reset(new net::HttpServerPropertiesImpl());
   // In-memory cookie store.
   // TODO(crbug.com/801910): Hook up logging by passing in a non-null netlog.
-  globals_->system_cookie_store.reset(new net::CookieMonster(
-      nullptr /* store */, nullptr /* channel_id_service */,
-      nullptr /* netlog */));
+  globals_->system_cookie_store.reset(
+      new net::CookieMonster(nullptr /* store */, nullptr /* netlog */));
   // In-memory channel ID store.
   globals_->system_channel_id_service.reset(
       new net::ChannelIDService(new net::DefaultChannelIDStore(nullptr)));
diff --git a/ios/net/cookies/cookie_store_ios.mm b/ios/net/cookies/cookie_store_ios.mm
index 92df7be..5bc35f4 100644
--- a/ios/net/cookies/cookie_store_ios.mm
+++ b/ios/net/cookies/cookie_store_ios.mm
@@ -501,7 +501,6 @@
     std::unique_ptr<SystemCookieStore> system_store,
     NetLog* net_log)
     : cookie_monster_(new net::CookieMonster(persistent_store,
-                                             nullptr /* channel_id_service */,
                                              net_log)),
       system_store_(std::move(system_store)),
       metrics_enabled_(false),
diff --git a/ios/third_party/edo/BUILD.gn b/ios/third_party/edo/BUILD.gn
index 3c136d4..ea2663b 100644
--- a/ios/third_party/edo/BUILD.gn
+++ b/ios/third_party/edo/BUILD.gn
@@ -13,25 +13,48 @@
 
   sources = [
     "src/Channel/Sources/EDOChannel.h",
+    "src/Channel/Sources/EDOChannelPool.h",
+    "src/Channel/Sources/EDOChannelPool.m",
+    "src/Channel/Sources/EDOChannelUtil.h",
+    "src/Channel/Sources/EDOChannelUtil.m",
+    "src/Channel/Sources/EDOHostPort.h",
+    "src/Channel/Sources/EDOHostPort.m",
     "src/Channel/Sources/EDOListenSocket.h",
     "src/Channel/Sources/EDOListenSocket.m",
     "src/Channel/Sources/EDOSocket.h",
     "src/Channel/Sources/EDOSocket.m",
     "src/Channel/Sources/EDOSocketChannel.h",
     "src/Channel/Sources/EDOSocketChannel.m",
-    "src/Channel/Sources/EDOSocketChannelPool.h",
-    "src/Channel/Sources/EDOSocketChannelPool.m",
     "src/Channel/Sources/EDOSocketPort.h",
     "src/Channel/Sources/EDOSocketPort.m",
+    "src/Device/Sources/EDODeviceChannel.h",
+    "src/Device/Sources/EDODeviceChannel.m",
+    "src/Device/Sources/EDODeviceConnector.h",
+    "src/Device/Sources/EDODeviceConnector.m",
+    "src/Device/Sources/EDODeviceDetector.h",
+    "src/Device/Sources/EDODeviceDetector.m",
+    "src/Device/Sources/EDOUSBMuxUtil.h",
+    "src/Device/Sources/EDOUSBMuxUtil.m",
+    "src/Measure/Sources/EDONumericMeasure.h",
+    "src/Measure/Sources/EDONumericMeasure.m",
     "src/Service/Sources/EDOBlockObject.h",
     "src/Service/Sources/EDOBlockObject.m",
     "src/Service/Sources/EDOClassMessage.h",
     "src/Service/Sources/EDOClassMessage.m",
+    "src/Service/Sources/EDOClientService+Device.h",
     "src/Service/Sources/EDOClientService+Private.h",
     "src/Service/Sources/EDOClientService.h",
     "src/Service/Sources/EDOClientService.m",
+    "src/Service/Sources/EDOClientServiceStatsCollector.h",
+    "src/Service/Sources/EDOClientServiceStatsCollector.m",
     "src/Service/Sources/EDOExecutor.h",
     "src/Service/Sources/EDOExecutor.m",
+    "src/Service/Sources/EDOExecutorMessage.h",
+    "src/Service/Sources/EDOExecutorMessage.m",
+    "src/Service/Sources/EDOHostNamingService+Private.h",
+    "src/Service/Sources/EDOHostNamingService.h",
+    "src/Service/Sources/EDOHostNamingService.m",
+    "src/Service/Sources/EDOHostService+Device.h",
     "src/Service/Sources/EDOHostService+Handlers.h",
     "src/Service/Sources/EDOHostService+Handlers.m",
     "src/Service/Sources/EDOHostService+Private.h",
@@ -66,11 +89,17 @@
     "src/Service/Sources/EDOServicePort.m",
     "src/Service/Sources/EDOServiceRequest.h",
     "src/Service/Sources/EDOServiceRequest.m",
+    "src/Service/Sources/EDOTimingFunctions.h",
+    "src/Service/Sources/EDOTimingFunctions.m",
     "src/Service/Sources/EDOValueObject+EDOParameter.m",
     "src/Service/Sources/EDOValueObject.h",
     "src/Service/Sources/EDOValueObject.m",
     "src/Service/Sources/EDOValueType.m",
     "src/Service/Sources/NSBlock+EDOInvocation.m",
+    "src/Service/Sources/NSKeyedArchiver+EDOAdditions.h",
+    "src/Service/Sources/NSKeyedArchiver+EDOAdditions.m",
+    "src/Service/Sources/NSKeyedUnarchiver+EDOAdditions.h",
+    "src/Service/Sources/NSKeyedUnarchiver+EDOAdditions.m",
     "src/Service/Sources/NSObject+EDOParameter.h",
     "src/Service/Sources/NSObject+EDOParameter.m",
     "src/Service/Sources/NSObject+EDOValue.h",
diff --git a/ios/web/navigation/legacy_navigation_manager_impl.mm b/ios/web/navigation/legacy_navigation_manager_impl.mm
index 0fd6212..cdde8a6 100644
--- a/ios/web/navigation/legacy_navigation_manager_impl.mm
+++ b/ios/web/navigation/legacy_navigation_manager_impl.mm
@@ -210,6 +210,9 @@
     int last_committed_item_index,
     std::vector<std::unique_ptr<NavigationItem>> items) {
   WillRestore(items.size());
+  for (size_t index = 0; index < items.size(); ++index) {
+    RewriteItemURLIfNecessary(items[index].get());
+  }
 
   DCHECK(GetItemCount() == 0 && !GetPendingItem());
   DCHECK_LT(last_committed_item_index, static_cast<int>(items.size()));
diff --git a/ios/web/public/origin_util.mm b/ios/web/public/origin_util.mm
index 570d1560..47ad181 100644
--- a/ios/web/public/origin_util.mm
+++ b/ios/web/public/origin_util.mm
@@ -19,6 +19,10 @@
   if (url.SchemeIsCryptographic() || url.SchemeIsFile())
     return true;
 
+  // TODO(crbug.com/939077): Also consider inner origins of blob: URLs
+  // (ideally, by deleting this function altogether and instead reusing
+  // //services/network/public/cpp/is_potentially_trustworthy.h (possibly after
+  // moving it to a location that can be consumed by //ios).
   if (url.SchemeIsFileSystem() && url.inner_url() &&
       IsOriginSecure(*url.inner_url())) {
     return true;
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 27dfc4732..2e6fb711 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -2049,6 +2049,10 @@
   ProceduralBlock defaultNavigationBlock = ^{
     web::NavigationItem* item = self.currentNavItem;
     GURL navigationURL = item ? item->GetURL() : GURL::EmptyGURL();
+    GURL virtualURL = item ? item->GetVirtualURL() : GURL::EmptyGURL();
+    // Set |item| to nullptr here to avoid any use-after-free issues, as it can
+    // be cleared by the call to -registerLoadRequestForURL below.
+    item = nullptr;
     GURL contextURL = IsPlaceholderUrl(navigationURL)
                           ? ExtractUrlFromPlaceholderUrl(navigationURL)
                           : navigationURL;
@@ -2062,7 +2066,6 @@
                   placeholderNavigation:IsPlaceholderUrl(navigationURL)];
 
     WKNavigation* navigation = nil;
-    GURL virtualURL = item ? item->GetVirtualURL() : GURL::EmptyGURL();
     if (navigationURL.SchemeIsFile() &&
         web::GetWebClient()->IsAppSpecificURL(virtualURL)) {
       // file:// URL navigations are allowed for app-specific URLs, which
diff --git a/ios/web_view/internal/web_view_browser_state.mm b/ios/web_view/internal/web_view_browser_state.mm
index fa0e21a..934ddf2 100644
--- a/ios/web_view/internal/web_view_browser_state.mm
+++ b/ios/web_view/internal/web_view_browser_state.mm
@@ -124,6 +124,11 @@
 #if BUILDFLAG(IOS_WEB_VIEW_ENABLE_SYNC)
   ActiveStateManager::FromBrowserState(this)->SetActive(false);
 #endif  // BUILDFLAG(IOS_WEB_VIEW_ENABLE_SYNC)
+
+  base::PostTaskWithTraits(
+      FROM_HERE, {web::WebThread::IO},
+      base::BindOnce(&WebViewURLRequestContextGetter::ShutDown,
+                     request_context_getter_));
 }
 
 PrefService* WebViewBrowserState::GetPrefs() {
diff --git a/ios/web_view/internal/web_view_url_request_context_getter.h b/ios/web_view/internal/web_view_url_request_context_getter.h
index d1bed19..c893c6284 100644
--- a/ios/web_view/internal/web_view_url_request_context_getter.h
+++ b/ios/web_view/internal/web_view_url_request_context_getter.h
@@ -36,6 +36,10 @@
   scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
       const override;
 
+  // Discard reference to URLRequestContext and inform observers of shutdown.
+  // Must be called before destruction. May only be called on IO thread.
+  void ShutDown();
+
  protected:
   ~WebViewURLRequestContextGetter() override;
 
@@ -50,6 +54,9 @@
   std::unique_ptr<net::TransportSecurityPersister>
       transport_security_persister_;
 
+  // Used to ensure GetURLRequestContext() returns nullptr during shut down.
+  bool is_shutting_down_;
+
   DISALLOW_COPY_AND_ASSIGN(WebViewURLRequestContextGetter);
 };
 
diff --git a/ios/web_view/internal/web_view_url_request_context_getter.mm b/ios/web_view/internal/web_view_url_request_context_getter.mm
index 3be9309..c0d482c7 100644
--- a/ios/web_view/internal/web_view_url_request_context_getter.mm
+++ b/ios/web_view/internal/web_view_url_request_context_getter.mm
@@ -51,13 +51,18 @@
       network_task_runner_(network_task_runner),
       proxy_config_service_(
           new net::ProxyConfigServiceIOS(NO_TRAFFIC_ANNOTATION_YET)),
-      net_log_(new net::NetLog()) {}
+      net_log_(new net::NetLog()),
+      is_shutting_down_(false) {}
 
 WebViewURLRequestContextGetter::~WebViewURLRequestContextGetter() = default;
 
 net::URLRequestContext* WebViewURLRequestContextGetter::GetURLRequestContext() {
   DCHECK(network_task_runner_->BelongsToCurrentThread());
 
+  if (is_shutting_down_) {
+    return nullptr;
+  }
+
   if (!url_request_context_) {
     url_request_context_.reset(new net::URLRequestContext());
     url_request_context_->set_net_log(net_log_.get());
@@ -173,4 +178,10 @@
   return network_task_runner_;
 }
 
+void WebViewURLRequestContextGetter::ShutDown() {
+  is_shutting_down_ = true;
+  url_request_context_.reset();
+  net::URLRequestContextGetter::NotifyContextShuttingDown();
+}
+
 }  // namespace ios_web_view
diff --git a/ios/web_view/internal/web_view_web_main_parts.mm b/ios/web_view/internal/web_view_web_main_parts.mm
index 06b549af..5b72df5 100644
--- a/ios/web_view/internal/web_view_web_main_parts.mm
+++ b/ios/web_view/internal/web_view_web_main_parts.mm
@@ -81,8 +81,11 @@
 
 void WebViewWebMainParts::PostMainMessageLoopRun() {
   WebViewTranslateService::GetInstance()->Shutdown();
-  ApplicationContext::GetInstance()->SaveState();
+
+  // CWVWebViewConfiguration must destroy its WebViewBrowserStates before the
+  // threads are stopped by ApplicationContext.
   [CWVWebViewConfiguration shutDown];
+  ApplicationContext::GetInstance()->SaveState();
 }
 
 void WebViewWebMainParts::PostDestroyThreads() {
diff --git a/jingle/glue/network_service_async_socket_unittest.cc b/jingle/glue/network_service_async_socket_unittest.cc
index eab01653..bb66f19 100644
--- a/jingle/glue/network_service_async_socket_unittest.cc
+++ b/jingle/glue/network_service_async_socket_unittest.cc
@@ -390,9 +390,10 @@
     }
 
     std::string ToString() const {
-      return base::StrCat(
-          {"(", base::IntToString(signal), ",", base::IntToString(state), ",",
-           base::IntToString(error), ",", base::IntToString(net_error), ")"});
+      return base::StrCat({"(", base::NumberToString(signal), ",",
+                           base::NumberToString(state), ",",
+                           base::NumberToString(error), ",",
+                           base::NumberToString(net_error), ")"});
     }
 
     Signal signal;
diff --git a/jingle/notifier/listener/xml_element_util.cc b/jingle/notifier/listener/xml_element_util.cc
index 63f4dff2..d058f90 100644
--- a/jingle/notifier/listener/xml_element_util.cc
+++ b/jingle/notifier/listener/xml_element_util.cc
@@ -35,7 +35,7 @@
   const jingle_xmpp::QName intAttrQName(jingle_xmpp::STR_EMPTY, "int");
   jingle_xmpp::XmlElement* int_xml_element =
       new jingle_xmpp::XmlElement(elementQName, true);
-  int_xml_element->AddAttr(intAttrQName, base::IntToString(value));
+  int_xml_element->AddAttr(intAttrQName, base::NumberToString(value));
   return int_xml_element;
 }
 
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index d96e904a..eef8c494 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -69,7 +69,6 @@
 #include "net/cookies/cookie_util.h"
 #include "net/cookies/parsed_cookie.h"
 #include "net/log/net_log.h"
-#include "net/ssl/channel_id_service.h"
 #include "url/origin.h"
 
 using base::Time;
@@ -337,24 +336,15 @@
 }  // namespace
 
 CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
-                             ChannelIDService* channel_id_service,
                              NetLog* net_log)
     : CookieMonster(
           std::move(store),
-          channel_id_service,
           base::TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds),
           net_log) {}
 
 CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
                              base::TimeDelta last_access_threshold,
                              NetLog* net_log)
-    : CookieMonster(std::move(store), nullptr, last_access_threshold, net_log) {
-}
-
-CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store,
-                             ChannelIDService* channel_id_service,
-                             base::TimeDelta last_access_threshold,
-                             NetLog* net_log)
     : initialized_(false),
       started_fetching_all_cookies_(false),
       finished_fetching_all_cookies_(false),
@@ -362,7 +352,6 @@
       net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::COOKIE_STORE)),
       store_(std::move(store)),
       last_access_threshold_(last_access_threshold),
-      channel_id_service_(channel_id_service),
       last_statistic_record_time_(base::Time::Now()),
       persist_session_cookies_(false),
       weak_ptr_factory_(this) {
@@ -370,21 +359,10 @@
   cookieable_schemes_.insert(
       cookieable_schemes_.begin(), kDefaultCookieableSchemes,
       kDefaultCookieableSchemes + kDefaultCookieableSchemesCount);
-  if (channel_id_service_ && store_) {
-    // |store_| can outlive this CookieMonster, but there are no guarantees
-    // about the lifetime of |channel_id_service_| relative to |store_|. The
-    // only guarantee is that |channel_id_service_| will outlive this
-    // CookieMonster. To avoid the PersistentCookieStore retaining a pointer to
-    // the ChannelIDStore via this callback after this CookieMonster is
-    // destroyed, CookieMonster's d'tor sets the callback to a null callback.
-    store_->SetBeforeCommitCallback(
-        base::Bind(&ChannelIDStore::Flush,
-                   base::Unretained(channel_id_service_->GetChannelIDStore())));
-  }
   net_log_.BeginEvent(
       NetLogEventType::COOKIE_STORE_ALIVE,
       base::BindRepeating(&NetLogCookieMonsterConstructorCallback,
-                          store != nullptr, channel_id_service != nullptr));
+                          store != nullptr));
 }
 
 // Asynchronous CookieMonster API
@@ -584,10 +562,6 @@
 CookieMonster::~CookieMonster() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  if (channel_id_service_ && store_) {
-    store_->SetBeforeCommitCallback(base::RepeatingClosure());
-  }
-
   // TODO(mmenke): Does it really make sense to run
   // CookieChanged callbacks when the CookieStore is destroyed?
   for (auto cookie_it = cookies_.begin(); cookie_it != cookies_.end();) {
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index d92c94b..d74a4dc 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -40,7 +40,6 @@
 
 namespace net {
 
-class ChannelIDService;
 class CookieChangeDispatcher;
 
 // The cookie monster is the system for storing and retrieving cookies. It has
@@ -131,12 +130,8 @@
   // class will take care of initializing it. The backing store is NOT owned by
   // this class, but it must remain valid for the duration of the cookie
   // monster's existence. If |store| is NULL, then no backing store will be
-  // updated. |channel_id_service| is a non-owninng pointer for the
-  // corresponding ChannelIDService used with this CookieStore. The
-  // |channel_id_service| must outlive the CookieMonster. |net_log| must outlive
-  // the CookieMonster. Both |channel_id_service| and |net_log| can be null.
+  // updated. |net_log| must outlive the CookieMonster and can be null.
   CookieMonster(scoped_refptr<PersistentCookieStore> store,
-                ChannelIDService* channel_id_service,
                 NetLog* net_log);
 
   // Only used during unit testing.
@@ -210,11 +205,6 @@
   static std::string GetKey(base::StringPiece domain);
 
  private:
-  CookieMonster(scoped_refptr<PersistentCookieStore> store,
-                ChannelIDService* channel_id_service,
-                base::TimeDelta last_access_threshold,
-                NetLog* net_log);
-
   // For garbage collection constants.
   FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestHostGarbageCollection);
   FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, GarbageCollectionTriggers);
@@ -631,8 +621,6 @@
 
   std::vector<std::string> cookieable_schemes_;
 
-  ChannelIDService* channel_id_service_;
-
   base::Time last_statistic_record_time_;
 
   bool persist_session_cookies_;
diff --git a/net/cookies/cookie_monster_netlog_params.cc b/net/cookies/cookie_monster_netlog_params.cc
index b4b17d28..dff8422 100644
--- a/net/cookies/cookie_monster_netlog_params.cc
+++ b/net/cookies/cookie_monster_netlog_params.cc
@@ -11,12 +11,10 @@
 
 std::unique_ptr<base::Value> NetLogCookieMonsterConstructorCallback(
     bool persistent_store,
-    bool channel_id_service,
     NetLogCaptureMode /* capture_mode */) {
   std::unique_ptr<base::Value> dict =
       std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
   dict->SetKey("persistent_store", base::Value(persistent_store));
-  dict->SetKey("channel_id_service", base::Value(channel_id_service));
   return dict;
 }
 
diff --git a/net/cookies/cookie_monster_netlog_params.h b/net/cookies/cookie_monster_netlog_params.h
index 8a5dc1f..16ab7727 100644
--- a/net/cookies/cookie_monster_netlog_params.h
+++ b/net/cookies/cookie_monster_netlog_params.h
@@ -20,7 +20,6 @@
 // a CookieMonster.
 std::unique_ptr<base::Value> NetLogCookieMonsterConstructorCallback(
     bool persistent_store,
-    bool channel_id_service,
     NetLogCaptureMode capture_mode);
 
 // Returns a Value containing NetLog parameters for adding a cookie.
diff --git a/net/cookies/cookie_monster_perftest.cc b/net/cookies/cookie_monster_perftest.cc
index b7c90ec..55e2cc72 100644
--- a/net/cookies/cookie_monster_perftest.cc
+++ b/net/cookies/cookie_monster_perftest.cc
@@ -137,7 +137,7 @@
 }
 
 TEST_F(CookieMonsterTest, TestAddCookiesOnSingleHost) {
-  auto cm = std::make_unique<CookieMonster>(nullptr, nullptr, nullptr);
+  auto cm = std::make_unique<CookieMonster>(nullptr, nullptr);
   std::vector<std::string> cookies;
   for (int i = 0; i < kNumCookies; i++) {
     cookies.push_back(base::StringPrintf("a%03d=b", i));
@@ -170,7 +170,7 @@
 }
 
 TEST_F(CookieMonsterTest, TestAddCookieOnManyHosts) {
-  auto cm = std::make_unique<CookieMonster>(nullptr, nullptr, nullptr);
+  auto cm = std::make_unique<CookieMonster>(nullptr, nullptr);
   std::string cookie(kCookieLine);
   std::vector<GURL> gurls;  // just wanna have ffffuunnn
   for (int i = 0; i < kNumCookies; ++i) {
@@ -203,7 +203,7 @@
 }
 
 TEST_F(CookieMonsterTest, TestDomainTree) {
-  auto cm = std::make_unique<CookieMonster>(nullptr, nullptr, nullptr);
+  auto cm = std::make_unique<CookieMonster>(nullptr, nullptr);
   GetCookieListCallback getCookieListCallback;
   SetCookieCallback setCookieCallback;
   const char domain_cookie_format_tree[] = "a=b; domain=%s";
@@ -259,7 +259,7 @@
 }
 
 TEST_F(CookieMonsterTest, TestDomainLine) {
-  auto cm = std::make_unique<CookieMonster>(nullptr, nullptr, nullptr);
+  auto cm = std::make_unique<CookieMonster>(nullptr, nullptr);
   SetCookieCallback setCookieCallback;
   GetCookieListCallback getCookieListCallback;
   std::vector<std::string> domain_list;
@@ -320,8 +320,7 @@
 
   store->SetLoadExpectation(true, std::move(initial_cookies));
 
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(store.get(), nullptr, nullptr));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr));
 
   // Import will happen on first access.
   GURL gurl("www.foo.com");
@@ -335,8 +334,7 @@
 }
 
 TEST_F(CookieMonsterTest, TestGetKey) {
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, nullptr));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr));
   base::PerfTimeLogger timer("Cookie_monster_get_key");
   for (int i = 0; i < kNumCookies; i++)
     cm->GetKey("www.foo.com");
diff --git a/net/cookies/cookie_monster_store_test.cc b/net/cookies/cookie_monster_store_test.cc
index c929043..6294399 100644
--- a/net/cookies/cookie_monster_store_test.cc
+++ b/net/cookies/cookie_monster_store_test.cc
@@ -238,7 +238,7 @@
     store->AddCookie(*cc);
   }
 
-  return std::make_unique<CookieMonster>(store.get(), nullptr, nullptr);
+  return std::make_unique<CookieMonster>(store.get(), nullptr);
 }
 
 MockSimplePersistentCookieStore::~MockSimplePersistentCookieStore() = default;
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 02521262..f833a47 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -97,7 +97,6 @@
 struct CookieMonsterTestTraits {
   static std::unique_ptr<CookieStore> Create() {
     return std::make_unique<CookieMonster>(nullptr /* store */,
-                                           nullptr /* channel_id_service */,
                                            nullptr /* netlog */);
   }
 
@@ -382,7 +381,7 @@
         (domain_max_cookies + domain_purge_cookies) * 2;
     // Add a bunch of cookies on a single host, should purge them.
     {
-      auto cm = std::make_unique<CookieMonster>(nullptr, nullptr, &net_log_);
+      auto cm = std::make_unique<CookieMonster>(nullptr, &net_log_);
       for (int i = 0; i < more_than_enough_cookies; ++i) {
         std::string cookie = base::StringPrintf("a%03d=b", i);
         EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), cookie));
@@ -399,7 +398,7 @@
     // between them.  We shouldn't go above kDomainMaxCookies for both together.
     GURL url_google_specific(http_www_foo_.Format("http://www.gmail.%D"));
     {
-      auto cm = std::make_unique<CookieMonster>(nullptr, nullptr, &net_log_);
+      auto cm = std::make_unique<CookieMonster>(nullptr, &net_log_);
       for (int i = 0; i < more_than_enough_cookies; ++i) {
         std::string cookie_general = base::StringPrintf("a%03d=b", i);
         EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), cookie_general));
@@ -576,7 +575,7 @@
     std::unique_ptr<CookieMonster> cm;
 
     if (alt_host_entries == nullptr) {
-      cm.reset(new CookieMonster(nullptr, nullptr, &net_log_));
+      cm.reset(new CookieMonster(nullptr, &net_log_));
     } else {
       // When generating all of these cookies on alternate hosts, they need to
       // be all older than the max "safe" date for GC, which is currently 30
@@ -621,7 +620,7 @@
     DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies -
                         CookieMonster::kDomainPurgeCookies);
 
-    auto cm = std::make_unique<CookieMonster>(nullptr, nullptr, &net_log_);
+    auto cm = std::make_unique<CookieMonster>(nullptr, &net_log_);
 
     // Each test case adds 181 cookies, so 31 cookies are evicted.
     // Cookie same priority, repeated for each priority.
@@ -684,7 +683,7 @@
     DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies -
                         CookieMonster::kDomainPurgeCookies);
 
-    auto cm = std::make_unique<CookieMonster>(nullptr, nullptr, &net_log_);
+    auto cm = std::make_unique<CookieMonster>(nullptr, &net_log_);
 
     // Each test case adds 181 cookies, so 31 cookies are evicted.
     // Cookie same priority, repeated for each priority.
@@ -741,7 +740,7 @@
     DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies -
                         CookieMonster::kDomainPurgeCookies);
 
-    auto cm = std::make_unique<CookieMonster>(nullptr, nullptr, &net_log_);
+    auto cm = std::make_unique<CookieMonster>(nullptr, &net_log_);
 
     // Each test case adds 180 secure cookies, and some non-secure cookie. The
     // secure cookies take priority, so the non-secure cookie is removed, along
@@ -847,7 +846,7 @@
   // Function for creating a CM with a number of cookies in it,
   // no store (and hence no ability to affect access time).
   CookieMonster* CreateMonsterForGC(int num_cookies) {
-    CookieMonster* cm(new CookieMonster(nullptr, nullptr, &net_log_));
+    CookieMonster* cm(new CookieMonster(nullptr, &net_log_));
     for (int i = 0; i < num_cookies; i++) {
       SetCookie(cm, GURL(base::StringPrintf("http://h%05d.izzle", i)), "a=1");
     }
@@ -967,8 +966,8 @@
  protected:
   DeferredCookieTaskTest() : expect_load_called_(false) {
     persistent_store_ = new NewMockPersistentCookieStore();
-    cookie_monster_ = std::make_unique<CookieMonster>(persistent_store_.get(),
-                                                      nullptr, &net_log_);
+    cookie_monster_ =
+        std::make_unique<CookieMonster>(persistent_store_.get(), &net_log_);
   }
 
   // Defines a cookie to be returned from PersistentCookieStore::Load
@@ -1352,8 +1351,7 @@
 
 TEST_F(CookieMonsterTest, TestCookieDeleteAll) {
   scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(store.get(), nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
   CookieOptions options;
   options.set_include_httponly();
 
@@ -1384,8 +1382,7 @@
 }
 
 TEST_F(CookieMonsterTest, TestCookieDeleteAllCreatedInTimeRangeTimestamps) {
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, &net_log_));
   Time now = Time::Now();
 
   // Nothing has been added so nothing should be deleted.
@@ -1432,8 +1429,7 @@
 
 TEST_F(CookieMonsterTest,
        TestCookieDeleteAllCreatedInTimeRangeTimestampsWithInfo) {
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, &net_log_));
   Time now = Time::Now();
 
   CanonicalCookie test_cookie;
@@ -1543,10 +1539,8 @@
 }
 
 TEST_F(CookieMonsterTest, SetCookieableSchemes) {
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, &net_log_));
-  std::unique_ptr<CookieMonster> cm_foo(
-      new CookieMonster(nullptr, nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm_foo(new CookieMonster(nullptr, &net_log_));
 
   // Only cm_foo should allow foo:// cookies.
   std::vector<std::string> schemes;
@@ -1739,8 +1733,7 @@
 }
 
 TEST_F(CookieMonsterTest, GetAllCookiesForURLPathMatching) {
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, &net_log_));
   CookieOptions options;
 
   EXPECT_TRUE(SetCookieWithOptions(cm.get(), www_foo_foo_.url(),
@@ -1778,8 +1771,7 @@
 }
 
 TEST_F(CookieMonsterTest, GetExcludedCookiesForURLPathMatching) {
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, &net_log_));
   CookieOptions options;
 
   EXPECT_TRUE(SetCookieWithOptions(cm.get(), www_foo_foo_.url(),
@@ -1814,8 +1806,7 @@
 }
 
 TEST_F(CookieMonsterTest, CookieSorting) {
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, &net_log_));
 
   EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "B=B1; path=/"));
   EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "B=B2; path=/foo"));
@@ -1839,8 +1830,7 @@
 }
 
 TEST_F(CookieMonsterTest, InheritCreationDate) {
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, &net_log_));
 
   base::Time the_not_so_distant_past(base::Time::Now() -
                                      base::TimeDelta::FromSeconds(1000));
@@ -1872,8 +1862,7 @@
 // Check that GetAllCookiesForURL() does not return expired cookies and deletes
 // them.
 TEST_F(CookieMonsterTest, DeleteExpiredCookiesOnGet) {
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, &net_log_));
 
   EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=B;"));
 
@@ -1945,8 +1934,7 @@
   // Inject our initial cookies into the mock PersistentCookieStore.
   store->SetLoadExpectation(true, std::move(initial_cookies));
 
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(store.get(), nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
 
   // Verify that duplicates were not imported for path "/".
   // (If this had failed, GetCookies() would have also returned X=1, X=2, X=4).
@@ -2002,8 +1990,7 @@
   // Inject our initial cookies into the mock PersistentCookieStore.
   store->SetLoadExpectation(true, std::move(initial_cookies));
 
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(store.get(), nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
 
   CookieList list(GetAllCookies(cm.get()));
   EXPECT_EQ(2U, list.size());
@@ -2016,8 +2003,7 @@
 }
 
 TEST_F(CookieMonsterTest, PredicateSeesAllCookies) {
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, &net_log_));
   PopulateCmForPredicateCheck(cm.get());
   // We test that we can see all cookies with |delete_info|. This includes
   // host, http_only, host secure, and all domain cookies.
@@ -2039,8 +2025,7 @@
 // Mainly a test of GetEffectiveDomain, or more specifically, of the
 // expected behavior of GetEffectiveDomain within the CookieMonster.
 TEST_F(CookieMonsterTest, GetKey) {
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, &net_log_));
 
   // This test is really only interesting if GetKey() actually does something.
   EXPECT_EQ("foo.com", cm->GetKey("www.foo.com"));
@@ -2085,7 +2070,7 @@
   // Create new cookies and flush them to the store.
   {
     std::unique_ptr<CookieMonster> cmout(
-        new CookieMonster(store.get(), nullptr, &net_log_));
+        new CookieMonster(store.get(), &net_log_));
     for (const auto& cookie : input_info) {
       EXPECT_TRUE(SetCanonicalCookie(
           cmout.get(),
@@ -2104,7 +2089,7 @@
   // Create a new cookie monster and make sure that everything is correct
   {
     std::unique_ptr<CookieMonster> cmin(
-        new CookieMonster(store.get(), nullptr, &net_log_));
+        new CookieMonster(store.get(), &net_log_));
     CookieList cookies(GetAllCookies(cmin.get()));
     ASSERT_EQ(2u, cookies.size());
     // Ordering is path length, then creation time.  So second cookie
@@ -2138,7 +2123,7 @@
       base::MakeRefCounted<MockPersistentCookieStore>();
 
   {
-    CookieMonster cmout(store.get(), nullptr, &net_log_);
+    CookieMonster cmout(store.get(), &net_log_);
     GURL url("http://www.example.com/");
     EXPECT_TRUE(
         SetCookieWithCreationTime(&cmout, url, "A=1; max-age=600", current));
@@ -2160,7 +2145,7 @@
 
   // Now read them in. Should get two cookies, not one.
   {
-    CookieMonster cmin(store2.get(), nullptr, &net_log_);
+    CookieMonster cmin(store2.get(), &net_log_);
     CookieList cookies(GetAllCookies(&cmin));
     ASSERT_EQ(2u, cookies.size());
   }
@@ -2169,8 +2154,7 @@
 TEST_F(CookieMonsterTest, CookieListOrdering) {
   // Put a random set of cookies into a monster and make sure
   // they're returned in the right order.
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, &net_log_));
   EXPECT_TRUE(
       SetCookie(cm.get(), GURL("http://d.c.b.a.foo.com/aa/x.html"), "c=1"));
   EXPECT_TRUE(SetCookie(cm.get(), GURL("http://b.a.foo.com/aa/bb/cc/x.html"),
@@ -2305,8 +2289,7 @@
 
   scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
   store->set_store_load_commands(true);
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(store.get(), nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
 
   // Get all cookies task that queues a task to set a cookie when executed.
   ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus>
@@ -2363,8 +2346,7 @@
 
   scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
   store->set_store_load_commands(true);
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(store.get(), nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
 
   ResultSavingCookieCallback<uint32_t> delete_callback;
   cm->DeleteAllAsync(base::BindOnce(&ResultSavingCookieCallback<uint32_t>::Run,
@@ -2404,8 +2386,7 @@
 
   scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
   store->set_store_load_commands(true);
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(store.get(), nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
 
   GetCookieListCallback get_cookie_list_callback1;
   cm->GetAllCookiesAsync(
@@ -2462,8 +2443,7 @@
 
   scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
   store->set_store_load_commands(true);
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(store.get(), nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
 
   // Get all cookies task that queues a task to set a cookie when executed.
   ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus>
@@ -2513,7 +2493,7 @@
 TEST_F(CookieMonsterTest, FlushStore) {
   auto counter = base::MakeRefCounted<CallbackCounter>();
   auto store = base::MakeRefCounted<FlushablePersistentStore>();
-  auto cm = std::make_unique<CookieMonster>(store, nullptr, &net_log_);
+  auto cm = std::make_unique<CookieMonster>(store, &net_log_);
 
   ASSERT_EQ(0, store->flush_count());
   ASSERT_EQ(0, counter->callback_count());
@@ -2548,7 +2528,7 @@
   ASSERT_EQ(2, counter->callback_count());
 
   // If there's no backing store, FlushStore() is always a safe no-op.
-  cm.reset(new CookieMonster(nullptr, nullptr, &net_log_));
+  cm.reset(new CookieMonster(nullptr, &net_log_));
   GetAllCookies(cm.get());  // Force init.
   cm->FlushStore(base::DoNothing());
   base::RunLoop().RunUntilIdle();
@@ -2561,23 +2541,9 @@
   ASSERT_EQ(3, counter->callback_count());
 }
 
-TEST_F(CookieMonsterTest, SetBeforeCommitCallbackIsCalled) {
-  std::unique_ptr<ChannelIDService> channel_id_service(
-      new ChannelIDService(nullptr));
-
-  scoped_refptr<NewMockPersistentCookieStore> store(
-      new NewMockPersistentCookieStore());
-
-  // SetBeforeCommitCallback should be called in both the c'tor and d'tor.
-  EXPECT_CALL(*store, SetBeforeCommitCallback(testing::_)).Times(2);
-
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(store.get(), channel_id_service.get(), &net_log_));
-}
-
 TEST_F(CookieMonsterTest, SetAllCookies) {
   scoped_refptr<FlushablePersistentStore> store(new FlushablePersistentStore());
-  auto cm = std::make_unique<CookieMonster>(store.get(), nullptr, &net_log_);
+  auto cm = std::make_unique<CookieMonster>(store.get(), &net_log_);
   cm->SetPersistSessionCookies(true);
 
   EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "U=V; path=/"));
@@ -2640,7 +2606,7 @@
 // works).
 TEST_F(CookieMonsterTest, DeleteAll) {
   scoped_refptr<FlushablePersistentStore> store(new FlushablePersistentStore());
-  auto cm = std::make_unique<CookieMonster>(store.get(), nullptr, &net_log_);
+  auto cm = std::make_unique<CookieMonster>(store.get(), &net_log_);
   cm->SetPersistSessionCookies(true);
 
   EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "X=Y; path=/"));
@@ -2668,8 +2634,7 @@
 }
 
 TEST_F(CookieMonsterTest, HistogramCheck) {
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, &net_log_));
   // Should match call in InitializeHistograms, but doesn't really matter
   // since the histogram should have been initialized by the CM construction
   // above.
@@ -2711,8 +2676,7 @@
 // CookieStore if the "persist session cookies" option is on.
 TEST_F(CookieMonsterTest, PersistSessionCookies) {
   scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(store.get(), nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
   cm->SetPersistSessionCookies(true);
 
   // All cookies set with SetCookie are session cookies.
@@ -2749,8 +2713,7 @@
 // Test the commands sent to the persistent cookie store.
 TEST_F(CookieMonsterTest, PersisentCookieStorageTest) {
   scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(store.get(), nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
 
   // Add a cookie.
   EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(),
@@ -2819,8 +2782,7 @@
   // Inject our initial cookies into the mock PersistentCookieStore.
   store->SetLoadExpectation(true, std::move(initial_cookies));
 
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(store.get(), nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
 
   EXPECT_EQ("foo=bar; hello=world", GetCookies(cm.get(), url));
 }
@@ -2831,8 +2793,7 @@
   const std::string cookie_source_histogram = "Cookie.CookieSourceScheme";
 
   scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(store.get(), nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
 
   histograms.ExpectTotalCount(cookie_source_histogram, 0);
 
@@ -2894,8 +2855,7 @@
   const std::string cookie_source_histogram = "Cookie.CookieDeleteEquivalent";
 
   scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(store.get(), nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
 
   // Set a secure cookie from a secure origin
   EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(), "A=B; Secure"));
@@ -2993,8 +2953,7 @@
 }
 
 TEST_F(CookieMonsterTest, SetSecureCookies) {
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, &net_log_));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, &net_log_));
   GURL http_url("http://www.foo.com");
   GURL http_superdomain_url("http://foo.com");
   GURL https_url("https://www.foo.com");
@@ -3264,8 +3223,7 @@
 // Tests that strict secure cookies doesn't trip equivalent cookie checks
 // accidentally. Regression test for https://crbug.com/569943.
 TEST_F(CookieMonsterTest, EquivalentCookies) {
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, nullptr));
+  std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr));
   GURL http_url("http://www.foo.com");
   GURL http_superdomain_url("http://foo.com");
   GURL https_url("https://www.foo.com");
@@ -3293,7 +3251,7 @@
       base::MakeRefCounted<MockPersistentCookieStore>();
   // Collect load commands so we have control over their execution.
   persistent_store->set_store_load_commands(true);
-  CookieMonster cm(persistent_store.get(), nullptr, nullptr);
+  CookieMonster cm(persistent_store.get(), nullptr);
 
   // Start of a canonical cookie set.
   ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus>
@@ -3341,7 +3299,7 @@
   // that the implementation doesn't just happen to pick the right one because
   // of implementation details.
   for (size_t run = 0; run < base::size(kNames); ++run) {
-    CookieMonster cm(nullptr, nullptr, nullptr);
+    CookieMonster cm(nullptr, nullptr);
     Time now = Time::Now();
     GURL url("http://www.example.com");
 
@@ -3378,7 +3336,7 @@
   GURL url("http://www.example.com");
   std::string cookie_line = "foo=bar";
   CookieOptions options;
-  CookieMonster cm(nullptr, nullptr, nullptr);
+  CookieMonster cm(nullptr, nullptr);
 
   // Write a cookie created at |t1|.
   auto cookie = CanonicalCookie::Create(url, cookie_line, t1, options);
@@ -3418,7 +3376,7 @@
   CookieMonsterNotificationTest()
       : test_url_("http://www.foo.com/foo"),
         store_(new MockPersistentCookieStore),
-        monster_(new CookieMonster(store_.get(), nullptr, nullptr)) {}
+        monster_(new CookieMonster(store_.get(), nullptr)) {}
 
   ~CookieMonsterNotificationTest() override = default;
 
@@ -3449,7 +3407,7 @@
   store->set_store_load_commands(true);
 
   // Bind it to a CookieMonster
-  auto monster = std::make_unique<CookieMonster>(store.get(), nullptr, nullptr);
+  auto monster = std::make_unique<CookieMonster>(store.get(), nullptr);
 
   // Trigger load dispatch and confirm it.
   monster->GetAllCookiesAsync(CookieStore::GetCookieListCallback());
diff --git a/net/cookies/cookie_store_test_helpers.cc b/net/cookies/cookie_store_test_helpers.cc
index 70675bc1..813bfe1 100644
--- a/net/cookies/cookie_store_test_helpers.cc
+++ b/net/cookies/cookie_store_test_helpers.cc
@@ -65,7 +65,6 @@
 
 DelayedCookieMonster::DelayedCookieMonster()
     : cookie_monster_(new CookieMonster(nullptr /* store */,
-                                        nullptr /* channel_id_service */,
                                         nullptr /* netlog */)),
       did_run_(false),
       result_(
diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc b/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
index 0043b78d..9bf3935 100644
--- a/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
+++ b/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
@@ -1227,7 +1227,7 @@
   // Create a cookie on a scheme that doesn't handle cookies by default,
   // and save it.
   std::unique_ptr<CookieMonster> cookie_monster =
-      std::make_unique<CookieMonster>(store_.get(), nullptr, nullptr);
+      std::make_unique<CookieMonster>(store_.get(), nullptr);
   cookie_monster->SetCookieableSchemes({"gopher", "http"});
   ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus>
       set_cookie_callback;
@@ -1267,8 +1267,7 @@
   // instances, so they should complete before the new PersistentCookieStore
   // starts looking at the state on disk.
   Create(false, false, true /* want current thread to invoke cookie monster */);
-  cookie_monster =
-      std::make_unique<CookieMonster>(store_.get(), nullptr, nullptr);
+  cookie_monster = std::make_unique<CookieMonster>(store_.get(), nullptr);
   cookie_monster->SetCookieableSchemes({"gopher", "http"});
 
   // Now try to get the cookie back.
@@ -1293,7 +1292,7 @@
       base::CreateDirectory(temp_dir_.GetPath().Append(kCookieFilename)));
   Create(false, false, true /* want current thread to invoke cookie monster */);
   std::unique_ptr<CookieMonster> cookie_monster =
-      std::make_unique<CookieMonster>(store_.get(), nullptr, nullptr);
+      std::make_unique<CookieMonster>(store_.get(), nullptr);
 
   ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus>
       set_cookie_callback;
diff --git a/net/http/http_proxy_connect_job_unittest.cc b/net/http/http_proxy_connect_job_unittest.cc
index f942365..05b0d28 100644
--- a/net/http/http_proxy_connect_job_unittest.cc
+++ b/net/http/http_proxy_connect_job_unittest.cc
@@ -846,10 +846,11 @@
     return;
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  // The SPDY CONNECT request should have a priority of HIGHEST.
+  // The SPDY CONNECT request should have a priority of MEDIUM, even though the
+  // ConnectJob's priority is set to HIGHEST after connection establishment.
   spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyConnect(
       nullptr /* extra_headers */, 0 /* extra_header_count */,
-      1 /* stream_id */, HIGHEST, HostPortPair(kEndpointHost, 443)));
+      1 /* stream_id */, MEDIUM, HostPortPair(kEndpointHost, 443)));
   MockWrite spdy_writes[] = {CreateMockWrite(req, 0, ASYNC)};
   spdy::SpdySerializedFrame resp(
       spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index d2350cb..a9a38c4 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -8226,6 +8226,72 @@
   EXPECT_TRUE(mock_quic_data.AllWriteDataConsumed());
 }
 
+// Makes sure the CONNECT request packet for a QUIC proxy contains the correct
+// HTTP/2 stream dependency and weights given the request priority.
+TEST_P(QuicNetworkTransactionTest, QuicProxyMultipleRequestsError) {
+  session_params_.enable_quic = true;
+  session_params_.enable_quic_proxies_for_https_urls = true;
+  proxy_resolution_service_ = ProxyResolutionService::CreateFixedFromPacResult(
+      "QUIC proxy.example.org:70", TRAFFIC_ANNOTATION_FOR_TESTS);
+
+  const RequestPriority kRequestPriority = MEDIUM;
+  const RequestPriority kRequestPriority2 = LOWEST;
+
+  MockQuicData mock_quic_data;
+  quic::QuicStreamOffset header_stream_offset = 0;
+  mock_quic_data.AddWrite(
+      ASYNC, ConstructInitialSettingsPacket(1, &header_stream_offset));
+  mock_quic_data.AddWrite(SYNCHRONOUS, ERR_FAILED);
+  // This should never be reached.
+  mock_quic_data.AddRead(ASYNC, ERR_CONNECTION_FAILED);
+  mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+  // Second connection attempt just fails - result doesn't really matter.
+  MockQuicData mock_quic_data2;
+  mock_quic_data2.AddConnect(SYNCHRONOUS, ERR_FAILED);
+  mock_quic_data2.AddSocketDataToFactory(&socket_factory_);
+
+  int original_max_sockets_per_group =
+      ClientSocketPoolManager::max_sockets_per_group(
+          HttpNetworkSession::SocketPoolType::NORMAL_SOCKET_POOL);
+  ClientSocketPoolManager::set_max_sockets_per_group(
+      HttpNetworkSession::SocketPoolType::NORMAL_SOCKET_POOL, 1);
+  int original_max_sockets_per_pool =
+      ClientSocketPoolManager::max_sockets_per_pool(
+          HttpNetworkSession::SocketPoolType::NORMAL_SOCKET_POOL);
+  ClientSocketPoolManager::set_max_sockets_per_pool(
+      HttpNetworkSession::SocketPoolType::NORMAL_SOCKET_POOL, 1);
+  CreateSession();
+
+  request_.url = GURL("https://mail.example.org/");
+  HttpNetworkTransaction trans(kRequestPriority, session_.get());
+  TestCompletionCallback callback;
+  int rv = trans.Start(&request_, callback.callback(), net_log_.bound());
+  EXPECT_EQ(ERR_IO_PENDING, rv);
+
+  HttpRequestInfo request2;
+  request2.url = GURL("https://mail.example.org/some/other/path/");
+  request2.traffic_annotation =
+      net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
+
+  HttpNetworkTransaction trans2(kRequestPriority2, session_.get());
+  TestCompletionCallback callback2;
+  int rv2 = trans2.Start(&request2, callback2.callback(), net_log_.bound());
+  EXPECT_EQ(ERR_IO_PENDING, rv2);
+
+  EXPECT_EQ(ERR_QUIC_PROTOCOL_ERROR, callback.WaitForResult());
+  EXPECT_TRUE(mock_quic_data.AllWriteDataConsumed());
+
+  EXPECT_EQ(ERR_FAILED, callback2.WaitForResult());
+
+  ClientSocketPoolManager::set_max_sockets_per_pool(
+      HttpNetworkSession::SocketPoolType::NORMAL_SOCKET_POOL,
+      original_max_sockets_per_pool);
+  ClientSocketPoolManager::set_max_sockets_per_group(
+      HttpNetworkSession::SocketPoolType::NORMAL_SOCKET_POOL,
+      original_max_sockets_per_group);
+}
+
 // Test the request-challenge-retry sequence for basic auth, over a QUIC
 // connection when setting up a QUIC proxy tunnel.
 TEST_P(QuicNetworkTransactionTest, QuicProxyAuth) {
diff --git a/net/quic/quic_proxy_client_socket.cc b/net/quic/quic_proxy_client_socket.cc
index db69ce0..e6f2b811 100644
--- a/net/quic/quic_proxy_client_socket.cc
+++ b/net/quic/quic_proxy_client_socket.cc
@@ -79,9 +79,13 @@
   return kProtoQUIC;
 }
 
-void QuicProxyClientSocket::SetStreamPriority(RequestPriority priority) {
-  stream_->SetPriority(ConvertRequestPriorityToQuicPriority(priority));
-}
+// Ignore priority changes, just use priority of initial request. Since multiple
+// requests are pooled on the QuicProxyClientSocket, reprioritization doesn't
+// really work.
+//
+// TODO(mmenke):  Use a single priority value for all QuicProxyClientSockets,
+// regardless of what priority they're created with.
+void QuicProxyClientSocket::SetStreamPriority(RequestPriority priority) {}
 
 // Sends a HEADERS frame to the proxy with a CONNECT request
 // for the specified endpoint.  Waits for the server to send back
diff --git a/net/quic/quic_proxy_client_socket_unittest.cc b/net/quic/quic_proxy_client_socket_unittest.cc
index d693d21..e5ed0a6 100644
--- a/net/quic/quic_proxy_client_socket_unittest.cc
+++ b/net/quic/quic_proxy_client_socket_unittest.cc
@@ -834,8 +834,10 @@
 
 TEST_P(QuicProxyClientSocketTest, SetStreamPriority) {
   mock_quic_data_.AddWrite(SYNCHRONOUS, ConstructSettingsPacket(1));
+  // Despite setting the priority to HIGHEST, the requets initial priority of
+  // LOWEST is used.
   mock_quic_data_.AddWrite(SYNCHRONOUS,
-                           ConstructConnectRequestPacket(2, HIGHEST));
+                           ConstructConnectRequestPacket(2, LOWEST));
   mock_quic_data_.AddRead(ASYNC, ConstructServerConnectReplyPacket(1, !kFin));
   mock_quic_data_.AddRead(SYNCHRONOUS, ERR_IO_PENDING);
   mock_quic_data_.AddWrite(
diff --git a/net/socket/transport_client_socket_pool_unittest.cc b/net/socket/transport_client_socket_pool_unittest.cc
index 05897576..7ffa4ab 100644
--- a/net/socket/transport_client_socket_pool_unittest.cc
+++ b/net/socket/transport_client_socket_pool_unittest.cc
@@ -7,8 +7,10 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
+#include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/platform_thread.h"
 #include "build/build_config.h"
@@ -1303,6 +1305,259 @@
   }
 }
 
+// Make sure there's no crash when an auth challenge is received over HTTP2
+// and there are two pending Requests to the socket pool, with a single
+// ConnectJob.
+//
+// See https://crbug.com/940848
+TEST_F(TransportClientSocketPoolTest, SpdyOneConnectJobTwoRequestsError) {
+  const HostPortPair kEndpoint("unresolvable.host.name", 443);
+  const HostPortPair kProxy("unresolvable.proxy.name", 443);
+
+  session_deps_.host_resolver->set_synchronous_mode(true);
+
+  // Create a socket pool which only allows a single connection at a time.
+  TransportClientSocketPool pool(
+      1, 1, kUnusedIdleSocketTimeout, &tagging_client_socket_factory_,
+      session_deps_.host_resolver.get(), nullptr /* proxy_delegate */,
+      nullptr /* http_user_agent_settings */, session_deps_.cert_verifier.get(),
+      nullptr /* channel_id_server */,
+      session_deps_.transport_security_state.get(),
+      session_deps_.cert_transparency_verifier.get(),
+      session_deps_.ct_policy_enforcer.get(),
+      nullptr /* ssl_client_session_cache */,
+      nullptr /* ssl_client_session_cache_privacy_mode */,
+      session_deps_.ssl_config_service.get(),
+      nullptr /* socket_performance_watcher_factory */,
+      nullptr /* network_quality_estimator */, nullptr /* net_log */);
+
+  // First connection attempt will get an error after creating the SpdyStream.
+
+  SpdyTestUtil spdy_util;
+  spdy::SpdySerializedFrame connect(
+      spdy_util.ConstructSpdyConnect(nullptr, 0, 1, HIGHEST, kEndpoint));
+
+  MockWrite writes[] = {
+      CreateMockWrite(connect, 0, ASYNC),
+      MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 2),
+  };
+
+  MockRead reads[] = {
+      MockRead(ASYNC, ERR_FAILED, 1),
+  };
+
+  SequencedSocketData socket_data(MockConnect(SYNCHRONOUS, OK), reads, writes);
+  tagging_client_socket_factory_.AddSocketDataProvider(&socket_data);
+  SSLSocketDataProvider ssl_data(SYNCHRONOUS, OK);
+  ssl_data.next_proto = kProtoHTTP2;
+  tagging_client_socket_factory_.AddSSLSocketDataProvider(&ssl_data);
+
+  // Second connection also fails.  Not a vital part of this test, but allows
+  // waiting for the second request to complete without too much extra code.
+  SequencedSocketData socket_data2(
+      MockConnect(SYNCHRONOUS, ERR_CONNECTION_TIMED_OUT),
+      base::span<const MockRead>(), base::span<const MockWrite>());
+  tagging_client_socket_factory_.AddSocketDataProvider(&socket_data2);
+  SSLSocketDataProvider ssl_data2(SYNCHRONOUS, OK);
+  tagging_client_socket_factory_.AddSSLSocketDataProvider(&ssl_data2);
+
+  scoped_refptr<TransportSocketParams> transport_params =
+      base::MakeRefCounted<TransportSocketParams>(
+          kProxy, false /* disable_resolver_cache */,
+          OnHostResolutionCallback());
+
+  scoped_refptr<SSLSocketParams> proxy_ssl_params =
+      base::MakeRefCounted<SSLSocketParams>(
+          transport_params, nullptr /* socks_proxy_params */,
+          nullptr /* http_proxy_params */, kProxy, GetSSLConfig(),
+          PRIVACY_MODE_DISABLED);
+
+  scoped_refptr<HttpProxySocketParams> http_proxy_params =
+      base::MakeRefCounted<HttpProxySocketParams>(
+          nullptr /* transport_params */, proxy_ssl_params,
+          quic::QUIC_VERSION_UNSUPPORTED, kEndpoint,
+          http_network_session_->http_auth_cache(),
+          http_network_session_->http_auth_handler_factory(),
+          http_network_session_->spdy_session_pool(),
+          nullptr /* quic_stream_factory */, false /* is_trusted_proxy */,
+          true /* tunnel */, TRAFFIC_ANNOTATION_FOR_TESTS);
+  scoped_refptr<SSLSocketParams> endpoint_ssl_params =
+      base::MakeRefCounted<SSLSocketParams>(
+          nullptr /* direct_params */, nullptr /* socks_proxy_params */,
+          http_proxy_params, kEndpoint, GetSSLConfig(), PRIVACY_MODE_DISABLED);
+
+  scoped_refptr<TransportClientSocketPool::SocketParams> pool_params =
+      TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+          endpoint_ssl_params);
+
+  // Start the first connection attempt.
+  TestCompletionCallback callback1;
+  ClientSocketHandle handle1;
+  int rv1 = handle1.Init(
+      "a", pool_params, HIGHEST, SocketTag(),
+      ClientSocketPool::RespectLimits::ENABLED, callback1.callback(),
+      ClientSocketPool::ProxyAuthCallback(), &pool, NetLogWithSource());
+  ASSERT_THAT(rv1, IsError(ERR_IO_PENDING));
+
+  // Create a second request with a lower priority.
+  TestCompletionCallback callback2;
+  ClientSocketHandle handle2;
+  int rv2 = handle2.Init(
+      "a", pool_params, LOWEST, SocketTag(),
+      ClientSocketPool::RespectLimits::ENABLED, callback2.callback(),
+      ClientSocketPool::ProxyAuthCallback(), &pool, NetLogWithSource());
+  ASSERT_THAT(rv2, IsError(ERR_IO_PENDING));
+
+  // First connection fails after creating a SpdySession and a SpdyStream on
+  // that session. The SpdyStream will be destroyed under the
+  // SpdyProxyClientSocket. The failure will result in temporarily assigning the
+  // failed ConnectJob to the second request, which results in an unneeded
+  // reprioritization, which should not dereference the null SpdyStream.
+  //
+  // TODO(mmenke): Avoid that temporary reassignment.
+  ASSERT_THAT(callback1.WaitForResult(), IsError(ERR_FAILED));
+
+  // Second connection fails, getting a connection error.
+  ASSERT_THAT(callback2.WaitForResult(), IsError(ERR_PROXY_CONNECTION_FAILED));
+}
+
+// Make sure there's no crash when an auth challenge is received over HTTP2
+// and there are two pending Requests to the socket pool, with a single
+// ConnectJob.
+//
+// See https://crbug.com/940848
+TEST_F(TransportClientSocketPoolTest, SpdyAuthOneConnectJobTwoRequests) {
+  const HostPortPair kEndpoint("unresolvable.host.name", 443);
+  const HostPortPair kProxy("unresolvable.proxy.name", 443);
+
+  session_deps_.host_resolver->set_synchronous_mode(true);
+
+  // Create a socket pool which only allows a single connection at a time.
+  TransportClientSocketPool pool(
+      1, 1, kUnusedIdleSocketTimeout, &tagging_client_socket_factory_,
+      session_deps_.host_resolver.get(), nullptr /* proxy_delegate */,
+      nullptr /* http_user_agent_settings */, session_deps_.cert_verifier.get(),
+      nullptr /* channel_id_server */,
+      session_deps_.transport_security_state.get(),
+      session_deps_.cert_transparency_verifier.get(),
+      session_deps_.ct_policy_enforcer.get(),
+      nullptr /* ssl_client_session_cache */,
+      nullptr /* ssl_client_session_cache_privacy_mode */,
+      session_deps_.ssl_config_service.get(),
+      nullptr /* socket_performance_watcher_factory */,
+      nullptr /* network_quality_estimator */, nullptr /* net_log */);
+
+  SpdyTestUtil spdy_util;
+  spdy::SpdySerializedFrame connect(
+      spdy_util.ConstructSpdyConnect(nullptr, 0, 1, HIGHEST, kEndpoint));
+
+  MockWrite writes[] = {
+      CreateMockWrite(connect, 0, ASYNC),
+      MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 4),
+  };
+
+  // The proxy responds to the connect with a 407, and them an
+  // ERROR_CODE_HTTP_1_1_REQUIRED.
+
+  const char kAuthStatus[] = "407";
+  const char* const kAuthChallenge[] = {
+      "proxy-authenticate",
+      "NTLM",
+  };
+  spdy::SpdySerializedFrame connect_auth_resp(spdy_util.ConstructSpdyReplyError(
+      kAuthStatus, kAuthChallenge, base::size(kAuthChallenge) / 2, 1));
+  spdy::SpdySerializedFrame reset(
+      spdy_util.ConstructSpdyRstStream(1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
+  MockRead reads[] = {
+      CreateMockRead(connect_auth_resp, 1, ASYNC),
+      CreateMockRead(reset, 2, SYNCHRONOUS),
+      MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3),
+  };
+
+  SequencedSocketData socket_data(MockConnect(SYNCHRONOUS, OK), reads, writes);
+  tagging_client_socket_factory_.AddSocketDataProvider(&socket_data);
+  SSLSocketDataProvider ssl_data(SYNCHRONOUS, OK);
+  ssl_data.next_proto = kProtoHTTP2;
+  tagging_client_socket_factory_.AddSSLSocketDataProvider(&ssl_data);
+
+  // Second connection fails, and gets a different error.  Not a vital part of
+  // this test, but allows waiting for the second request to complete without
+  // too much extra code.
+  SequencedSocketData socket_data2(
+      MockConnect(SYNCHRONOUS, ERR_CONNECTION_TIMED_OUT),
+      base::span<const MockRead>(), base::span<const MockWrite>());
+  tagging_client_socket_factory_.AddSocketDataProvider(&socket_data2);
+  SSLSocketDataProvider ssl_data2(SYNCHRONOUS, OK);
+  tagging_client_socket_factory_.AddSSLSocketDataProvider(&ssl_data2);
+
+  scoped_refptr<TransportSocketParams> transport_params =
+      base::MakeRefCounted<TransportSocketParams>(
+          kProxy, false /* disable_resolver_cache */,
+          OnHostResolutionCallback());
+
+  scoped_refptr<SSLSocketParams> proxy_ssl_params =
+      base::MakeRefCounted<SSLSocketParams>(
+          transport_params, nullptr /* socks_proxy_params */,
+          nullptr /* http_proxy_params */, kProxy, GetSSLConfig(),
+          PRIVACY_MODE_DISABLED);
+
+  scoped_refptr<HttpProxySocketParams> http_proxy_params =
+      base::MakeRefCounted<HttpProxySocketParams>(
+          nullptr /* transport_params */, proxy_ssl_params,
+          quic::QUIC_VERSION_UNSUPPORTED, kEndpoint,
+          http_network_session_->http_auth_cache(),
+          http_network_session_->http_auth_handler_factory(),
+          http_network_session_->spdy_session_pool(),
+          nullptr /* quic_stream_factory */, false /* is_trusted_proxy */,
+          true /* tunnel */, TRAFFIC_ANNOTATION_FOR_TESTS);
+  scoped_refptr<SSLSocketParams> endpoint_ssl_params =
+      base::MakeRefCounted<SSLSocketParams>(
+          nullptr /* direct_params */, nullptr /* socks_proxy_params */,
+          http_proxy_params, kEndpoint, GetSSLConfig(), PRIVACY_MODE_DISABLED);
+
+  scoped_refptr<TransportClientSocketPool::SocketParams> pool_params =
+      TransportClientSocketPool::SocketParams::CreateFromSSLSocketParams(
+          endpoint_ssl_params);
+
+  // Start the first connection attempt.
+  TestCompletionCallback callback1;
+  ClientSocketHandle handle1;
+  base::RunLoop run_loop;
+  int rv1 = handle1.Init("a", pool_params, HIGHEST, SocketTag(),
+                         ClientSocketPool::RespectLimits::ENABLED,
+                         callback1.callback(),
+                         base::BindLambdaForTesting(
+                             [&](const HttpResponseInfo& response,
+                                 HttpAuthController* auth_controller,
+                                 base::OnceClosure restart_with_auth_callback) {
+                               run_loop.Quit();
+                             }),
+                         &pool, NetLogWithSource());
+  ASSERT_THAT(rv1, IsError(ERR_IO_PENDING));
+
+  // Create a second request with a lower priority.
+  TestCompletionCallback callback2;
+  ClientSocketHandle handle2;
+  int rv2 = handle2.Init(
+      "a", pool_params, LOWEST, SocketTag(),
+      ClientSocketPool::RespectLimits::ENABLED, callback2.callback(),
+      ClientSocketPool::ProxyAuthCallback(), &pool, NetLogWithSource());
+  ASSERT_THAT(rv2, IsError(ERR_IO_PENDING));
+
+  // The ConnectJob connection sees the auth challenge and HTTP2 error, which
+  // causes the SpdySession to be destroyed, as well as the SpdyStream. Then the
+  // ConnectJob is bound to the first request. Binding the request will result
+  // in temporarily assigning the ConnectJob to the second request, which
+  // results in an unneeded reprioritization, which should not dereference the
+  // null SpdyStream.
+  //
+  // TODO(mmenke): Avoid that temporary reassignment.
+  run_loop.Run();
+
+  // Just tear down everything without continuing - there are other tests for
+  // auth over HTTP2.
+}
+
 // Test that SocketTag passed into TransportClientSocketPool is applied to
 // returned sockets.
 #if defined(OS_ANDROID)
diff --git a/net/spdy/spdy_proxy_client_socket.cc b/net/spdy/spdy_proxy_client_socket.cc
index e25c7be..c64dcb3 100644
--- a/net/spdy/spdy_proxy_client_socket.cc
+++ b/net/spdy/spdy_proxy_client_socket.cc
@@ -91,9 +91,13 @@
   return spdy_stream_->GetNegotiatedProtocol();
 }
 
-void SpdyProxyClientSocket::SetStreamPriority(RequestPriority priority) {
-  spdy_stream_->SetPriority(priority);
-}
+// Ignore priority changes, just use priority of initial request. Since multiple
+// requests are pooled on the SpdyProxyClientSocket, reprioritization doesn't
+// really work.
+//
+// TODO(mmenke):  Use a single priority value for all SpdyProxyClientSockets,
+// regardless of what priority they're created with.
+void SpdyProxyClientSocket::SetStreamPriority(RequestPriority priority) {}
 
 // Sends a HEADERS frame to the proxy with a CONNECT request
 // for the specified endpoint.  Waits for the server to send back
diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc
index 7252716..9fb91f3 100644
--- a/net/spdy/spdy_proxy_client_socket_unittest.cc
+++ b/net/spdy/spdy_proxy_client_socket_unittest.cc
@@ -135,7 +135,7 @@
   void PopulateConnectRequestIR(spdy::SpdyHeaderBlock* syn_ir);
   void PopulateConnectReplyIR(spdy::SpdyHeaderBlock* block, const char* status);
   spdy::SpdySerializedFrame ConstructConnectRequestFrame(
-      RequestPriority priority);
+      RequestPriority priority = LOWEST);
   spdy::SpdySerializedFrame ConstructConnectAuthRequestFrame();
   spdy::SpdySerializedFrame ConstructConnectReplyFrame();
   spdy::SpdySerializedFrame ConstructConnectAuthReplyFrame();
@@ -425,7 +425,7 @@
 // Constructs a standard SPDY HEADERS frame for a CONNECT request.
 spdy::SpdySerializedFrame
 SpdyProxyClientSocketTest::ConstructConnectRequestFrame(
-    RequestPriority priority = LOWEST) {
+    RequestPriority priority) {
   spdy::SpdyHeaderBlock block;
   PopulateConnectRequestIR(&block);
   return spdy_util_.ConstructSpdyHeaders(kStreamId, std::move(block), priority,
@@ -605,7 +605,7 @@
 }
 
 TEST_P(SpdyProxyClientSocketTest, SetStreamPriority) {
-  spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame(HIGHEST));
+  spdy::SpdySerializedFrame conn(ConstructConnectRequestFrame(LOWEST));
   MockWrite writes[] = {
       CreateMockWrite(conn, 0, SYNCHRONOUS),
   };
@@ -618,6 +618,8 @@
 
   Initialize(reads, writes);
 
+  // Set the stream priority. Since a connection was already established, it's
+  // too late to adjust the HTTP2 stream's priority, and the request is ignored.
   sock_->SetStreamPriority(HIGHEST);
 
   AssertConnectSucceeds();
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc
index c3dec2e..823f678 100644
--- a/net/spdy/spdy_test_util_common.cc
+++ b/net/spdy/spdy_test_util_common.cc
@@ -962,7 +962,8 @@
   block["hello"] = "bye";
   AppendToHeaderBlock(extra_headers, extra_header_count, &block);
 
-  return ConstructSpdyReply(stream_id, std::move(block));
+  spdy::SpdyHeadersIR reply(stream_id, std::move(block));
+  return spdy::SpdySerializedFrame(response_spdy_framer_.SerializeFrame(reply));
 }
 
 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyReplyError(int stream_id) {
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index 5c7d056..eff048b 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -453,8 +453,7 @@
     storage->set_cookie_store(std::move(cookie_store_));
   } else {
     std::unique_ptr<CookieStore> cookie_store(
-        new CookieMonster(nullptr /* store */, nullptr /* channel_id_service */,
-                          context->net_log()));
+        new CookieMonster(nullptr /* store */, context->net_log()));
     storage->set_cookie_store(std::move(cookie_store));
   }
 
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc
index 5a016a7a..1594cd4 100644
--- a/net/url_request/url_request_test_util.cc
+++ b/net/url_request/url_request_test_util.cc
@@ -103,8 +103,7 @@
   // In-memory cookie store.
   if (!cookie_store()) {
     context_storage_.set_cookie_store(std::make_unique<CookieMonster>(
-        nullptr /* store */, nullptr /* channel_id_service */,
-        nullptr /* netlog */));
+        nullptr /* store */, nullptr /* netlog */));
   }
 
   // In-memory Channel ID service.  Must be created before the
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index eb1c0157..c71e8ad 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -2650,7 +2650,7 @@
 
   TestURLRequestContext sync_context;
   std::unique_ptr<CookieMonster> cm =
-      std::make_unique<CookieMonster>(nullptr, nullptr, nullptr);
+      std::make_unique<CookieMonster>(nullptr, nullptr);
   sync_context.set_cookie_store(cm.get());
   FilteringTestLayeredNetworkDelegate sync_filter_network_delegate(
       std::make_unique<TestNetworkDelegate>());
diff --git a/remoting/protocol/webrtc_audio_stream.cc b/remoting/protocol/webrtc_audio_stream.cc
index 3028b01..1f198be8 100644
--- a/remoting/protocol/webrtc_audio_stream.cc
+++ b/remoting/protocol/webrtc_audio_stream.cc
@@ -52,6 +52,8 @@
   audio_sender_ =
       peer_connection_->AddTrack(audio_track.get(), {kAudioStreamLabel})
           .value();
+
+  webrtc_transport->OnAudioSenderCreated(audio_sender_);
 }
 
 void WebrtcAudioStream::Pause(bool pause) {
diff --git a/remoting/protocol/webrtc_audio_stream.h b/remoting/protocol/webrtc_audio_stream.h
index 75ac45e..13baf221 100644
--- a/remoting/protocol/webrtc_audio_stream.h
+++ b/remoting/protocol/webrtc_audio_stream.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "remoting/protocol/audio_stream.h"
+#include "third_party/webrtc/api/scoped_refptr.h"
 
 namespace base {
 class SingleThreadTaskRunner;
@@ -43,7 +44,7 @@
   scoped_refptr<WebrtcAudioSourceAdapter> source_adapter_;
 
   scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
-  scoped_refptr<webrtc::RtpSenderInterface> audio_sender_;
+  rtc::scoped_refptr<webrtc::RtpSenderInterface> audio_sender_;
 
   DISALLOW_COPY_AND_ASSIGN(WebrtcAudioStream);
 };
diff --git a/remoting/protocol/webrtc_transport.cc b/remoting/protocol/webrtc_transport.cc
index 24df24a..48f2e5b 100644
--- a/remoting/protocol/webrtc_transport.cc
+++ b/remoting/protocol/webrtc_transport.cc
@@ -490,6 +490,11 @@
                        weak_factory_.GetWeakPtr(),
                        type == webrtc::SessionDescriptionInterface::kOffer)),
         session_description.release());
+
+    // SetRemoteDescription() might overwrite any bitrate caps previously set,
+    // so (re)apply them here. This might happen if ICE state were already
+    // connected and OnStatsDelivered() had already set the caps.
+    SetPeerConnectionBitrates(MaxBitrateForConnection());
   }
 
   XmlElement* candidate_element;
@@ -556,6 +561,17 @@
   }
 }
 
+void WebrtcTransport::OnAudioSenderCreated(
+    rtc::scoped_refptr<webrtc::RtpSenderInterface> sender) {}
+
+void WebrtcTransport::OnVideoSenderCreated(
+    rtc::scoped_refptr<webrtc::RtpSenderInterface> sender) {
+  // TODO(lambroslambrou): Store the VideoSender here, instead of looping over
+  // all Senders in GetVideoSender().
+  DCHECK_EQ(GetVideoSender(), sender);
+  SetSenderBitrates(MaxBitrateForConnection());
+}
+
 void WebrtcTransport::OnLocalSessionDescriptionCreated(
     std::unique_ptr<webrtc::SessionDescriptionInterface> description,
     const std::string& error) {
@@ -777,8 +793,24 @@
     LOG(ERROR) << "Connection type unknown, treating as direct.";
   }
 
+  // The max-bitrate needs to be applied even for direct (non-TURN) connections.
+  // Otherwise the video-sender b/w estimate is capped to a low default value
+  // (~600kbps).
+  // Set the global bitrate caps in addition to the VideoSender bitrates. The
+  // global caps affect the probing configuration used by b/w estimator.
+  // Setting min bitrate here enables padding.
+  //
+  // TODO(sergeyu): Padding needs to be enabled to workaround b/w estimator not
+  // handling spiky traffic patterns well. This won't be necessary with a
+  // better bandwidth estimator.
+  int max_bitrate_bps = MaxBitrateForConnection();
+  SetPeerConnectionBitrates(max_bitrate_bps);
+  SetSenderBitrates(max_bitrate_bps);
+}
+
+int WebrtcTransport::MaxBitrateForConnection() {
   int max_bitrate_bps = kMaxBitrateBps;
-  if (connection_relayed.value_or(false)) {
+  if (connection_relayed_.value_or(false)) {
     int turn_max_rate_kbps = transport_context_->GetTurnMaxRateKbps();
     if (turn_max_rate_kbps <= 0) {
       VLOG(0) << "No TURN bitrate cap set.";
@@ -790,22 +822,17 @@
       max_bitrate_bps = turn_max_rate_kbps * 1000;
     }
   }
+  return max_bitrate_bps;
+}
 
-  // The max-bitrate needs to be applied even for direct (non-TURN) connections.
-  // Otherwise the video-sender b/w estimate is capped to a low default value
-  // (~600kbps).
-  // Set the global bitrate caps in addition to the VideoSender bitrates. The
-  // global caps affect the probing configuration used by b/w estimator.
-  // Setting min bitrate here enables padding.
-  //
-  // TODO(sergeyu): Padding needs to be enabled to workaround b/w estimator not
-  // handling spiky traffic patterns well. This won't be necessary with a
-  // better bandwidth estimator.
+void WebrtcTransport::SetPeerConnectionBitrates(int max_bitrate_bps) {
   webrtc::BitrateSettings bitrate;
   bitrate.min_bitrate_bps = kMinBitrateBps;
   bitrate.max_bitrate_bps = max_bitrate_bps;
   peer_connection()->SetBitrate(bitrate);
+}
 
+void WebrtcTransport::SetSenderBitrates(int max_bitrate_bps) {
   // Only set the cap on the VideoSender, because the AudioSender (via the
   // Opus codec) is already configured with a lower bitrate.
   rtc::scoped_refptr<webrtc::RtpSenderInterface> sender = GetVideoSender();
@@ -828,7 +855,8 @@
 
   parameters.encodings[0].min_bitrate_bps = kMinBitrateBps;
   parameters.encodings[0].max_bitrate_bps = max_bitrate_bps;
-  sender->SetParameters(parameters);
+  webrtc::RTCError result = sender->SetParameters(parameters);
+  DCHECK(result.ok()) << "SetParameters() failed: " << result.message();
 }
 
 void WebrtcTransport::RequestRtcStats() {
diff --git a/remoting/protocol/webrtc_transport.h b/remoting/protocol/webrtc_transport.h
index b773b13..ebd97c7a 100644
--- a/remoting/protocol/webrtc_transport.h
+++ b/remoting/protocol/webrtc_transport.h
@@ -88,6 +88,16 @@
 
   void ApplySessionOptions(const SessionOptions& options);
 
+  // Called when a new AudioSender has been created from
+  // PeerConnection::AddTrack().
+  void OnAudioSenderCreated(
+      rtc::scoped_refptr<webrtc::RtpSenderInterface> sender);
+
+  // Called when a new VideoSender has been created from
+  // PeerConnection::AddTrack().
+  void OnVideoSenderCreated(
+      rtc::scoped_refptr<webrtc::RtpSenderInterface> sender);
+
  private:
   // PeerConnectionWrapper is responsible for PeerConnection creation,
   // ownership. It passes all events to the corresponding methods below. This is
@@ -122,6 +132,20 @@
   void OnStatsDelivered(
       const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report);
 
+  // Returns the max bitrate to set for this connection, taking into
+  // account any relay bitrate cap. If the relay status is unknown, this
+  // returns the default maximum bitrate.
+  int MaxBitrateForConnection();
+
+  // Sets bitrates on the PeerConnection.
+  // Called after SetRemoteDescription(), but also called if the relay status
+  // changes.
+  void SetPeerConnectionBitrates(int max_bitrate_bps);
+
+  // Sets bitrates on the (video) sender. Called when the sender is created, but
+  // also called if the relay status changes.
+  void SetSenderBitrates(int max_bitrate_bps);
+
   void RequestRtcStats();
   void RequestNegotiation();
   void SendOffer();
diff --git a/remoting/protocol/webrtc_video_stream.cc b/remoting/protocol/webrtc_video_stream.cc
index 570c794..6e4331d 100644
--- a/remoting/protocol/webrtc_video_stream.cc
+++ b/remoting/protocol/webrtc_video_stream.cc
@@ -140,6 +140,8 @@
   video_sender_ =
       peer_connection_->AddTrack(video_track.get(), {kStreamLabel}).value();
 
+  webrtc_transport_->OnVideoSenderCreated(video_sender_);
+
   scheduler_.reset(new WebrtcFrameSchedulerSimple(session_options_));
   scheduler_->Start(
       webrtc_transport_->video_encoder_factory(),
diff --git a/remoting/protocol/webrtc_video_stream.h b/remoting/protocol/webrtc_video_stream.h
index b19c8ae1..07a3cfc 100644
--- a/remoting/protocol/webrtc_video_stream.h
+++ b/remoting/protocol/webrtc_video_stream.h
@@ -21,6 +21,7 @@
 #include "remoting/codec/webrtc_video_encoder_selector.h"
 #include "remoting/protocol/host_video_stats_dispatcher.h"
 #include "remoting/protocol/video_stream.h"
+#include "third_party/webrtc/api/scoped_refptr.h"
 #include "third_party/webrtc/common_types.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h"
 
@@ -87,7 +88,7 @@
   scoped_refptr<InputEventTimestampsSource> event_timestamps_source_;
 
   scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
-  scoped_refptr<webrtc::RtpSenderInterface> video_sender_;
+  rtc::scoped_refptr<webrtc::RtpSenderInterface> video_sender_;
 
   HostVideoStatsDispatcher video_stats_dispatcher_;
 
diff --git a/remoting/test/protocol_perftest.cc b/remoting/test/protocol_perftest.cc
index ed80305c..e24b27a 100644
--- a/remoting/test/protocol_perftest.cc
+++ b/remoting/test/protocol_perftest.cc
@@ -10,15 +10,16 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/rand_util.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/task_scheduler/task_scheduler.h"
 #include "base/task_runner_util.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "jingle/glue/thread_wrapper.h"
+#include "net/base/network_change_notifier.h"
 #include "net/test/test_data_directory.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "remoting/base/rsa_key_pair.h"
@@ -51,6 +52,7 @@
 
 namespace remoting {
 
+using base::test::ScopedTaskEnvironment;
 using protocol::ChannelConfig;
 
 namespace {
@@ -106,7 +108,8 @@
       public HostStatusObserver {
  public:
   ProtocolPerfTest()
-      : host_thread_("host"),
+      : task_environment_(ScopedTaskEnvironment::MainThreadType::IO),
+        host_thread_("host"),
         capture_thread_("capture"),
         encode_thread_("encode"),
         decode_thread_("decode") {
@@ -116,7 +119,7 @@
     encode_thread_.Start();
     decode_thread_.Start();
 
-    base::TaskScheduler::CreateAndStartWithDefaultParams("ProtocolPerfTest");
+    network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
 
     desktop_environment_factory_.reset(
         new FakeDesktopEnvironmentFactory(capture_thread_.task_runner()));
@@ -195,7 +198,7 @@
   }
 
   void OnClientConnected(const std::string& jid) override {
-    message_loop_.task_runner()->PostTask(
+    task_environment_.GetMainThreadTaskRunner()->PostTask(
         FROM_HERE, base::BindOnce(&ProtocolPerfTest::OnHostConnectedMainThread,
                                   base::Unretained(this)));
   }
@@ -322,7 +325,7 @@
     host_->status_monitor()->AddStatusObserver(this);
     host_->Start(kHostOwner);
 
-    message_loop_.task_runner()->PostTask(
+    task_environment_.GetMainThreadTaskRunner()->PostTask(
         FROM_HERE, base::BindOnce(&ProtocolPerfTest::StartClientAfterHost,
                                   base::Unretained(this)));
   }
@@ -377,7 +380,7 @@
   void MeasureTotalLatency(bool use_webrtc);
   void MeasureScrollPerformance(bool use_webrtc);
 
-  base::MessageLoopForIO message_loop_;
+  ScopedTaskEnvironment task_environment_;
 
   scoped_refptr<FakeNetworkDispatcher> fake_network_dispatcher_;
 
@@ -418,6 +421,8 @@
   std::unique_ptr<webrtc::DesktopFrame> last_video_frame_;
   std::vector<protocol::FrameStats> frame_stats_;
 
+  std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(ProtocolPerfTest);
 };
diff --git a/services/data_decoder/public/cpp/testing_json_parser.cc b/services/data_decoder/public/cpp/testing_json_parser.cc
index 2cddd953..921f8f7 100644
--- a/services/data_decoder/public/cpp/testing_json_parser.cc
+++ b/services/data_decoder/public/cpp/testing_json_parser.cc
@@ -11,7 +11,7 @@
 #include "base/json/json_reader.h"
 #include "base/location.h"
 #include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/values.h"
 
 namespace data_decoder {
@@ -53,8 +53,8 @@
 
   // Run the callback asynchronously. Post the delete task first, so that the
   // completion callbacks may quit the run loop without leaking |this|.
-  base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
+  base::SequencedTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, value ? base::Bind(success_callback_, base::Passed(&value))
                        : base::Bind(error_callback_, error));
 }
diff --git a/services/identity/identity_accessor_impl.cc b/services/identity/identity_accessor_impl.cc
index afff7d4..666a5e9 100644
--- a/services/identity/identity_accessor_impl.cc
+++ b/services/identity/identity_accessor_impl.cc
@@ -82,14 +82,6 @@
   std::move(callback).Run(account_info, account_state);
 }
 
-void IdentityAccessorImpl::GetAccountInfoFromGaiaId(
-    const std::string& gaia_id,
-    GetAccountInfoFromGaiaIdCallback callback) {
-  AccountInfo account_info = account_tracker_->FindAccountInfoByGaiaId(gaia_id);
-  AccountState account_state = GetStateOfAccount(account_info);
-  std::move(callback).Run(account_info, account_state);
-}
-
 void IdentityAccessorImpl::GetAccessToken(const std::string& account_id,
                                           const ScopeSet& scopes,
                                           const std::string& consumer_id,
diff --git a/services/identity/identity_accessor_impl.h b/services/identity/identity_accessor_impl.h
index d055c80d..97774ab 100644
--- a/services/identity/identity_accessor_impl.h
+++ b/services/identity/identity_accessor_impl.h
@@ -51,9 +51,6 @@
   void GetPrimaryAccountInfo(GetPrimaryAccountInfoCallback callback) override;
   void GetPrimaryAccountWhenAvailable(
       GetPrimaryAccountWhenAvailableCallback callback) override;
-  void GetAccountInfoFromGaiaId(
-      const std::string& gaia_id,
-      GetAccountInfoFromGaiaIdCallback callback) override;
   void GetAccessToken(const std::string& account_id,
                       const ScopeSet& scopes,
                       const std::string& consumer_id,
diff --git a/services/identity/identity_accessor_impl_unittest.cc b/services/identity/identity_accessor_impl_unittest.cc
index b657d336..4093283 100644
--- a/services/identity/identity_accessor_impl_unittest.cc
+++ b/services/identity/identity_accessor_impl_unittest.cc
@@ -64,15 +64,6 @@
     quit_closure.Run();
   }
 
-  void OnReceivedAccountInfoFromGaiaId(
-      base::RepeatingClosure quit_closure,
-      const base::Optional<AccountInfo>& account_info,
-      const AccountState& account_state) {
-    account_info_from_gaia_id_ = account_info;
-    account_state_from_gaia_id_ = account_state;
-    quit_closure.Run();
-  }
-
   void OnGotAccounts(base::RepeatingClosure quit_closure,
                      std::vector<mojom::AccountPtr>* output,
                      std::vector<mojom::AccountPtr> accounts) {
@@ -301,35 +292,14 @@
   // Set the refresh token, but don't sign in yet.
   std::string account_id_to_use =
       identity_test_environment()->MakeAccountAvailable(kTestEmail).account_id;
-
   identity_test_environment()->SetRefreshTokenForAccount(account_id_to_use);
+
   base::RunLoop run_loop;
   GetIdentityAccessorImpl()->GetPrimaryAccountWhenAvailable(base::BindRepeating(
       &IdentityAccessorImplTest::OnPrimaryAccountAvailable,
       base::Unretained(this), run_loop.QuitClosure(),
       base::Unretained(&account_info), base::Unretained(&account_state)));
 
-  // Verify that the account is present and has a refresh token, but that the
-  // primary account is not yet considered available (this also serves to ensure
-  // that the preceding call has been received by the IdentityAccessor before
-  // proceeding).
-  base::RunLoop run_loop2;
-  GetIdentityAccessorImpl()->GetAccountInfoFromGaiaId(
-      kTestGaiaId,
-      base::BindRepeating(
-          &IdentityAccessorImplTest::OnReceivedAccountInfoFromGaiaId,
-          base::Unretained(this), run_loop2.QuitClosure()));
-  run_loop2.Run();
-
-  EXPECT_TRUE(account_info_from_gaia_id_);
-  EXPECT_EQ(account_id_to_use, account_info_from_gaia_id_->account_id);
-  EXPECT_EQ(kTestGaiaId, account_info_from_gaia_id_->gaia);
-  EXPECT_EQ(kTestEmail, account_info_from_gaia_id_->email);
-  EXPECT_TRUE(account_state_from_gaia_id_.has_refresh_token);
-  EXPECT_FALSE(account_state_from_gaia_id_.is_primary_account);
-
-  EXPECT_TRUE(account_info.account_id.empty());
-
   // Sign the user in and check that the callback is invoked as expected (i.e.,
   // the primary account is now considered available).
   std::string primary_account_id =
@@ -435,65 +405,6 @@
   EXPECT_TRUE(account_state.is_primary_account);
 }
 
-// Check that the account info for a given GAIA ID is null if that GAIA ID is
-// unknown.
-TEST_F(IdentityAccessorImplTest, GetAccountInfoForUnknownGaiaID) {
-  base::RunLoop run_loop;
-  GetIdentityAccessorImpl()->GetAccountInfoFromGaiaId(
-      kTestGaiaId,
-      base::BindRepeating(
-          &IdentityAccessorImplTest::OnReceivedAccountInfoFromGaiaId,
-          base::Unretained(this), run_loop.QuitClosure()));
-  run_loop.Run();
-  EXPECT_FALSE(account_info_from_gaia_id_);
-}
-
-// Check that the account info for a given GAIA ID has expected values if that
-// GAIA ID is known and there is no refresh token available for it.
-TEST_F(IdentityAccessorImplTest, GetAccountInfoForKnownGaiaIdNoRefreshToken) {
-  AccountInfo input_info;
-  input_info.email = kTestEmail;
-  input_info.gaia = kTestGaiaId;
-  std::string account_id =
-      identity_test_environment()->identity_manager()->LegacySeedAccountInfo(
-          input_info);
-
-  base::RunLoop run_loop;
-  GetIdentityAccessorImpl()->GetAccountInfoFromGaiaId(
-      kTestGaiaId,
-      base::BindRepeating(
-          &IdentityAccessorImplTest::OnReceivedAccountInfoFromGaiaId,
-          base::Unretained(this), run_loop.QuitClosure()));
-  run_loop.Run();
-  EXPECT_TRUE(account_info_from_gaia_id_);
-  EXPECT_EQ(account_id, account_info_from_gaia_id_->account_id);
-  EXPECT_EQ(kTestGaiaId, account_info_from_gaia_id_->gaia);
-  EXPECT_EQ(kTestEmail, account_info_from_gaia_id_->email);
-  EXPECT_FALSE(account_state_from_gaia_id_.has_refresh_token);
-  EXPECT_FALSE(account_state_from_gaia_id_.is_primary_account);
-}
-
-// Check that the account info for a given GAIA ID has expected values if that
-// GAIA ID is known and has a refresh token available.
-TEST_F(IdentityAccessorImplTest, GetAccountInfoForKnownGaiaIdRefreshToken) {
-  std::string account_id =
-      identity_test_environment()->MakeAccountAvailable(kTestEmail).account_id;
-
-  base::RunLoop run_loop;
-  GetIdentityAccessorImpl()->GetAccountInfoFromGaiaId(
-      kTestGaiaId,
-      base::BindRepeating(
-          &IdentityAccessorImplTest::OnReceivedAccountInfoFromGaiaId,
-          base::Unretained(this), run_loop.QuitClosure()));
-  run_loop.Run();
-  EXPECT_TRUE(account_info_from_gaia_id_);
-  EXPECT_EQ(account_id, account_info_from_gaia_id_->account_id);
-  EXPECT_EQ(kTestGaiaId, account_info_from_gaia_id_->gaia);
-  EXPECT_EQ(kTestEmail, account_info_from_gaia_id_->email);
-  EXPECT_TRUE(account_state_from_gaia_id_.has_refresh_token);
-  EXPECT_FALSE(account_state_from_gaia_id_.is_primary_account);
-}
-
 // Check that the expected error is received if requesting an access token when
 // not signed in.
 TEST_F(IdentityAccessorImplTest, GetAccessTokenNotSignedIn) {
diff --git a/services/identity/public/mojom/identity_accessor.mojom b/services/identity/public/mojom/identity_accessor.mojom
index 4f4f1b9..242c16c 100644
--- a/services/identity/public/mojom/identity_accessor.mojom
+++ b/services/identity/public/mojom/identity_accessor.mojom
@@ -29,13 +29,6 @@
   GetPrimaryAccountWhenAvailable() => (AccountInfo account_info,
                                        AccountState account_state);
 
-  // Returns the AccountInfo for the user's Google account corresponding to
-  // |gaia_id|, or null if the user has such corresponding account.
-  // |account_state| gives the current state of the account (relevant only if
-  // |account_info| is non-null).
-  GetAccountInfoFromGaiaId(string gaia_id) => (AccountInfo? account_info,
-                                               AccountState account_state);
-
   // Returns an access token with the requested scopes for the given
   // |account_id|, or null if it is not possible to obtain such a token (e.g.,
   // because the user is not signed in with that account). |expiration_time|
diff --git a/services/network/cookie_manager_unittest.cc b/services/network/cookie_manager_unittest.cc
index 53a0cbb..44b7b5d 100644
--- a/services/network/cookie_manager_unittest.cc
+++ b/services/network/cookie_manager_unittest.cc
@@ -243,8 +243,7 @@
       scoped_refptr<SessionCleanupCookieStore> cleanup_store) {
     connection_error_seen_ = false;
     cookie_monster_ = std::make_unique<net::CookieMonster>(
-        std::move(store), nullptr /*channel_id_service */,
-        nullptr /* netlog */);
+        std::move(store), nullptr /* netlog */);
     cookie_service_ = std::make_unique<CookieManager>(
         cookie_monster_.get(), std::move(cleanup_store), nullptr);
     cookie_service_->AddRequest(mojo::MakeRequest(&cookie_service_ptr_));
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index d90c044..0493111c 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -1761,7 +1761,7 @@
 
     std::unique_ptr<net::CookieMonster> cookie_store =
         std::make_unique<net::CookieMonster>(session_cleanup_cookie_store.get(),
-                                             nullptr, net_log);
+                                             net_log);
     if (params_->persist_session_cookies)
       cookie_store->SetPersistSessionCookies(true);
 
diff --git a/services/network/public/cpp/is_potentially_trustworthy.cc b/services/network/public/cpp/is_potentially_trustworthy.cc
index 30dc499..5bfa423 100644
--- a/services/network/public/cpp/is_potentially_trustworthy.cc
+++ b/services/network/public/cpp/is_potentially_trustworthy.cc
@@ -156,6 +156,93 @@
 
 }  // namespace
 
+bool IsOriginPotentiallyTrustworthy(const url::Origin& origin) {
+  // The code below is based on the specification at
+  // https://www.w3.org/TR/powerful-features/#is-origin-trustworthy.
+
+  // 1. If origin is an opaque origin, return "Not Trustworthy".
+  if (origin.opaque())
+    return false;
+
+  // 2. Assert: origin is a tuple origin.
+  DCHECK(!origin.opaque());
+
+  // 3. If origin’s scheme is either "https" or "wss", return "Potentially
+  //    Trustworthy".
+  if (GURL::SchemeIsCryptographic(origin.scheme()))
+    return true;
+
+  // 4. If origin’s host component matches one of the CIDR notations 127.0.0.0/8
+  //    or ::1/128 [RFC4632], return "Potentially Trustworthy".
+  //
+  // Diverging from the spec a bit here - in addition to the hostnames covered
+  // by https://www.w3.org/TR/powerful-features/#is-origin-trustworthy, the code
+  // below also considers "localhost" to be potentially secure.
+  //
+  // Cannot just pass |origin.host()| to |HostStringIsLocalhost|, because of the
+  // need to also strip the brackets from things like "[::1]".
+  if (net::IsLocalhost(origin.GetURL()))
+    return true;
+
+  // 5. If origin’s scheme component is file, return "Potentially Trustworthy".
+  //
+  // This is somewhat redundant with the GetLocalSchemes-based check below.
+  if (origin.scheme() == url::kFileScheme)
+    return true;
+
+  // 6. If origin’s scheme component is one which the user agent considers to be
+  //    authenticated, return "Potentially Trustworthy".
+  //    Note: See §7.1 Packaged Applications for detail here.
+  //
+  // Note that this ignores some schemes that are considered trustworthy by
+  // higher layers (e.g. see GetSchemesBypassingSecureContextCheck in //chrome).
+  //
+  // See also
+  // - content::ContentClient::AddAdditionalSchemes and
+  //   content::ContentClient::Schemes::local_schemes and
+  //   content::ContentClient::Schemes::secure_schemes
+  // - url::AddLocalScheme
+  // - url::AddSecureScheme
+  if (base::ContainsValue(url::GetSecureSchemes(), origin.scheme()) ||
+      base::ContainsValue(url::GetLocalSchemes(), origin.scheme())) {
+    return true;
+  }
+
+  // 7. If origin has been configured as a trustworthy origin, return
+  //    "Potentially Trustworthy".
+  //    Note: See §7.2 Development Environments for detail here.
+  if (IsAllowlistedAsSecureOrigin(origin, GetSecureOriginAllowlist()))
+    return true;
+
+  // 8. Return "Not Trustworthy".
+  return false;
+}
+
+bool IsUrlPotentiallyTrustworthy(const GURL& url) {
+  // The code below is based on the specification at
+  // https://www.w3.org/TR/powerful-features/#is-url-trustworthy.
+
+  // 1. If url’s scheme is "data", return "Not Trustworthy".
+  //    Note: This aligns the definition of a secure context with the de facto
+  //    "data: URL as opaque origin" behavior that a majority of today’s
+  //    browsers have agreed upon, rather than the de jure "data: URL inherits
+  //    origin" behavior defined in HTML.
+  if (url.SchemeIs(url::kDataScheme))
+    return false;
+
+  // 2. If url is "about:blank" or "about:srcdoc", return "Potentially
+  //    Trustworthy".
+  if (url.SchemeIs(url::kAboutScheme))
+    return true;
+
+  // 3. Return the result of executing §3.2 Is origin potentially trustworthy?
+  //    on url’s origin.
+  //    Note: The origin of blob: and filesystem: URLs is the origin of the
+  //    context in which they were created. Therefore, blobs created in a
+  //    trustworthy origin will themselves be potentially trustworthy.
+  return IsOriginPotentiallyTrustworthy(url::Origin::Create(url));
+}
+
 const std::vector<std::string>& GetSecureOriginAllowlist() {
   // This function will initialize |s_allowlist| in a thread-safe way because of
   // the way how |static| works - invoking base::NoDestructor's constructor and
diff --git a/services/network/public/cpp/is_potentially_trustworthy.h b/services/network/public/cpp/is_potentially_trustworthy.h
index 279f6c4..e465804b 100644
--- a/services/network/public/cpp/is_potentially_trustworthy.h
+++ b/services/network/public/cpp/is_potentially_trustworthy.h
@@ -17,6 +17,18 @@
 
 namespace network {
 
+// Returns whether an origin is potentially trustworthy according to
+// https://www.w3.org/TR/powerful-features/#is-origin-trustworthy.
+//
+// See also blink::SecurityOrigin::isPotentiallyTrustworthy.
+COMPONENT_EXPORT(NETWORK_CPP)
+bool IsOriginPotentiallyTrustworthy(const url::Origin& origin);
+
+// Returns whether a URL is potentially trustworthy according to
+// https://www.w3.org/TR/powerful-features/#is-url-trustworthy.
+COMPONENT_EXPORT(NETWORK_CPP)
+bool IsUrlPotentiallyTrustworthy(const GURL& url);
+
 // Return an allowlist of origins and hostname patterns that need to be
 // considered trustworthy.  The allowlist is given by the
 // --unsafely-treat-insecure-origin-as-secure command-line option. See
diff --git a/services/network/public/cpp/is_potentially_trustworthy_unittest.cc b/services/network/public/cpp/is_potentially_trustworthy_unittest.cc
index ec7ced4..71818bca 100644
--- a/services/network/public/cpp/is_potentially_trustworthy_unittest.cc
+++ b/services/network/public/cpp/is_potentially_trustworthy_unittest.cc
@@ -17,6 +17,75 @@
                                      network::GetSecureOriginAllowlist());
 }
 
+bool IsPotentiallyTrustworthy(const char* str) {
+  return network::IsUrlPotentiallyTrustworthy(GURL(str));
+}
+
+TEST(IsPotentiallyTrustworthy, MainTest) {
+  const url::Origin unique_origin;
+  EXPECT_FALSE(network::IsOriginPotentiallyTrustworthy(unique_origin));
+  const url::Origin opaque_origin =
+      url::Origin::Create(GURL("https://www.example.com"))
+          .DeriveNewOpaqueOrigin();
+  EXPECT_FALSE(network::IsOriginPotentiallyTrustworthy(opaque_origin));
+
+  EXPECT_TRUE(IsPotentiallyTrustworthy("about:blank"));
+  EXPECT_TRUE(IsPotentiallyTrustworthy("about:blank#ref"));
+  EXPECT_TRUE(IsPotentiallyTrustworthy("about:srcdoc"));
+
+  EXPECT_FALSE(IsPotentiallyTrustworthy("data:test/plain;blah"));
+  EXPECT_FALSE(IsPotentiallyTrustworthy("javascript:alert('blah')"));
+
+  EXPECT_TRUE(IsPotentiallyTrustworthy("file:///test/fun.html"));
+  EXPECT_TRUE(IsPotentiallyTrustworthy("file:///test/"));
+  EXPECT_TRUE(IsPotentiallyTrustworthy("file://localhost/test/"));
+  EXPECT_TRUE(IsPotentiallyTrustworthy("file://otherhost/test/"));
+
+  EXPECT_TRUE(IsPotentiallyTrustworthy("https://example.com/fun.html"));
+  EXPECT_FALSE(IsPotentiallyTrustworthy("http://example.com/fun.html"));
+
+  EXPECT_TRUE(IsPotentiallyTrustworthy("wss://example.com/fun.html"));
+  EXPECT_FALSE(IsPotentiallyTrustworthy("ws://example.com/fun.html"));
+
+  EXPECT_TRUE(IsPotentiallyTrustworthy("http://localhost/fun.html"));
+  EXPECT_TRUE(IsPotentiallyTrustworthy("http://pumpkin.localhost/fun.html"));
+  EXPECT_TRUE(
+      IsPotentiallyTrustworthy("http://crumpet.pumpkin.localhost/fun.html"));
+  EXPECT_TRUE(
+      IsPotentiallyTrustworthy("http://pumpkin.localhost:8080/fun.html"));
+  EXPECT_TRUE(IsPotentiallyTrustworthy(
+      "http://crumpet.pumpkin.localhost:3000/fun.html"));
+  EXPECT_FALSE(IsPotentiallyTrustworthy("http://localhost.com/fun.html"));
+  EXPECT_TRUE(IsPotentiallyTrustworthy("https://localhost.com/fun.html"));
+
+  EXPECT_TRUE(IsPotentiallyTrustworthy("http://127.0.0.1/fun.html"));
+  EXPECT_TRUE(IsPotentiallyTrustworthy("ftp://127.0.0.1/fun.html"));
+  EXPECT_TRUE(IsPotentiallyTrustworthy("http://127.3.0.1/fun.html"));
+  EXPECT_FALSE(IsPotentiallyTrustworthy("http://127.example.com/fun.html"));
+  EXPECT_TRUE(IsPotentiallyTrustworthy("https://127.example.com/fun.html"));
+
+  EXPECT_TRUE(IsPotentiallyTrustworthy("http://[::1]/fun.html"));
+  EXPECT_FALSE(IsPotentiallyTrustworthy("http://[::2]/fun.html"));
+  EXPECT_FALSE(IsPotentiallyTrustworthy("http://[::1].example.com/fun.html"));
+
+  EXPECT_FALSE(
+      IsPotentiallyTrustworthy("filesystem:http://www.example.com/temporary/"));
+  EXPECT_FALSE(
+      IsPotentiallyTrustworthy("filesystem:ftp://www.example.com/temporary/"));
+  EXPECT_TRUE(
+      IsPotentiallyTrustworthy("filesystem:ftp://127.0.0.1/temporary/"));
+  EXPECT_TRUE(IsPotentiallyTrustworthy(
+      "filesystem:https://www.example.com/temporary/"));
+
+  EXPECT_FALSE(
+      IsPotentiallyTrustworthy("blob:http://www.example.com/guid-goes-here"));
+  EXPECT_FALSE(
+      IsPotentiallyTrustworthy("blob:ftp://www.example.com/guid-goes-here"));
+  EXPECT_TRUE(IsPotentiallyTrustworthy("blob:ftp://127.0.0.1/guid-goes-here"));
+  EXPECT_TRUE(
+      IsPotentiallyTrustworthy("blob:https://www.example.com/guid-goes-here"));
+}
+
 class SecureOriginAllowlistTest : public testing::Test {
   void TearDown() override {
     // Ensure that we reset the allowlisted origins without any flags applied.
@@ -29,15 +98,11 @@
       url::Origin::Create(GURL("http://example.com/a.html"))));
   EXPECT_FALSE(IsAllowlistedAsSecureOrigin(
       url::Origin::Create(GURL("http://127.example.com/a.html"))));
-  // TODO(lukasza): Reintegrate this test with IsPotentiallyTrustworthy
-  // function (temporarily still in the //content layer)
-  // EXPECT_FALSE(IsPotentiallyTrustworthy("http://example.com/a.html"));
-  // EXPECT_FALSE(IsPotentiallyTrustworthy("http://127.example.com/a.html"));
+  EXPECT_FALSE(IsPotentiallyTrustworthy("http://example.com/a.html"));
+  EXPECT_FALSE(IsPotentiallyTrustworthy("http://127.example.com/a.html"));
 
   // Add http://example.com and http://127.example.com to allowlist by
   // command-line and see if they are now considered secure origins.
-  // (The command line is applied via
-  // ChromeContentClient::AddSecureSchemesAndOrigins)
   base::test::ScopedCommandLine scoped_command_line;
   base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
   command_line->AppendSwitchASCII(
@@ -50,17 +115,13 @@
       url::Origin::Create(GURL("http://example.com/a.html"))));
   EXPECT_TRUE(IsAllowlistedAsSecureOrigin(
       url::Origin::Create(GURL("http://127.example.com/a.html"))));
-  // TODO(lukasza): Reintegrate this test with IsPotentiallyTrustworthy
-  // function (temporarily still in the //content layer)
-  // EXPECT_TRUE(IsPotentiallyTrustworthy("http://example.com/a.html"));
-  // EXPECT_TRUE(IsPotentiallyTrustworthy("http://127.example.com/a.html"));
+  EXPECT_TRUE(IsPotentiallyTrustworthy("http://example.com/a.html"));
+  EXPECT_TRUE(IsPotentiallyTrustworthy("http://127.example.com/a.html"));
 
   // Check that similarly named sites are not considered secure.
-  // TODO(lukasza): Reintegrate this test with IsPotentiallyTrustworthy
-  // function (temporarily still in the //content layer)
-  // EXPECT_FALSE(IsPotentiallyTrustworthy("http://128.example.com/a.html"));
-  // EXPECT_FALSE(
-  //    IsPotentiallyTrustworthy("http://foobar.127.example.com/a.html"));
+  EXPECT_FALSE(IsPotentiallyTrustworthy("http://128.example.com/a.html"));
+  EXPECT_FALSE(
+      IsPotentiallyTrustworthy("http://foobar.127.example.com/a.html"));
 }
 
 TEST_F(SecureOriginAllowlistTest, HostnamePatterns) {
@@ -102,10 +163,7 @@
     GURL input_url(test.test_input);
     url::Origin input_origin = url::Origin::Create(input_url);
     EXPECT_EQ(test.expected_secure, IsAllowlistedAsSecureOrigin(input_origin));
-    // TODO(lukasza): Reintegrate this test with IsPotentiallyTrustworthy
-    // function (temporarily still in the //content layer)
-    // EXPECT_EQ(test.expected_secure,
-    // IsPotentiallyTrustworthy(test.test_input));
+    EXPECT_EQ(test.expected_secure, IsPotentiallyTrustworthy(test.test_input));
   }
 }
 
diff --git a/services/network/restricted_cookie_manager_unittest.cc b/services/network/restricted_cookie_manager_unittest.cc
index 5a204d3..7b6ea91a 100644
--- a/services/network/restricted_cookie_manager_unittest.cc
+++ b/services/network/restricted_cookie_manager_unittest.cc
@@ -84,7 +84,7 @@
 class RestrictedCookieManagerTest : public testing::Test {
  public:
   RestrictedCookieManagerTest()
-      : cookie_monster_(nullptr, nullptr, nullptr /* netlog */),
+      : cookie_monster_(nullptr, nullptr /* netlog */),
         service_(std::make_unique<RestrictedCookieManager>(
             &cookie_monster_,
             &cookie_settings_,
diff --git a/services/resource_coordinator/public/mojom/signals.mojom b/services/resource_coordinator/public/mojom/signals.mojom
index d0b4a948..a269924 100644
--- a/services/resource_coordinator/public/mojom/signals.mojom
+++ b/services/resource_coordinator/public/mojom/signals.mojom
@@ -27,9 +27,6 @@
   kCPUUsage,
   kExpectedTaskQueueingDuration,
   kMainThreadTaskLoadIsLow,
-  // Network is considered almost idle when there's no more than 2 network
-  // connections.
-  kNetworkAlmostIdle,
   kPID,
   kUKMSourceId,
   kLifecycleState,
diff --git a/services/ws/public/mojom/window_manager.mojom b/services/ws/public/mojom/window_manager.mojom
index 9b9e0df..99cef472 100644
--- a/services/ws/public/mojom/window_manager.mojom
+++ b/services/ws/public/mojom/window_manager.mojom
@@ -69,6 +69,9 @@
   // A small version of the application icon. Type: SkBitmap
   const string kAppIconSmall_Property = "prop:app-icon-small";
 
+  // The avatar icon to display in the frame header, if any. Type: SkBitmap
+  const string kAvatarIcon_Property = "prop:avatar-icon";
+
   // The Android Java-style package name for an ARC++ window, such as
   // "com.google.Photos". Type: mojom::String.
   const string kArcPackageName_Property = "prop:arc-package-name";
diff --git a/styleguide/c++/c++-dos-and-donts.md b/styleguide/c++/c++-dos-and-donts.md
index 8a3df325..9f5f4bf 100644
--- a/styleguide/c++/c++-dos-and-donts.md
+++ b/styleguide/c++/c++-dos-and-donts.md
@@ -14,7 +14,7 @@
 If a file isn't using the symbols from some header, remove the header. It turns
 out that this happens frequently in the Chromium codebase due to refactoring.
 
-### Move inner classes into the implementation
+### Move helper / inner classes into the implementation
 
 You can also forward declare classes inside a class:
 
@@ -42,39 +42,6 @@
 require the full definition at declaration time (most notably, std::deque and
 the STL adapters that wrap it).
 
-### Move static implementation details to the implementation whenever possible
-
-If you have the class in a header file, you should try to move that from a class
-member into the anonymous namespace in the implementation file.
-
-DON'T:
-
-```cpp
-#include "BigImplementationDetail.h"
-class PublicInterface {
-  public:
-   /* ... */
-  private:
-   static BigImplementationDetail detail_;
-};
-```
-
-DO:
-
-```cpp
-namespace {
-BigImplementationDetail g_detail;
-}  // namespace
-```
-
-That way, people who don't use your interface don't need to know about or care
-about `BigImplementationDetail`.
-
-You can do this for helper functions, too.  Note that if there is more than one
-class in the .cc file, it can aid clarity to define your translation-unit-scope
-helpers in an anonymous namespace just above the class that uses them, instead
-of at the top of the file.
-
 ## Stop inlining code in headers
 
 *** note
@@ -700,4 +667,4 @@
 ```cpp
 // FooImpl implements the FooBase class.
 // FooFunction() modifies |foo_member_|.
-```
\ No newline at end of file
+```
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index e161fab..b314aaf 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -6215,6 +6215,706 @@
       }
     ]
   },
+  "linux-chromeos-code-coverage": {
+    "additional_compile_targets": [
+      "gn_all"
+    ],
+    "gtest_tests": [
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "accessibility_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "angle_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "app_list_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "app_shell_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ash_unittests"
+      },
+      {
+        "args": [
+          "--disable-features=SingleProcessMash"
+        ],
+        "name": "non_single_process_mash_ash_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ash_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "aura_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "blink_common_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "blink_heap_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "blink_platform_unittests"
+      },
+      {
+        "name": "webkit_unit_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "blink_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "boringssl_crypto_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "boringssl_ssl_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 10
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
+          "--enable-features=Mash",
+          "--disable-features=SingleProcessMash",
+          "--override-use-software-gl-for-tests",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.mash.browser_tests.filter"
+        ],
+        "name": "mash_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "hard_timeout": 1800
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
+          "--disable-features=SingleProcessMash",
+          "--override-use-software-gl-for-tests"
+        ],
+        "name": "non_single_process_mash_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 10
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
+          "--enable-features=VizDisplayCompositor"
+        ],
+        "name": "viz_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 10
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
+          "--disable-features=WebUIPolymer2",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/webui_polymer1_browser_tests.filter"
+        ],
+        "name": "webui_polymer1_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 4
+        },
+        "test": "browser_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cacheinvalidation_unittests"
+      },
+      {
+        "args": [
+          "--gtest_filter=-*UsingRealWebcam*"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "capture_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cast_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cc_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "chrome_app_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "chromedriver_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "chromeos_components_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "chromeos_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "components_browsertests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "components_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "compositor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 6
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
+          "--disable-features=SingleProcessMash",
+          "--override-use-software-gl-for-tests"
+        ],
+        "name": "non_single_process_mash_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 5
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
+          "--enable-perfetto",
+          "--gtest_filter=TracingControllerTest.*"
+        ],
+        "name": "perfetto_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
+          "--enable-features=VizDisplayCompositor"
+        ],
+        "name": "viz_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 10
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
+        "args": [
+          "--disable-features=SingleProcessMash"
+        ],
+        "name": "non_single_process_mash_content_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
+        "args": [
+          "--enable-features=VizDisplayCompositor"
+        ],
+        "name": "viz_content_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "crypto_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "dbus_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "device_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "display_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "events_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "exo_unittests"
+      },
+      {
+        "args": [
+          "--disable-features=SingleProcessMash"
+        ],
+        "name": "non_single_process_mash_exo_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "exo_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "extensions_browsertests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "extensions_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "filesystem_service_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gcm_unit_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gfx_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gin_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gl_unittests_ozone"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "google_apis_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gpu_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 3
+        },
+        "test": "interactive_ui_tests"
+      },
+      {
+        "args": [
+          "--disable-features=SingleProcessMash"
+        ],
+        "name": "non_single_process_mash_interactive_ui_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 3
+        },
+        "test": "interactive_ui_tests"
+      },
+      {
+        "args": [
+          "--disable-features=WebUIPolymer2",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/webui_polymer1_interactive_ui_tests.filter"
+        ],
+        "name": "webui_polymer1_interactive_ui_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "interactive_ui_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ipc_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "jingle_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "keyboard_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "latency_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "leveldb_service_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "libjingle_xmpp_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "media_blink_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "media_service_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "media_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "message_center_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "mojo_core_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "mojo_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "nacl_helper_nonsfi_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "nacl_loader_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "native_theme_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "net_unittests"
+      },
+      {
+        "args": [
+          "--ozone-platform=headless"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ozone_gl_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ozone_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ozone_x11_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "pdf_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ppapi_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "printing_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "remoting_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "sandbox_linux_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "service_manager_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "services_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "shell_dialogs_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "skia_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "snapshot_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "sql_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "storage_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "sync_integration_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ui_base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ui_chromeos_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ui_touch_selection_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "unit_tests"
+      },
+      {
+        "args": [
+          "--disable-features=SingleProcessMash"
+        ],
+        "name": "non_single_process_mash_unit_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "unit_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "url_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "views_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "viz_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "wayland_client_perftests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "wm_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "wtf_unittests"
+      }
+    ]
+  },
   "linux-chromium-tests-staging-builder": {
     "additional_compile_targets": [
       "all"
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 432616c..96c373e9 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -4563,6 +4563,38 @@
       }
     ]
   },
+  "Android FYI Release (Pixel 2)": {
+    "isolated_scripts": [
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=android-chromium",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--webgl-conformance-version=2.0.1",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "webgl2_conformance_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "P",
+              "device_type": "walleye",
+              "os": "Android",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "idempotent": false,
+          "shards": 20
+        }
+      }
+    ]
+  },
   "Android FYI dEQP Release (Nexus 5X)": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json
index e4d46d9..9ee9894 100644
--- a/testing/buildbot/chromium.perf.fyi.json
+++ b/testing/buildbot/chromium.perf.fyi.json
@@ -184,10 +184,8 @@
       {
         "args": [
           "-v",
-          "--browser=exact",
+          "--browser=android-chrome",
           "--upload-results",
-          "--browser-executable=../../out/Release/bin/monochrome_64_32_bundle",
-          "--device=android",
           "--run-ref-build",
           "--test-shard-map-filename=android-pixel2-perf_map.json"
         ],
diff --git a/testing/buildbot/filters/mojo.fyi.network_chrome_public_test_apk.filter b/testing/buildbot/filters/mojo.fyi.network_chrome_public_test_apk.filter
index 7c207874..cefdd29 100644
--- a/testing/buildbot/filters/mojo.fyi.network_chrome_public_test_apk.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_chrome_public_test_apk.filter
@@ -13,3 +13,10 @@
 -org.chromium.chrome.browser.webapps.WebApkIntegrationTest.testLaunchAndNavigateOffOrigin
 -org.chromium.chrome.browser.webapps.WebApkIntegrationTest.testLaunchAndNavigationInNewWindowOffandInOrigin
 -org.chromium.chrome.browser.webapps.WebApkIntegrationTest.testLaunchAndOpenNewWindowInOrigin
+
+# Miscellaneous flaky or failing tests:
+# http://crbug.com/941856
+-org.chromium.chrome.browser.webapps.WebApkIntegrationTest#testActivateWebApk
+
+# http://crbug.com/941858
+-org.chromium.chrome.browser.payments.PaymentRequestUpdateWithTest#testUpdateWithShippingOptions
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 64f7b38..6a97f8a 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -3403,6 +3403,24 @@
       },
     },
 
+    'gpu_fyi_optional_android_release_specific_telemetry_tests': {
+      'webgl2_conformance_tests': {
+        'telemetry_test_name': 'webgl_conformance',
+        'args': [
+          '--webgl-conformance-version=2.0.1',
+          # The current working directory when run via isolate is
+          # out/Debug or out/Release. Reference this file relatively to
+          # it.
+          '--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json',
+        ],
+        'swarming': {
+          # These tests currently take about an hour and fifteen minutes
+          # to run. Split them into roughly 5-minute shards.
+          'shards': 20,
+        },
+      },
+    },
+
     'gpu_fyi_vulkan_gtests': {
       'vulkan_content_browsertests': {
         'args': [
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index f8c703b..c3eec97 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -1506,6 +1506,14 @@
           'shards': 20,
         },
       },
+      'linux-chromeos-code-coverage': {
+        'additional_compile_targets': [
+          'gn_all',
+        ],
+        'test_suites': {
+          'gtest_tests': 'linux_chromeos_gtests',
+        },
+      },
       'linux-chromium-tests-staging-builder': {
         'additional_compile_targets': [
           'all'
@@ -2155,6 +2163,21 @@
           'gpu_telemetry_tests': 'gpu_common_telemetry_tests',
         },
       },
+      'Android FYI Release (Pixel 2)': {
+        'browser_config': 'android-chromium',
+        'os_type': 'android',
+        'skip_merge_script': True,
+        'mixins': [
+          'gpu_pool',
+          'pie',
+          'walleye',
+        ],
+        'test_suites': {
+          # We currently only want to run the WebGL 2.0 conformance tests on
+          # this until additional Pixel 2 capacity is added.
+          'gpu_telemetry_tests': 'gpu_fyi_optional_android_release_specific_telemetry_tests',
+        },
+      },
       'Android FYI dEQP Release (Nexus 5X)': {
         'os_type': 'android',
         'skip_merge_script': True,
diff --git a/testing/scripts/get_compile_targets.py b/testing/scripts/get_compile_targets.py
index 16cff95..014272e 100755
--- a/testing/scripts/get_compile_targets.py
+++ b/testing/scripts/get_compile_targets.py
@@ -27,7 +27,9 @@
   for filename in os.listdir(common.SCRIPT_DIR):
     if not filename.endswith('.py'):
       continue
-    if filename in ('common.py', 'get_compile_targets.py'):
+    if filename in ('common.py',
+                    'get_compile_targets.py',
+                    'gpu_integration_test_adapter.py'):
       continue
 
     with common.temporary_file() as tempfile_path:
diff --git a/testing/scripts/gpu_integration_test_adapter.py b/testing/scripts/gpu_integration_test_adapter.py
new file mode 100644
index 0000000..e62c501
--- /dev/null
+++ b/testing/scripts/gpu_integration_test_adapter.py
@@ -0,0 +1,34 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import common
+
+class GpuIntegrationTestAdapater(common.BaseIsolatedScriptArgsAdapter):
+
+  def generate_test_output_args(self, output):
+    return ['--write-full-results-to', output]
+
+  def generate_test_also_run_disabled_tests_args(self):
+    return ['--also-run-disabled-tests']
+
+  def generate_test_filter_args(self, test_filter_str):
+    filter_list = common.extract_filter_list(test_filter_str)
+    # isolated_script_test_filter comes in like:
+    #   gpu_tests.webgl_conformance_integration_test.WebGLConformanceIntegrationTest.WebglExtension_WEBGL_depth_texture  # pylint: disable=line-too-long
+    # but we need to pass it to --test-filter like this:
+    #   WebglExtension_WEBGL_depth_texture
+    filter_list = [f.split('.')[-1] for f in filter_list]
+    # Need to convert this to a valid regex.
+    filter_regex = '(' + '|'.join(filter_list) + ')'
+    return ['--test-filter=%s' % filter_regex]
+
+  def generate_sharding_args(self, total_shards, shard_index):
+    return ['--total-shards=%d' % total_shards,
+            '--shard-index=%d' % shard_index]
+
+  def generate_test_launcher_retry_limit_args(self, retry_limit):
+    return ['--retry-limit=%d' % retry_limit]
+
+  def generate_test_repeat_args(self, repeat_count):
+    return ['--repeat=%d' % repeat_count]
diff --git a/testing/scripts/run_gpu_integration_test_as_googletest.py b/testing/scripts/run_gpu_integration_test_as_googletest.py
index 6a65ee4..fd48ec4 100755
--- a/testing/scripts/run_gpu_integration_test_as_googletest.py
+++ b/testing/scripts/run_gpu_integration_test_as_googletest.py
@@ -28,45 +28,14 @@
 """
 
 import json
-import os
-import shutil
 import sys
-import tempfile
-import traceback
 
 import common
+import gpu_integration_test_adapter
 
-class GpuIntegrationTestAdapater(common.BaseIsolatedScriptArgsAdapter):
-
-  def generate_test_output_args(self, output):
-    return ['--write-full-results-to', output]
-
-  def generate_test_also_run_disabled_tests_args(self):
-    return ['--also-run-disabled-tests']
-
-  def generate_test_filter_args(self, test_filter_str):
-    filter_list = common.extract_filter_list(test_filter_str)
-    # isolated_script_test_filter comes in like:
-    #   gpu_tests.webgl_conformance_integration_test.WebGLConformanceIntegrationTest.WebglExtension_WEBGL_depth_texture  # pylint: disable=line-too-long
-    # but we need to pass it to --test-filter like this:
-    #   WebglExtension_WEBGL_depth_texture
-    filter_list = [f.split('.')[-1] for f in filter_list]
-    # Need to convert this to a valid regex.
-    filter_regex = '(' + '|'.join(filter_list) + ')'
-    return ['--test-filter=%s' % filter_regex]
-
-  def generate_sharding_args(self, total_shards, shard_index):
-    return ['--total-shards=%d' % total_shards,
-            '--shard-index=%d' % shard_index]
-
-  def generate_test_launcher_retry_limit_args(self, retry_limit):
-    return ['--retry-limit=%d' % retry_limit]
-
-  def generate_test_repeat_args(self, repeat_count):
-    return ['--repeat=%d' % repeat_count]
 
 def main():
-  adapter = GpuIntegrationTestAdapater()
+  adapter = gpu_integration_test_adapter.GpuIntegrationTestAdapater()
   return adapter.run_test()
 
 
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 3d14e7d..8e44bec5 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -34,6 +34,10 @@
 const base::Feature kFirstContentfulPaintPlusPlus{
     "FirstContentfulPaintPlusPlus", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Perform memory purges after freezing only if all pages are frozen.
+const base::Feature kFreezePurgeMemoryAllPagesFrozen{
+    "FreezePurgeMemoryAllPagesFrozen", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables the experimental sweep-line algorithm for tracking "jank" from
 // layout objects changing their visual location between animation frames.
 const base::Feature kJankTrackingSweepLine{"JankTrackingSweepLine",
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 7ac37872..cb90f2d 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -18,6 +18,7 @@
     kEnableGpuRasterizationViewportRestriction;
 BLINK_COMMON_EXPORT extern const base::Feature kScriptStreaming;
 BLINK_COMMON_EXPORT extern const base::Feature kFirstContentfulPaintPlusPlus;
+BLINK_COMMON_EXPORT extern const base::Feature kFreezePurgeMemoryAllPagesFrozen;
 BLINK_COMMON_EXPORT extern const base::Feature kImplicitRootScroller;
 BLINK_COMMON_EXPORT extern const base::Feature kJankTrackingSweepLine;
 BLINK_COMMON_EXPORT extern const base::Feature kBlinkGenPropertyTrees;
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index 08c2bf8..6d9f923a 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -1659,16 +1659,21 @@
   }
 
   if (const auto* primitive_value = DynamicTo<CSSPrimitiveValue>(value)) {
-    if ((primitive_value->IsCalculated() &&
-         (primitive_value->IsCalculatedPercentageWithLength() ||
-          primitive_value->IsLength() || primitive_value->IsPercentage())) ||
-        CSSPrimitiveValue::IsRelativeUnit(
-            primitive_value->TypeWithCalcResolved())) {
+    // For simple (non-calculated) px or percentage values, we do not need to
+    // convert, as the value already has the proper computed form.
+    if (!primitive_value->IsCalculated() &&
+        (primitive_value->IsPx() || primitive_value->IsPercentage())) {
+      return value;
+    }
+
+    if (primitive_value->IsLength() || primitive_value->IsPercentage() ||
+        primitive_value->IsCalculatedPercentageWithLength()) {
       // Instead of the actual zoom, use 1 to avoid potential rounding errors
       Length length = primitive_value->ConvertToLength(
           css_to_length_conversion_data.CopyWithAdjustedZoom(1));
       return *CSSPrimitiveValue::Create(length, 1);
     }
+
     // If we encounter a calculated number that was not resolved during
     // parsing, it means that a calc()-expression was allowed in place of
     // an integer. Such calc()-for-integers must be rounded at computed value
diff --git a/third_party/blink/renderer/core/feature_policy/feature_policy.cc b/third_party/blink/renderer/core/feature_policy/feature_policy.cc
index 9d3cdc2..c0404af 100644
--- a/third_party/blink/renderer/core/feature_policy/feature_policy.cc
+++ b/third_party/blink/renderer/core/feature_policy/feature_policy.cc
@@ -37,10 +37,6 @@
     return false;
   }
 
-  // Impossible to know without an ExecutionContext, so block.
-  if (!execution_context)
-    return true;
-
   // Check whether this feature's origin trial is enabled, and block otherwise.
   DCHECK(origin_trial_enabled);
   return !origin_trial_enabled(execution_context);
diff --git a/third_party/blink/renderer/core/html/resources/html.css b/third_party/blink/renderer/core/html/resources/html.css
index 96fd1f8..ccf544a 100644
--- a/third_party/blink/renderer/core/html/resources/html.css
+++ b/third_party/blink/renderer/core/html/resources/html.css
@@ -559,10 +559,16 @@
 /* TODO(crbug.com/880258): Use different styles for
   `-internal-autofill-previewed` and `-internal-autofill-selected`. */
 input:-internal-autofill-previewed,
-input:-internal-autofill-selected,
 textarea:-internal-autofill-previewed,
+select:-internal-autofill-previewed {
+  font-family: system-ui !important;
+  background-color: #E8F0FE !important;
+  background-image:none !important;
+  color: #000000 !important;
+}
+
+input:-internal-autofill-selected,
 textarea:-internal-autofill-selected,
-select:-internal-autofill-previewed,
 select:-internal-autofill-selected {
   background-color: #E8F0FE !important;
   background-image:none !important;
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
index 0dbca64..c41c4b5 100644
--- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl
+++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -4821,11 +4821,6 @@
       # Whether to paint size or not.
       boolean show
 
-  command setSuspended
-    parameters
-      # Whether overlay should be suspended and not consume any resources until resumed.
-      boolean suspended
-
   # Fired when the node should be inspected. This happens after call to `setInspectMode` or when
   # user manually inspects an element.
   event inspectNodeRequested
diff --git a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
index fe5add9..e472b20 100644
--- a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
@@ -266,7 +266,6 @@
       swallow_next_escape_up_(false),
       backend_node_id_to_inspect_(0),
       enabled_(&agent_state_, false),
-      suspended_(&agent_state_, false),
       show_ad_highlights_(&agent_state_, false),
       show_debug_borders_(&agent_state_, false),
       show_fps_counter_(&agent_state_, false),
@@ -296,6 +295,8 @@
 }
 
 void InspectorOverlayAgent::Restore() {
+  if (enabled_.Get())
+    enable();
   setShowAdHighlights(show_ad_highlights_.Get());
   setShowDebugBorders(show_debug_borders_.Get());
   setShowFPSCounter(show_fps_counter_.Get());
@@ -303,14 +304,12 @@
   setShowScrollBottleneckRects(show_scroll_bottleneck_rects_.Get());
   setShowHitTestBorders(show_hit_test_borders_.Get());
   setShowViewportSizeOnResize(show_size_on_resize_.Get());
-  setSuspended(suspended_.Get());
   PickTheRightTool();
 }
 
 void InspectorOverlayAgent::Dispose() {
   InspectorBaseAgent::Dispose();
   disposed_ = true;
-  ClearInternal();
 }
 
 Response InspectorOverlayAgent::enable() {
@@ -335,10 +334,18 @@
   setShowScrollBottleneckRects(false);
   setShowHitTestBorders(false);
   setShowViewportSizeOnResize(false);
-  setSuspended(false);
   paused_in_debugger_message_.Clear();
   inspect_mode_.Set(protocol::Overlay::InspectModeEnum::None);
   inspect_mode_protocol_config_.Set(String());
+  if (overlay_page_) {
+    overlay_page_->WillBeDestroyed();
+    overlay_page_.Clear();
+    overlay_chrome_client_.Clear();
+    overlay_host_->ClearListener();
+    overlay_host_.Clear();
+  }
+  timer_.Stop();
+  frame_overlay_.reset();
   PickTheRightTool();
   SetNeedsUnbufferedInput(false);
   return Response::OK();
@@ -444,14 +451,6 @@
   return Response::OK();
 }
 
-Response InspectorOverlayAgent::setSuspended(bool suspended) {
-  if (suspended && !suspended_.Get())
-    ClearInternal();
-  suspended_.Set(suspended);
-  SetNeedsUnbufferedInput(!suspended);
-  return Response::OK();
-}
-
 Response InspectorOverlayAgent::highlightRect(
     int x,
     int y,
@@ -772,8 +771,6 @@
 bool InspectorOverlayAgent::IsEmpty() {
   if (disposed_)
     return true;
-  if (suspended_.Get())
-    return true;
   bool has_visible_elements =
       highlight_node_ || event_target_node_ || highlight_quad_ ||
       (resize_timer_active_ && show_size_on_resize_.Get());
@@ -1043,23 +1040,6 @@
   ScheduleUpdate();
 }
 
-void InspectorOverlayAgent::ClearInternal() {
-  if (overlay_page_) {
-    overlay_page_->WillBeDestroyed();
-    overlay_page_.Clear();
-    overlay_chrome_client_.Clear();
-    overlay_host_->ClearListener();
-    overlay_host_.Clear();
-  }
-  resize_timer_active_ = false;
-  paused_in_debugger_message_.Clear();
-  inspect_mode_.Set(protocol::Overlay::InspectModeEnum::None);
-  inspect_mode_protocol_config_.Set(String());
-  timer_.Stop();
-  frame_overlay_.reset();
-  PickTheRightTool();
-}
-
 void InspectorOverlayAgent::OverlayResumed() {
   if (v8_session_)
     v8_session_->resume();
diff --git a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
index a918309eda..bd6c0ca9 100644
--- a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.h
@@ -121,7 +121,6 @@
   protocol::Response setShowViewportSizeOnResize(bool) override;
   protocol::Response setPausedInDebuggerMessage(
       protocol::Maybe<String>) override;
-  protocol::Response setSuspended(bool) override;
   protocol::Response setInspectMode(
       const String& mode,
       protocol::Maybe<protocol::Overlay::HighlightConfig>) override;
@@ -200,7 +199,6 @@
   void RebuildOverlayPage();
   void Invalidate();
   void ScheduleUpdate();
-  void ClearInternal();
 
   protocol::Response CompositingEnabled();
 
@@ -244,7 +242,6 @@
   bool swallow_next_escape_up_;
   DOMNodeId backend_node_id_to_inspect_;
   InspectorAgentState::Boolean enabled_;
-  InspectorAgentState::Boolean suspended_;
   InspectorAgentState::Boolean show_ad_highlights_;
   InspectorAgentState::Boolean show_debug_borders_;
   InspectorAgentState::Boolean show_fps_counter_;
diff --git a/third_party/blink/renderer/core/layout/overflow_model.h b/third_party/blink/renderer/core/layout/overflow_model.h
index 467a4e4..b8ee53c 100644
--- a/third_party/blink/renderer/core/layout/overflow_model.h
+++ b/third_party/blink/renderer/core/layout/overflow_model.h
@@ -159,8 +159,6 @@
 // visual overflow.
 
 class BoxLayoutOverflowModel {
-  USING_FAST_MALLOC(BoxLayoutOverflowModel);
-
  public:
   BoxLayoutOverflowModel(const LayoutRect& layout_rect)
       : layout_overflow_(layout_rect) {}
@@ -186,8 +184,6 @@
 };
 
 class BoxVisualOverflowModel {
-  USING_FAST_MALLOC(BoxVisualOverflowModel);
-
  public:
   BoxVisualOverflowModel(const LayoutRect& self_visual_overflow_rect)
       : self_visual_overflow_(self_visual_overflow_rect) {}
@@ -237,6 +233,8 @@
 struct BoxOverflowModel {
   base::Optional<BoxLayoutOverflowModel> layout_overflow;
   base::Optional<BoxVisualOverflowModel> visual_overflow;
+
+  USING_FAST_MALLOC(BoxOverflowModel);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
index 126877a..d0e7234 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
+++ b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
@@ -9,6 +9,7 @@
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/element_traversal.h"
 #include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/events/keyboard_event.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
@@ -143,10 +144,23 @@
     KeyboardEvent* event) {
   DCHECK(page_->GetSettings().GetSpatialNavigationEnabled());
 
+  // TODO(bokan): KeyboardEventManager sends non-arrow keys here. KEM should
+  // filter out the non-arrow keys for us.
   SpatialNavigationDirection direction = FocusDirectionForKey(event);
   if (direction == SpatialNavigationDirection::kNone)
     return false;
 
+  // In focusless mode, the user must explicitly move focus in and out of an
+  // editable so we can avoid advancing interest and we should swallow the
+  // event. This prevents double-handling actions for things like search box
+  // suggestions.
+  if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) {
+    LocalFrame* frame =
+        DynamicTo<LocalFrame>(page_->GetFocusController().FocusedOrMainFrame());
+    if (frame->Selection().SelectionHasFocus())
+      return true;
+  }
+
   return Advance(direction);
 }
 
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 5b4acfe..38113da 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -940,7 +940,6 @@
         state.direct_compositing_reasons =
             full_context_.direct_compositing_reasons &
             CompositingReason::kDirectReasonsForEffectProperty;
-        CompositingReasonFinder::CompositingReasonsForAnimation(style);
         if (state.direct_compositing_reasons) {
           state.compositor_element_id = CompositorElementIdFromUniqueObjectId(
               object_.UniqueId(), CompositorElementIdNamespace::kPrimaryEffect);
diff --git a/third_party/blink/renderer/devtools/front_end/common/Settings.js b/third_party/blink/renderer/devtools/front_end/common/Settings.js
index 9652e59..8b5aeab 100644
--- a/third_party/blink/renderer/devtools/front_end/common/Settings.js
+++ b/third_party/blink/renderer/devtools/front_end/common/Settings.js
@@ -272,9 +272,10 @@
   /**
    * @param {function(!Common.Event)} listener
    * @param {!Object=} thisObject
+   * @return {!Common.EventTarget.EventDescriptor}
    */
   addChangeListener(listener, thisObject) {
-    this._eventSupport.addEventListener(this._name, listener, thisObject);
+    return this._eventSupport.addEventListener(this._name, listener, thisObject);
   }
 
   /**
diff --git a/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeView.js b/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeView.js
index 144a61b..2691b18 100644
--- a/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeView.js
+++ b/third_party/blink/renderer/devtools/front_end/emulation/DeviceModeView.js
@@ -376,9 +376,7 @@
    * @return {!Promise}
    */
   async captureScreenshot() {
-    SDK.OverlayModel.muteHighlight();
     const screenshot = await this._model.captureScreenshot(false);
-    SDK.OverlayModel.unmuteHighlight();
     if (screenshot === null)
       return;
 
@@ -411,9 +409,7 @@
    * @return {!Promise}
    */
   async captureFullSizeScreenshot() {
-    SDK.OverlayModel.muteHighlight();
     const screenshot = await this._model.captureScreenshot(true);
-    SDK.OverlayModel.unmuteHighlight();
     if (screenshot === null)
       return;
     return this._saveScreenshotBase64(screenshot);
@@ -424,9 +420,7 @@
    * @return {!Promise}
    */
   async captureAreaScreenshot(clip) {
-    SDK.OverlayModel.muteHighlight();
     const screenshot = await this._model.captureScreenshot(false, clip);
-    SDK.OverlayModel.unmuteHighlight();
     if (screenshot === null)
       return;
     return this._saveScreenshotBase64(screenshot);
diff --git a/third_party/blink/renderer/devtools/front_end/sdk/OverlayModel.js b/third_party/blink/renderer/devtools/front_end/sdk/OverlayModel.js
index 7833a9d..e4932a9 100644
--- a/third_party/blink/renderer/devtools/front_end/sdk/OverlayModel.js
+++ b/third_party/blink/renderer/devtools/front_end/sdk/OverlayModel.js
@@ -15,8 +15,6 @@
 
     target.registerOverlayDispatcher(this);
     this._overlayAgent = target.overlayAgent();
-    this._overlayAgent.enable();
-    this._overlayAgent.setShowViewportSizeOnResize(true);
 
     this._debuggerModel = target.model(SDK.DebuggerModel);
     if (this._debuggerModel) {
@@ -36,43 +34,18 @@
     this._highlighter = this._defaultHighlighter;
 
     this._showPaintRectsSetting = Common.moduleSetting('showPaintRects');
-    this._showPaintRectsSetting.addChangeListener(
-        () => this._overlayAgent.setShowPaintRects(this._showPaintRectsSetting.get()));
-    if (this._showPaintRectsSetting.get())
-      this._overlayAgent.setShowPaintRects(true);
-
     this._showAdHighlightsSetting = Common.moduleSetting('showAdHighlights');
-    this._showAdHighlightsSetting.addChangeListener(
-        () => this._overlayAgent.setShowAdHighlights(this._showAdHighlightsSetting.get()));
-    if (this._showAdHighlightsSetting.get())
-      this._overlayAgent.setShowAdHighlights(true);
-
     this._showDebugBordersSetting = Common.moduleSetting('showDebugBorders');
-    this._showDebugBordersSetting.addChangeListener(
-        () => this._overlayAgent.setShowDebugBorders(this._showDebugBordersSetting.get()));
-    if (this._showDebugBordersSetting.get())
-      this._overlayAgent.setShowDebugBorders(true);
-
     this._showFPSCounterSetting = Common.moduleSetting('showFPSCounter');
-    this._showFPSCounterSetting.addChangeListener(
-        () => this._overlayAgent.setShowFPSCounter(this._showFPSCounterSetting.get()));
-    if (this._showFPSCounterSetting.get())
-      this._overlayAgent.setShowFPSCounter(true);
-
     this._showScrollBottleneckRectsSetting = Common.moduleSetting('showScrollBottleneckRects');
-    this._showScrollBottleneckRectsSetting.addChangeListener(
-        () => this._overlayAgent.setShowScrollBottleneckRects(this._showScrollBottleneckRectsSetting.get()));
-    if (this._showScrollBottleneckRectsSetting.get())
-      this._overlayAgent.setShowScrollBottleneckRects(true);
-
     this._showHitTestBordersSetting = Common.moduleSetting('showHitTestBorders');
-    this._showHitTestBordersSetting.addChangeListener(
-        () => this._overlayAgent.setShowHitTestBorders(this._showHitTestBordersSetting.get()));
-    if (this._showHitTestBordersSetting.get())
-      this._overlayAgent.setShowHitTestBorders(true);
 
-    if (target.suspended())
-      this._overlayAgent.setSuspended(true);
+    this._registeredListeners = [];
+    this._showViewportSizeOnResize = true;
+    if (!target.suspended()) {
+      this._overlayAgent.enable();
+      this._wireAgentToSettings();
+    }
   }
 
   /**
@@ -89,17 +62,48 @@
       overlayModel._delayedHideHighlight(0);
   }
 
-  static muteHighlight() {
-    SDK.OverlayModel.hideDOMNodeHighlight();
-    SDK.OverlayModel._highlightDisabled = true;
-    for (const overlayModel of SDK.targetManager.models(SDK.OverlayModel))
-      overlayModel._updatePausedInDebuggerMessage();
+  static async muteHighlight() {
+    return Promise.all(SDK.targetManager.models(SDK.OverlayModel).map(model => model.suspendModel()));
   }
 
-  static unmuteHighlight() {
-    SDK.OverlayModel._highlightDisabled = false;
-    for (const overlayModel of SDK.targetManager.models(SDK.OverlayModel))
-      overlayModel._updatePausedInDebuggerMessage();
+  static async unmuteHighlight() {
+    return Promise.all(SDK.targetManager.models(SDK.OverlayModel).map(model => model.resumeModel()));
+  }
+
+  /**
+   * @return {!Promise}
+   */
+  _wireAgentToSettings() {
+    this._registeredListeners = [
+      this._showPaintRectsSetting.addChangeListener(
+          () => this._overlayAgent.setShowPaintRects(this._showPaintRectsSetting.get())),
+      this._showAdHighlightsSetting.addChangeListener(
+          () => this._overlayAgent.setShowAdHighlights(this._showAdHighlightsSetting.get())),
+      this._showDebugBordersSetting.addChangeListener(
+          () => this._overlayAgent.setShowDebugBorders(this._showDebugBordersSetting.get())),
+      this._showFPSCounterSetting.addChangeListener(
+          () => this._overlayAgent.setShowFPSCounter(this._showFPSCounterSetting.get())),
+      this._showScrollBottleneckRectsSetting.addChangeListener(
+          () => this._overlayAgent.setShowScrollBottleneckRects(this._showScrollBottleneckRectsSetting.get())),
+      this._showHitTestBordersSetting.addChangeListener(
+          () => this._overlayAgent.setShowHitTestBorders(this._showHitTestBordersSetting.get()))
+    ];
+
+    if (this._showPaintRectsSetting.get())
+      this._overlayAgent.setShowPaintRects(true);
+    if (this._showAdHighlightsSetting.get())
+      this._overlayAgent.setShowAdHighlights(true);
+    if (this._showDebugBordersSetting.get())
+      this._overlayAgent.setShowDebugBorders(true);
+    if (this._showFPSCounterSetting.get())
+      this._overlayAgent.setShowFPSCounter(true);
+    if (this._showScrollBottleneckRectsSetting.get())
+      this._overlayAgent.setShowScrollBottleneckRects(true);
+    if (this._showHitTestBordersSetting.get())
+      this._overlayAgent.setShowHitTestBorders(true);
+    if (this._debuggerModel.isPaused())
+      this._updatePausedInDebuggerMessage();
+    return this._overlayAgent.setShowViewportSizeOnResize(this._showViewportSizeOnResize);
   }
 
   /**
@@ -107,7 +111,8 @@
    * @return {!Promise}
    */
   suspendModel() {
-    return this._overlayAgent.setSuspended(true);
+    Common.EventTarget.removeEventListeners(this._registeredListeners);
+    return this._overlayAgent.disable();
   }
 
   /**
@@ -115,19 +120,30 @@
    * @return {!Promise}
    */
   resumeModel() {
-    return this._overlayAgent.setSuspended(false);
+    this._overlayAgent.enable();
+    return this._wireAgentToSettings();
   }
 
+  /**
+   * @param {boolean} show
+   */
   setShowViewportSizeOnResize(show) {
+    this._showViewportSizeOnResize = show;
+    if (this.target().suspended())
+      return;
     this._overlayAgent.setShowViewportSizeOnResize(show);
   }
 
+  /**
+   * @return {!Promise}
+   */
   _updatePausedInDebuggerMessage() {
-    const message = this._debuggerModel.isPaused() && !Common.moduleSetting('disablePausedStateOverlay').get() &&
-            !SDK.OverlayModel._highlightDisabled ?
+    if (this.target().suspended())
+      return Promise.resolve();
+    const message = this._debuggerModel.isPaused() && !Common.moduleSetting('disablePausedStateOverlay').get() ?
         Common.UIString('Paused in debugger') :
         undefined;
-    this._overlayAgent.setPausedInDebuggerMessage(message);
+    return this._overlayAgent.setPausedInDebuggerMessage(message);
   }
 
   /**
@@ -161,8 +177,6 @@
    * @param {boolean=} showInfo
    */
   highlightInOverlay(data, mode, showInfo) {
-    if (SDK.OverlayModel._highlightDisabled)
-      return;
     if (this._hideHighlightTimeout) {
       clearTimeout(this._hideHighlightTimeout);
       this._hideHighlightTimeout = null;
@@ -193,8 +207,6 @@
    * @param {!Protocol.Page.FrameId} frameId
    */
   highlightFrame(frameId) {
-    if (SDK.OverlayModel._highlightDisabled)
-      return;
     if (this._hideHighlightTimeout) {
       clearTimeout(this._hideHighlightTimeout);
       this._hideHighlightTimeout = null;
diff --git a/third_party/blink/renderer/devtools/front_end/sdk/ScreenCaptureModel.js b/third_party/blink/renderer/devtools/front_end/sdk/ScreenCaptureModel.js
index ddb7f44..4a213ed 100644
--- a/third_party/blink/renderer/devtools/front_end/sdk/ScreenCaptureModel.js
+++ b/third_party/blink/renderer/devtools/front_end/sdk/ScreenCaptureModel.js
@@ -46,8 +46,11 @@
    * @param {!Protocol.Page.Viewport=} clip
    * @return {!Promise<?string>}
    */
-  captureScreenshot(format, quality, clip) {
-    return this._agent.captureScreenshot(format, quality, clip, true);
+  async captureScreenshot(format, quality, clip) {
+    await SDK.OverlayModel.muteHighlight();
+    const result = await this._agent.captureScreenshot(format, quality, clip, true);
+    await SDK.OverlayModel.unmuteHighlight();
+    return result;
   }
 
   /**
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc b/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
index 1ea1d66..b99b656f 100644
--- a/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
+++ b/third_party/blink/renderer/modules/clipboard/clipboard_promise.cc
@@ -29,8 +29,6 @@
 #include "third_party/blink/renderer/platform/scheduler/public/worker_pool.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
-// And now, a brief note about clipboard permissions.
-//
 // There are 2 clipboard permissions defined in the spec:
 // * clipboard-read
 // * clipboard-write
@@ -68,6 +66,7 @@
 
 ClipboardPromise::~ClipboardPromise() = default;
 
+// static
 ScriptPromise ClipboardPromise::CreateForRead(ScriptState* script_state) {
   ClipboardPromise* clipboard_promise =
       MakeGarbageCollected<ClipboardPromise>(script_state);
@@ -77,6 +76,7 @@
   return clipboard_promise->script_promise_resolver_->Promise();
 }
 
+// static
 ScriptPromise ClipboardPromise::CreateForReadText(ScriptState* script_state) {
   ClipboardPromise* clipboard_promise =
       MakeGarbageCollected<ClipboardPromise>(script_state);
@@ -86,6 +86,7 @@
   return clipboard_promise->script_promise_resolver_->Promise();
 }
 
+// static
 ScriptPromise ClipboardPromise::CreateForWrite(ScriptState* script_state,
                                                HeapVector<Member<Blob>> data) {
   ClipboardPromise* clipboard_promise =
@@ -99,6 +100,7 @@
   return clipboard_promise->script_promise_resolver_->Promise();
 }
 
+// static
 ScriptPromise ClipboardPromise::CreateForWriteText(ScriptState* script_state,
                                                    const String& data) {
   ClipboardPromise* clipboard_promise =
@@ -120,7 +122,8 @@
 
 scoped_refptr<base::SingleThreadTaskRunner> ClipboardPromise::GetTaskRunner() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(async_clipboard_sequence_checker);
-  // TODO(garykac): Replace MiscPlatformAPI with TaskType specific to clipboard.
+  // TODO(https://crbug.com/941835): Replace MiscPlatformAPI with TaskType
+  // specific to clipboard.
   return GetExecutionContext()->GetTaskRunner(TaskType::kMiscPlatformAPI);
 }
 
@@ -196,7 +199,6 @@
                                   WrapPersistent(this)));
 }
 
-// TODO(garykac): This currently only handles images and plain text.
 void ClipboardPromise::HandleReadWithPermission(PermissionStatus status) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(async_clipboard_sequence_checker);
   if (status != PermissionStatus::GRANTED) {
@@ -246,7 +248,6 @@
 }
 
 void ClipboardPromise::HandleWrite(HeapVector<Member<Blob>>* data) {
-  // TODO(huangdarwin): This currently only handles plain text and images.
   DCHECK_CALLED_ON_VALID_SEQUENCE(async_clipboard_sequence_checker);
   CHECK(data);
   blob_sequence_data_ = std::move(*data);
diff --git a/third_party/blink/renderer/modules/clipboard/clipboard_promise.h b/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
index 857cf17..89e0c084 100644
--- a/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
+++ b/third_party/blink/renderer/modules/clipboard/clipboard_promise.h
@@ -90,8 +90,6 @@
 
   bool IsValidClipboardType(const String&);
 
-  // Because v8 is thread-hostile, ensures that all interactions with
-  // ScriptState and ScriptPromiseResolver occur on the main thread.
   Member<ScriptState> script_state_;
   Member<ScriptPromiseResolver> script_promise_resolver_;
 
@@ -106,8 +104,11 @@
   // Index of clipboard representation currently being processed.
   wtf_size_t clipboard_representation_index_;
 
+  // Only used for reading Blobs via the ClipboardFileReader.
   scoped_refptr<base::SingleThreadTaskRunner> file_reading_task_runner_;
 
+  // Because v8 is thread-hostile, ensures that all interactions with
+  // ScriptState and ScriptPromiseResolver occur on the main thread.
   SEQUENCE_CHECKER(async_clipboard_sequence_checker);
 
   DISALLOW_COPY_AND_ASSIGN(ClipboardPromise);
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni
index 7f8e8d2..cdd15a6 100644
--- a/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -429,9 +429,9 @@
           "webgl/webgl_uniform_location.idl",
           "webgl/webgl_vertex_array_object.idl",
           "webgl/webgl_vertex_array_object_oes.idl",
-          "webgpu/webgpu.idl",
-          "webgpu/webgpu_adapter.idl",
-          "webgpu/webgpu_device.idl",
+          "webgpu/gpu.idl",
+          "webgpu/gpu_adapter.idl",
+          "webgpu/gpu_device.idl",
           "webmidi/midi_access.idl",
           "webmidi/midi_connection_event.idl",
           "webmidi/midi_input.idl",
@@ -734,7 +734,7 @@
           "webaudio/wave_shaper_options.idl",
           "webgl/webgl_context_attributes.idl",
           "webgl/webgl_context_event_init.idl",
-          "webgpu/webgpu_adapter_descriptor.idl",
+          "webgpu/gpu_adapter_descriptor.idl",
           "webmidi/midi_connection_event_init.idl",
           "webmidi/midi_message_event_init.idl",
           "webmidi/midi_options.idl",
@@ -851,7 +851,7 @@
           "webdatabase/window_web_database.idl",
           "webgl/webgl2_rendering_context_base.idl",
           "webgl/webgl_rendering_context_base.idl",
-          "webgpu/window_webgpu.idl",
+          "webgpu/navigator_gpu.idl",
           "webmidi/navigator_web_midi.idl",
           "webshare/navigator_share.idl",
           "webusb/navigator_usb.idl",
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context.cc b/third_party/blink/renderer/modules/webaudio/audio_context.cc
index 6ab33f2..39177bd 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_context.cc
@@ -110,11 +110,8 @@
 
   DEFINE_STATIC_LOCAL(SparseHistogram, max_channel_count_histogram,
                       ("WebAudio.AudioContext.MaxChannelsAvailable"));
-  DEFINE_STATIC_LOCAL(SparseHistogram, sample_rate_histogram,
-                      ("WebAudio.AudioContext.HardwareSampleRate"));
   max_channel_count_histogram.Sample(
       audio_context->destination()->maxChannelCount());
-  sample_rate_histogram.Sample(audio_context->sampleRate());
 
   probe::DidCreateAudioContext(&document);
 
diff --git a/third_party/blink/renderer/modules/webgpu/BUILD.gn b/third_party/blink/renderer/modules/webgpu/BUILD.gn
index 0182dfa..3b810a96 100644
--- a/third_party/blink/renderer/modules/webgpu/BUILD.gn
+++ b/third_party/blink/renderer/modules/webgpu/BUILD.gn
@@ -6,14 +6,14 @@
 
 blink_modules_sources("webgpu") {
   sources = [
-    "webgpu.cc",
-    "webgpu.h",
-    "webgpu_adapter.cc",
-    "webgpu_adapter.h",
-    "webgpu_device.cc",
-    "webgpu_device.h",
-    "window_webgpu.cc",
-    "window_webgpu.h",
+    "gpu.cc",
+    "gpu.h",
+    "gpu_adapter.cc",
+    "gpu_adapter.h",
+    "gpu_device.cc",
+    "gpu_device.h",
+    "navigator_gpu.cc",
+    "navigator_gpu.h",
   ]
   deps = [
     "//third_party/dawn/src/dawn:dawn_headers",
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.cc b/third_party/blink/renderer/modules/webgpu/gpu.cc
new file mode 100644
index 0000000..f6b9f9b
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/gpu.cc
@@ -0,0 +1,63 @@
+// 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 "third_party/blink/renderer/modules/webgpu/gpu.h"
+
+#include <utility>
+
+#include "gpu/command_buffer/client/webgpu_interface.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_adapter.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_adapter_descriptor.h"
+
+namespace blink {
+
+// static
+GPU* GPU::Create(ExecutionContext& execution_context) {
+  const auto& url = execution_context.Url();
+  Platform::GraphicsInfo info;
+
+  std::unique_ptr<WebGraphicsContext3DProvider> context_provider =
+      Platform::Current()->CreateWebGPUGraphicsContext3DProvider(url, &info);
+
+  // TODO(kainino): we will need a better way of accessing the GPU interface
+  // from multiple threads than BindToCurrentThread et al.
+  if (context_provider && context_provider->BindToCurrentThread()) {
+    info.error_message =
+        String("bindToCurrentThread failed: " + String(info.error_message));
+  }
+
+  if (!context_provider) {
+    // TODO(kainino): send the error message somewhere
+    // (see ExtractWebGLContextCreationError).
+    return nullptr;
+  }
+
+  return MakeGarbageCollected<GPU>(execution_context,
+                                   std::move(context_provider));
+}
+
+GPU::GPU(ExecutionContext& execution_context,
+         std::unique_ptr<WebGraphicsContext3DProvider> context_provider)
+    : ContextLifecycleObserver(&execution_context),
+      context_provider_(std::move(context_provider)) {}
+
+GPU::~GPU() = default;
+
+void GPU::Trace(blink::Visitor* visitor) {
+  ScriptWrappable::Trace(visitor);
+  ContextLifecycleObserver::Trace(visitor);
+}
+
+void GPU::ContextDestroyed(ExecutionContext* execution_context) {
+  context_provider_.reset();
+}
+
+GPUAdapter* GPU::getAdapter(const GPUAdapterDescriptor* descriptor) {
+  return GPUAdapter::Create(descriptor->powerPreference());
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.h b/third_party/blink/renderer/modules/webgpu/gpu.h
new file mode 100644
index 0000000..1e74187
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/gpu.h
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_H_
+
+#include <memory>
+
+#include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+
+namespace blink {
+
+class GPUAdapter;
+class GPUAdapterDescriptor;
+
+class GPU final : public ScriptWrappable, public ContextLifecycleObserver {
+  DEFINE_WRAPPERTYPEINFO();
+  USING_GARBAGE_COLLECTED_MIXIN(GPU);
+
+ public:
+  static GPU* Create(ExecutionContext& execution_context);
+  explicit GPU(ExecutionContext& execution_context,
+               std::unique_ptr<WebGraphicsContext3DProvider> context_provider);
+  ~GPU() override;
+
+  // ScriptWrappable overrides
+  void Trace(blink::Visitor* visitor) override;
+
+  // ContextLifecycleObserver overrides
+  void ContextDestroyed(ExecutionContext* execution_context) override;
+
+  GPUAdapter* getAdapter(const GPUAdapterDescriptor*);
+
+ private:
+  std::unique_ptr<WebGraphicsContext3DProvider> context_provider_;
+
+  DISALLOW_COPY_AND_ASSIGN(GPU);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_H_
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.idl b/third_party/blink/renderer/modules/webgpu/gpu.idl
new file mode 100644
index 0000000..55d4bbe3
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/gpu.idl
@@ -0,0 +1,11 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
+
+[
+    RuntimeEnabled=WebGPU
+] interface GPU {
+    GPUAdapter getAdapter(GPUAdapterDescriptor descriptor);
+};
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc b/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
new file mode 100644
index 0000000..c96a2cc2
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
@@ -0,0 +1,26 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webgpu/gpu_adapter.h"
+
+#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
+
+namespace blink {
+
+// static
+GPUAdapter* GPUAdapter::Create(const String& name) {
+  return MakeGarbageCollected<GPUAdapter>(name);
+}
+
+const String& GPUAdapter::name() const {
+  return name_;
+}
+
+GPUDevice* GPUAdapter::createDevice() {
+  return GPUDevice::Create(this);
+}
+
+GPUAdapter::GPUAdapter(const String& name) : name_(name) {}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_adapter.h b/third_party/blink/renderer/modules/webgpu/gpu_adapter.h
new file mode 100644
index 0000000..a993c32
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/gpu_adapter.h
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_ADAPTER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_ADAPTER_H_
+
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class GPUDevice;
+
+class GPUAdapter final : public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  static GPUAdapter* Create(const String& name);
+
+  GPUAdapter(const String& name);
+
+  const String& name() const;
+
+  GPUDevice* createDevice();
+
+ private:
+  String name_;
+
+  DISALLOW_COPY_AND_ASSIGN(GPUAdapter);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_ADAPTER_H_
diff --git a/third_party/blink/renderer/modules/webgpu/webgpu_adapter.idl b/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl
similarity index 65%
rename from third_party/blink/renderer/modules/webgpu/webgpu_adapter.idl
rename to third_party/blink/renderer/modules/webgpu/gpu_adapter.idl
index 08a9d3ff..01ef4985 100644
--- a/third_party/blink/renderer/modules/webgpu/webgpu_adapter.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
+
 [
     RuntimeEnabled=WebGPU
-] interface WebGPUAdapter {
+] interface GPUAdapter {
     readonly attribute DOMString name;
 
-    [CallWith=ExecutionContext] WebGPUDevice createDevice();
+    GPUDevice createDevice();
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_adapter_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_adapter_descriptor.idl
new file mode 100644
index 0000000..f2a90b4
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/gpu_adapter_descriptor.idl
@@ -0,0 +1,15 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
+
+enum GPUPowerPreference {
+    "default",
+    "low-power",
+    "high-performance",
+};
+
+dictionary GPUAdapterDescriptor {
+    GPUPowerPreference powerPreference = "default";
+};
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.cc b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
new file mode 100644
index 0000000..dcacac5
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
+
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_adapter.h"
+
+namespace blink {
+
+// static
+GPUDevice* GPUDevice::Create(GPUAdapter* adapter) {
+  return MakeGarbageCollected<GPUDevice>(adapter);
+}
+
+GPUAdapter* GPUDevice::adapter() const {
+  return adapter_;
+}
+
+void GPUDevice::Trace(blink::Visitor* visitor) {
+  visitor->Trace(adapter_);
+  ScriptWrappable::Trace(visitor);
+}
+
+GPUDevice::GPUDevice(GPUAdapter* adapter) : adapter_(adapter) {}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.h b/third_party/blink/renderer/modules/webgpu/gpu_device.h
new file mode 100644
index 0000000..232cbc0
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.h
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_DEVICE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_DEVICE_H_
+
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+
+namespace blink {
+
+class GPUAdapter;
+
+class GPUDevice final : public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  static GPUDevice* Create(GPUAdapter*);
+
+  GPUDevice(GPUAdapter*);
+
+  GPUAdapter* adapter() const;
+
+  void Trace(blink::Visitor*) override;
+
+ private:
+  Member<GPUAdapter> adapter_;
+
+  DISALLOW_COPY_AND_ASSIGN(GPUDevice);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_GPU_DEVICE_H_
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.idl b/third_party/blink/renderer/modules/webgpu/gpu_device.idl
new file mode 100644
index 0000000..3a1dc5d
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.idl
@@ -0,0 +1,11 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
+
+[
+    RuntimeEnabled=WebGPU
+] interface GPUDevice {
+    readonly attribute GPUAdapter adapter;
+};
diff --git a/third_party/blink/renderer/modules/webgpu/navigator_gpu.cc b/third_party/blink/renderer/modules/webgpu/navigator_gpu.cc
new file mode 100644
index 0000000..1a08230
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/navigator_gpu.cc
@@ -0,0 +1,49 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webgpu/navigator_gpu.h"
+
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/navigator.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu.h"
+
+namespace blink {
+
+NavigatorGPU& NavigatorGPU::From(Navigator& navigator) {
+  NavigatorGPU* supplement =
+      Supplement<Navigator>::From<NavigatorGPU>(navigator);
+  if (!supplement) {
+    supplement = MakeGarbageCollected<NavigatorGPU>(navigator);
+    ProvideTo(navigator, supplement);
+  }
+  return *supplement;
+}
+
+// static
+GPU* NavigatorGPU::gpu(ScriptState* script_state, Navigator& navigator) {
+  return NavigatorGPU::From(navigator).gpu(script_state);
+}
+
+GPU* NavigatorGPU::gpu(ScriptState* script_state) {
+  if (!gpu_) {
+    ExecutionContext* context = ExecutionContext::From(script_state);
+    DCHECK(context);
+
+    gpu_ = GPU::Create(*context);
+  }
+  return gpu_;
+}
+
+void NavigatorGPU::Trace(blink::Visitor* visitor) {
+  visitor->Trace(gpu_);
+  Supplement<Navigator>::Trace(visitor);
+}
+
+NavigatorGPU::NavigatorGPU(Navigator& navigator)
+    : Supplement<Navigator>(navigator) {}
+
+const char NavigatorGPU::kSupplementName[] = "NavigatorGPU";
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/navigator_gpu.h b/third_party/blink/renderer/modules/webgpu/navigator_gpu.h
new file mode 100644
index 0000000..79312b2
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/navigator_gpu.h
@@ -0,0 +1,43 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_NAVIGATOR_GPU_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_NAVIGATOR_GPU_H_
+
+#include "third_party/blink/renderer/core/frame/navigator.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+class Navigator;
+class GPU;
+
+class NavigatorGPU final : public GarbageCollected<NavigatorGPU>,
+                           public Supplement<Navigator> {
+  USING_GARBAGE_COLLECTED_MIXIN(NavigatorGPU);
+
+ public:
+  static const char kSupplementName[];
+
+  // Gets, or creates, NavigatorGPU supplement on Navigator.
+  // See platform/Supplementable.h
+  static NavigatorGPU& From(Navigator&);
+
+  static GPU* gpu(ScriptState* script_state, Navigator&);
+  GPU* gpu(ScriptState* script_state);
+
+  explicit NavigatorGPU(Navigator&);
+
+  void Trace(blink::Visitor*) override;
+
+ private:
+  Member<GPU> gpu_;
+
+  DISALLOW_COPY_AND_ASSIGN(NavigatorGPU);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_NAVIGATOR_GPU_H_
diff --git a/third_party/blink/renderer/modules/webgpu/navigator_gpu.idl b/third_party/blink/renderer/modules/webgpu/navigator_gpu.idl
new file mode 100644
index 0000000..5d5fa8b
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/navigator_gpu.idl
@@ -0,0 +1,12 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://github.com/gpuweb/gpuweb/blob/master/design/sketch.webidl
+
+[
+    Exposed=Window,
+    ImplementedAs=NavigatorGPU
+] partial interface Navigator {
+    [SameObject, RuntimeEnabled=WebGPU, CallWith=ScriptState] readonly attribute GPU gpu;
+};
diff --git a/third_party/blink/renderer/modules/webgpu/webgpu.cc b/third_party/blink/renderer/modules/webgpu/webgpu.cc
deleted file mode 100644
index 05edb42..0000000
--- a/third_party/blink/renderer/modules/webgpu/webgpu.cc
+++ /dev/null
@@ -1,23 +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 "third_party/blink/renderer/modules/webgpu/webgpu.h"
-
-#include "third_party/blink/renderer/modules/webgpu/webgpu_adapter.h"
-#include "third_party/blink/renderer/modules/webgpu/webgpu_adapter_descriptor.h"
-
-namespace blink {
-
-// static
-WebGPU* WebGPU::Create() {
-  return MakeGarbageCollected<WebGPU>();
-}
-
-WebGPUAdapter* WebGPU::getAdapter(const WebGPUAdapterDescriptor* descriptor) {
-  return WebGPUAdapter::Create(descriptor->powerPreference());
-}
-
-WebGPU::WebGPU() {}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/webgpu.h b/third_party/blink/renderer/modules/webgpu/webgpu.h
deleted file mode 100644
index 84a2fc5..0000000
--- a/third_party/blink/renderer/modules/webgpu/webgpu.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 THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WEBGPU_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WEBGPU_H_
-
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-
-namespace blink {
-
-class WebGPUAdapter;
-class WebGPUAdapterDescriptor;
-
-class WebGPU final : public ScriptWrappable {
-  DISALLOW_COPY_AND_ASSIGN(WebGPU);
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  static WebGPU* Create();
-
-  WebGPU();
-
-  WebGPUAdapter* getAdapter(const WebGPUAdapterDescriptor*);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WEBGPU_H_
diff --git a/third_party/blink/renderer/modules/webgpu/webgpu.idl b/third_party/blink/renderer/modules/webgpu/webgpu.idl
deleted file mode 100644
index 8877baff..0000000
--- a/third_party/blink/renderer/modules/webgpu/webgpu.idl
+++ /dev/null
@@ -1,9 +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.
-
-[
-    RuntimeEnabled=WebGPU
-] interface WebGPU {
-    WebGPUAdapter getAdapter(WebGPUAdapterDescriptor descriptor);
-};
diff --git a/third_party/blink/renderer/modules/webgpu/webgpu_adapter.cc b/third_party/blink/renderer/modules/webgpu/webgpu_adapter.cc
deleted file mode 100644
index b547074..0000000
--- a/third_party/blink/renderer/modules/webgpu/webgpu_adapter.cc
+++ /dev/null
@@ -1,26 +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 "third_party/blink/renderer/modules/webgpu/webgpu_adapter.h"
-
-#include "third_party/blink/renderer/modules/webgpu/webgpu_device.h"
-
-namespace blink {
-
-// static
-WebGPUAdapter* WebGPUAdapter::Create(const String& name) {
-  return MakeGarbageCollected<WebGPUAdapter>(name);
-}
-
-const String& WebGPUAdapter::name() const {
-  return name_;
-}
-
-WebGPUDevice* WebGPUAdapter::createDevice(ExecutionContext* execution_context) {
-  return WebGPUDevice::Create(execution_context, this);
-}
-
-WebGPUAdapter::WebGPUAdapter(const String& name) : name_(name) {}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/webgpu_adapter.h b/third_party/blink/renderer/modules/webgpu/webgpu_adapter.h
deleted file mode 100644
index 07af4bd..0000000
--- a/third_party/blink/renderer/modules/webgpu/webgpu_adapter.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WEBGPU_ADAPTER_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WEBGPU_ADAPTER_H_
-
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-
-namespace blink {
-
-class WebGPUDevice;
-
-class WebGPUAdapter final : public ScriptWrappable {
-  DISALLOW_COPY_AND_ASSIGN(WebGPUAdapter);
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  static WebGPUAdapter* Create(const String& name);
-
-  WebGPUAdapter(const String& name);
-
-  const String& name() const;
-
-  WebGPUDevice* createDevice(ExecutionContext*);
-
- private:
-  String name_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WEBGPU_ADAPTER_H_
diff --git a/third_party/blink/renderer/modules/webgpu/webgpu_adapter_descriptor.idl b/third_party/blink/renderer/modules/webgpu/webgpu_adapter_descriptor.idl
deleted file mode 100644
index 4c9a6ca..0000000
--- a/third_party/blink/renderer/modules/webgpu/webgpu_adapter_descriptor.idl
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-enum WebGPUPowerPreference {
-    "default",
-    "low-power",
-    "high-performance",
-};
-
-dictionary WebGPUAdapterDescriptor {
-    WebGPUPowerPreference powerPreference = "default";
-};
diff --git a/third_party/blink/renderer/modules/webgpu/webgpu_device.cc b/third_party/blink/renderer/modules/webgpu/webgpu_device.cc
deleted file mode 100644
index 111a129..0000000
--- a/third_party/blink/renderer/modules/webgpu/webgpu_device.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 "third_party/blink/renderer/modules/webgpu/webgpu_device.h"
-
-#include "gpu/command_buffer/client/webgpu_interface.h"
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/modules/webgpu/webgpu_adapter.h"
-
-namespace blink {
-
-// static
-WebGPUDevice* WebGPUDevice::Create(ExecutionContext* execution_context,
-                                   WebGPUAdapter* adapter) {
-  DCHECK(IsMainThread());
-
-  const auto& url = execution_context->Url();
-  Platform::GraphicsInfo info;
-
-  std::unique_ptr<WebGraphicsContext3DProvider> context_provider =
-      Platform::Current()->CreateWebGPUGraphicsContext3DProvider(url, &info);
-
-  // TODO(kainino): we will need a better way of accessing the WebGPU interface
-  // from multiple threads than BindToCurrentThread et al.
-  if (context_provider && context_provider->BindToCurrentThread()) {
-    info.error_message =
-        String("bindToCurrentThread failed: " + String(info.error_message));
-  }
-
-  if (!context_provider) {
-    // TODO(kainino): send the error message somewhere
-    // (see ExtractWebGLContextCreationError).
-    return nullptr;
-  }
-
-  return MakeGarbageCollected<WebGPUDevice>(adapter,
-                                            std::move(context_provider));
-}
-
-WebGPUAdapter* WebGPUDevice::adapter() const {
-  return adapter_;
-}
-
-void WebGPUDevice::Trace(blink::Visitor* visitor) {
-  visitor->Trace(adapter_);
-  ScriptWrappable::Trace(visitor);
-}
-
-WebGPUDevice::WebGPUDevice(
-    WebGPUAdapter* adapter,
-    std::unique_ptr<WebGraphicsContext3DProvider> context_provider)
-    : adapter_(adapter), context_provider_(std::move(context_provider)) {}
-
-gpu::webgpu::WebGPUInterface* WebGPUDevice::Interface() const {
-  DCHECK(context_provider_);
-  return context_provider_->WebGPUInterface();
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/webgpu_device.h b/third_party/blink/renderer/modules/webgpu/webgpu_device.h
deleted file mode 100644
index 2d86aef..0000000
--- a/third_party/blink/renderer/modules/webgpu/webgpu_device.h
+++ /dev/null
@@ -1,38 +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 THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WEBGPU_DEVICE_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WEBGPU_DEVICE_H_
-
-#include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
-
-namespace blink {
-
-class WebGPUAdapter;
-
-class WebGPUDevice final : public ScriptWrappable {
-  DISALLOW_COPY_AND_ASSIGN(WebGPUDevice);
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  static WebGPUDevice* Create(ExecutionContext*, WebGPUAdapter*);
-
-  WebGPUDevice(WebGPUAdapter*, std::unique_ptr<WebGraphicsContext3DProvider>);
-
-  WebGPUAdapter* adapter() const;
-
-  void Trace(blink::Visitor*) override;
-
- private:
-  gpu::webgpu::WebGPUInterface* Interface() const;
-
-  Member<WebGPUAdapter> adapter_;
-  std::unique_ptr<WebGraphicsContext3DProvider> context_provider_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WEBGPU_DEVICE_H_
diff --git a/third_party/blink/renderer/modules/webgpu/webgpu_device.idl b/third_party/blink/renderer/modules/webgpu/webgpu_device.idl
deleted file mode 100644
index 47f1b690..0000000
--- a/third_party/blink/renderer/modules/webgpu/webgpu_device.idl
+++ /dev/null
@@ -1,9 +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.
-
-[
-    RuntimeEnabled=WebGPU
-] interface WebGPUDevice {
-    readonly attribute WebGPUAdapter adapter;
-};
diff --git a/third_party/blink/renderer/modules/webgpu/window_webgpu.cc b/third_party/blink/renderer/modules/webgpu/window_webgpu.cc
deleted file mode 100644
index b392dd09..0000000
--- a/third_party/blink/renderer/modules/webgpu/window_webgpu.cc
+++ /dev/null
@@ -1,45 +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 "third_party/blink/renderer/modules/webgpu/window_webgpu.h"
-
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
-#include "third_party/blink/renderer/modules/webgpu/webgpu.h"
-
-namespace blink {
-
-const char WindowWebGPU::kSupplementName[] = "WindowWebGPU";
-
-// static
-WindowWebGPU& WindowWebGPU::From(LocalDOMWindow& window) {
-  WindowWebGPU* supplement =
-      Supplement<LocalDOMWindow>::From<WindowWebGPU>(window);
-  if (!supplement) {
-    supplement = MakeGarbageCollected<WindowWebGPU>(window);
-    ProvideTo(window, supplement);
-  }
-  return *supplement;
-}
-
-// static
-WebGPU* WindowWebGPU::webgpu(LocalDOMWindow& window) {
-  return WindowWebGPU::From(window).webgpu();
-}
-
-WebGPU* WindowWebGPU::webgpu() const {
-  if (!webgpu_) {
-    webgpu_ = WebGPU::Create();
-  }
-  return webgpu_.Get();
-}
-
-void WindowWebGPU::Trace(blink::Visitor* visitor) {
-  visitor->Trace(webgpu_);
-  Supplement<LocalDOMWindow>::Trace(visitor);
-}
-
-WindowWebGPU::WindowWebGPU(LocalDOMWindow& window)
-    : Supplement<LocalDOMWindow>(window) {}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/window_webgpu.h b/third_party/blink/renderer/modules/webgpu/window_webgpu.h
deleted file mode 100644
index 6ca56063..0000000
--- a/third_party/blink/renderer/modules/webgpu/window_webgpu.h
+++ /dev/null
@@ -1,37 +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 THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WINDOW_WEBGPU_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WINDOW_WEBGPU_H_
-
-#include "third_party/blink/renderer/platform/heap/handle.h"
-#include "third_party/blink/renderer/platform/supplementable.h"
-
-namespace blink {
-
-class WebGPU;
-class LocalDOMWindow;
-
-class WindowWebGPU final : public GarbageCollected<WindowWebGPU>,
-                           public Supplement<LocalDOMWindow> {
-  USING_GARBAGE_COLLECTED_MIXIN(WindowWebGPU);
-
- public:
-  static const char kSupplementName[];
-
-  static WindowWebGPU& From(LocalDOMWindow&);
-  static WebGPU* webgpu(LocalDOMWindow&);
-  WebGPU* webgpu() const;
-
-  explicit WindowWebGPU(LocalDOMWindow&);
-
-  void Trace(blink::Visitor*) override;
-
- private:
-  mutable Member<WebGPU> webgpu_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WINDOW_WEBGPU_H_
diff --git a/third_party/blink/renderer/modules/webgpu/window_webgpu.idl b/third_party/blink/renderer/modules/webgpu/window_webgpu.idl
deleted file mode 100644
index 344cd7d..0000000
--- a/third_party/blink/renderer/modules/webgpu/window_webgpu.idl
+++ /dev/null
@@ -1,10 +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.
-
-[
-    RuntimeEnabled=WebGPU,
-    ImplementedAs=WindowWebGPU
-] partial interface Window {
-    [Replaceable, SameObject] readonly attribute WebGPU webgpu;
-};
diff --git a/third_party/blink/renderer/platform/audio/audio_destination.cc b/third_party/blink/renderer/platform/audio/audio_destination.cc
index 895bc61..30e258b 100644
--- a/third_party/blink/renderer/platform/audio/audio_destination.cc
+++ b/third_party/blink/renderer/platform/audio/audio_destination.cc
@@ -100,10 +100,13 @@
     NOTREACHED();
   }
 
+  double scale_factor = 1;
+
   if (context_sample_rate.has_value() &&
       context_sample_rate.value() != web_audio_device_->SampleRate()) {
-    double scale_factor =
+    scale_factor =
         context_sample_rate.value() / web_audio_device_->SampleRate();
+
     resampler_.reset(new MediaMultiChannelResampler(
         MaxChannelCount(), scale_factor, audio_utilities::kRenderQuantumFrames,
         ConvertToBaseCallback(
@@ -119,6 +122,31 @@
   } else {
     context_sample_rate_ = web_audio_device_->SampleRate();
   }
+
+  DEFINE_STATIC_LOCAL(SparseHistogram, sample_rate_histogram,
+                      ("WebAudio.AudioContext.HardwareSampleRate"));
+
+  sample_rate_histogram.Sample(web_audio_device_->SampleRate());
+
+  // The actual supplied |sampleRate| is probably a small set including 44100,
+  // 48000, 22050, and 2400 Hz.  Other valid values range from 3000 to 384000
+  // Hz, but are not expected to be used much.
+  DEFINE_STATIC_LOCAL(SparseHistogram, selected_sample_rate_histogram,
+                      ("WebAudio.AudioContextOptions.sampleRate"));
+
+  // From the expected values above and the common HW sample rates, we expect
+  // the most common ratios to be the set 0.5, 44100/48000, and 48000/44100.
+  // Other values are possible but seem unlikely.
+  DEFINE_STATIC_LOCAL(SparseHistogram, sample_rate_ratio_histogram,
+                      ("WebAudio.AudioContextOptions.sampleRateRatio"));
+
+  // Record the selected sample rate and ratio if the sampleRate was given.  The
+  // ratio is recorded as a percentage, rounded to the nearest percent.
+  if (context_sample_rate.has_value()) {
+    selected_sample_rate_histogram.Sample(context_sample_rate.value());
+    sample_rate_ratio_histogram.Sample(
+        static_cast<int32_t>(100 * scale_factor + 0.5));
+  }
 }
 
 AudioDestination::~AudioDestination() {
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.cc
index 8e6a111d..128481c 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.cc
@@ -10,21 +10,6 @@
 namespace blink {
 
 template <typename TextContainerType>
-ShapeResultSpacing<TextContainerType>::ShapeResultSpacing(
-    const TextContainerType& text)
-    : text_(text),
-      letter_spacing_(0),
-      word_spacing_(0),
-      expansion_(0),
-      expansion_per_opportunity_(0),
-      expansion_opportunity_count_(0),
-      text_justify_(TextJustify::kAuto),
-      has_spacing_(false),
-      normalize_space_(false),
-      allow_tabs_(false),
-      is_after_expansion_(false) {}
-
-template <typename TextContainerType>
 bool ShapeResultSpacing<TextContainerType>::SetSpacing(
     const FontDescription& font_description) {
   if (!font_description.LetterSpacing() && !font_description.WordSpacing()) {
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h
index 391de422..42a3061 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h
@@ -20,7 +20,18 @@
   STACK_ALLOCATED();
 
  public:
-  explicit ShapeResultSpacing(const TextContainerType&);
+  explicit ShapeResultSpacing(const TextContainerType& text)
+      : text_(text),
+        letter_spacing_(0),
+        word_spacing_(0),
+        expansion_(0),
+        expansion_per_opportunity_(0),
+        expansion_opportunity_count_(0),
+        text_justify_(TextJustify::kAuto),
+        has_spacing_(false),
+        normalize_space_(false),
+        allow_tabs_(false),
+        is_after_expansion_(false) {}
 
   const TextContainerType& Text() const { return text_; }
   float LetterSpacing() const { return letter_spacing_; }
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
index f1fa25d..46c3a38a 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -2269,7 +2269,7 @@
 void MainThreadSchedulerImpl::AddPageScheduler(
     PageSchedulerImpl* page_scheduler) {
   main_thread_only().page_schedulers.insert(page_scheduler);
-  memory_purge_manager_.OnPageCreated(page_scheduler->IsFrozen());
+  memory_purge_manager_.OnPageCreated(page_scheduler->GetPageLifecycleState());
 }
 
 void MainThreadSchedulerImpl::RemovePageScheduler(
@@ -2277,15 +2277,16 @@
   DCHECK(main_thread_only().page_schedulers.find(page_scheduler) !=
          main_thread_only().page_schedulers.end());
   main_thread_only().page_schedulers.erase(page_scheduler);
-  memory_purge_manager_.OnPageDestroyed(page_scheduler->IsFrozen());
+  memory_purge_manager_.OnPageDestroyed(
+      page_scheduler->GetPageLifecycleState());
 }
 
 void MainThreadSchedulerImpl::OnPageFrozen() {
   memory_purge_manager_.OnPageFrozen();
 }
 
-void MainThreadSchedulerImpl::OnPageUnfrozen() {
-  memory_purge_manager_.OnPageUnfrozen();
+void MainThreadSchedulerImpl::OnPageResumed() {
+  memory_purge_manager_.OnPageResumed();
 }
 
 void MainThreadSchedulerImpl::BroadcastIntervention(
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
index 5fe86ec..d277cd1 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
@@ -306,9 +306,9 @@
   void AddPageScheduler(PageSchedulerImpl*);
   void RemovePageScheduler(PageSchedulerImpl*);
 
-  // Called by an associated PageScheduler when frozen or unfrozen.
+  // Called by an associated PageScheduler when frozen or resumed.
   void OnPageFrozen();
-  void OnPageUnfrozen();
+  void OnPageResumed();
 
   void AddTaskTimeObserver(base::sequence_manager::TaskTimeObserver*);
   void RemoveTaskTimeObserver(base::sequence_manager::TaskTimeObserver*);
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager.cc b/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager.cc
index eeda5a8d..95ffa36a 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager.cc
@@ -4,12 +4,28 @@
 
 #include "third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager.h"
 
+#include "base/feature_list.h"
 #include "base/memory/memory_pressure_listener.h"
+#include "base/metrics/field_trial_params.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/page/launching_process_state.h"
 
 namespace blink {
 
+namespace {
+
+base::TimeDelta FreezePurgeMemoryAllPagesFrozenDelay() {
+  static const base::FeatureParam<int>
+      kFreezePurgeMemoryAllPagesFrozenDelayInMinutes{
+          &blink::features::kFreezePurgeMemoryAllPagesFrozen,
+          "delay-in-minutes",
+          MemoryPurgeManager::kDefaultTimeToPurgeAfterFreezing};
+  return base::TimeDelta::FromMinutes(
+      kFreezePurgeMemoryAllPagesFrozenDelayInMinutes.Get());
+}
+
+}  // namespace
+
 MemoryPurgeManager::MemoryPurgeManager()
     : renderer_backgrounded_(kLaunchingProcessIsBackgrounded),
       total_page_count_(0),
@@ -17,20 +33,23 @@
 
 MemoryPurgeManager::~MemoryPurgeManager() = default;
 
-void MemoryPurgeManager::OnPageCreated(bool is_frozen) {
+void MemoryPurgeManager::OnPageCreated(PageLifecycleState state) {
   total_page_count_++;
-  if (is_frozen) {
+  if (state == PageLifecycleState::kFrozen) {
     frozen_page_count_++;
   } else {
     base::MemoryPressureListener::SetNotificationsSuppressed(false);
   }
+
+  if (!CanPurge())
+    purge_timer_.Stop();
 }
 
-void MemoryPurgeManager::OnPageDestroyed(bool was_frozen) {
+void MemoryPurgeManager::OnPageDestroyed(PageLifecycleState state) {
   DCHECK_GT(total_page_count_, 0);
   DCHECK_GE(frozen_page_count_, 0);
   total_page_count_--;
-  if (was_frozen)
+  if (state == PageLifecycleState::kFrozen)
     frozen_page_count_--;
   DCHECK_LE(frozen_page_count_, total_page_count_);
 }
@@ -39,9 +58,27 @@
   DCHECK_LT(frozen_page_count_, total_page_count_);
   frozen_page_count_++;
 
+  if (purge_timer_.IsRunning())
+    return;
+
   if (!CanPurge())
     return;
 
+  purge_timer_.Start(FROM_HERE, FreezePurgeMemoryAllPagesFrozenDelay(), this,
+                     &MemoryPurgeManager::PerformMemoryPurge);
+}
+
+void MemoryPurgeManager::OnPageResumed() {
+  DCHECK_GT(frozen_page_count_, 0);
+  frozen_page_count_--;
+  if (!CanPurge())
+    purge_timer_.Stop();
+  base::MemoryPressureListener::SetNotificationsSuppressed(false);
+}
+
+void MemoryPurgeManager::PerformMemoryPurge() {
+  DCHECK(CanPurge());
+
   base::MemoryPressureListener::NotifyMemoryPressure(
       base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
 
@@ -49,18 +86,22 @@
     base::MemoryPressureListener::SetNotificationsSuppressed(true);
 }
 
-void MemoryPurgeManager::OnPageUnfrozen() {
-  DCHECK_GT(frozen_page_count_, 0);
-  frozen_page_count_--;
-  base::MemoryPressureListener::SetNotificationsSuppressed(false);
-}
-
 void MemoryPurgeManager::SetRendererBackgrounded(bool backgrounded) {
+  if (!backgrounded)
+    purge_timer_.Stop();
   renderer_backgrounded_ = backgrounded;
 }
 
 bool MemoryPurgeManager::CanPurge() const {
-  return renderer_backgrounded_;
+  if (!renderer_backgrounded_)
+    return false;
+
+  if (!AreAllPagesFrozen() && base::FeatureList::IsEnabled(
+                                  features::kFreezePurgeMemoryAllPagesFrozen)) {
+    return false;
+  }
+
+  return true;
 }
 
 bool MemoryPurgeManager::AreAllPagesFrozen() const {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager.h b/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager.h
index 39c9a99..907145f 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager.h
@@ -6,7 +6,9 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_MEMORY_PURGE_MANAGER_H_
 
 #include "base/macros.h"
+#include "base/timer/timer.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/scheduler/public/page_lifecycle_state.h"
 
 namespace blink {
 
@@ -18,23 +20,36 @@
 
   // Called when a page is created or destroyed, to maintain the total count of
   // pages owned by a renderer.
-  void OnPageCreated(bool is_frozen);
-  void OnPageDestroyed(bool was_frozen);
+  void OnPageCreated(PageLifecycleState state);
+  void OnPageDestroyed(PageLifecycleState state);
 
-  // Called when a page is frozen. If the renderer is backgrounded, sends a
-  // critical memory pressure signal to purge memory.
+  // Called when a page is frozen. If all pages are frozen or
+  // |kFreezePurgeMemoryAllPagesFrozen| is disabled, and the renderer is
+  // backgrounded, ensures that a delayed memory purge is scheduled.
   void OnPageFrozen();
 
-  // Called when a page is unfrozen. Has the effect of unsuppressing memory
-  // pressure notifications.
-  void OnPageUnfrozen();
+  // Called when a page is resumed (unfrozen). Has the effect of unsuppressing
+  // memory pressure notifications.
+  void OnPageResumed();
 
   // Called when the renderer's process priority changes.
   void SetRendererBackgrounded(bool backgrounded);
 
+  // The time of purging after all pages have been frozen.
+  static constexpr int kDefaultTimeToPurgeAfterFreezing = 0;
+
  private:
+  // Called when the timer expires. Simulates a critical memory pressure signal
+  // to purge memory. Suppresses memory pressure notifications if all pages
+  // are frozen.
+  void PerformMemoryPurge();
+
+  // Returns true if all of the following are true:
+  // - The renderer is backgrounded.
+  // - All pages are frozen or kFreezePurgeMemoryAllPagesFrozen is disabled.
   bool CanPurge() const;
 
+  // Returns true if |total_page_count_| == |frozen_page_count_|
   bool AreAllPagesFrozen() const;
 
   bool renderer_backgrounded_;
@@ -42,6 +57,11 @@
   int total_page_count_;
   int frozen_page_count_;
 
+  // Timer to delay memory purging.
+  //
+  // TODO(adityakeerthi): This timer should use a best-effort task runner.
+  base::OneShotTimer purge_timer_;
+
   DISALLOW_COPY_AND_ASSIGN(MemoryPurgeManager);
 };
 
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager_unittest.cc
index ae13213..624111b 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager_unittest.cc
@@ -5,111 +5,265 @@
 #include "third_party/blink/renderer/platform/scheduler/main_thread/memory_purge_manager.h"
 
 #include "base/memory/memory_pressure_listener.h"
-#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
+#include "third_party/blink/renderer/platform/scheduler/public/page_lifecycle_state.h"
 
 namespace blink {
 
+namespace {
+
+constexpr base::TimeDelta kDelayForPurgeAfterFreeze =
+    base::TimeDelta::FromMinutes(1);
+
 class MemoryPurgeManagerTest : public testing::Test {
  public:
-  MemoryPurgeManagerTest() = default;
+  MemoryPurgeManagerTest()
+      : scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::UI_MOCK_TIME,
+            base::test::ScopedTaskEnvironment::NowSource::
+                MAIN_THREAD_MOCK_TIME),
+        observed_memory_pressure_(false) {}
 
   void SetUp() override {
     memory_pressure_listener_ =
         std::make_unique<base::MemoryPressureListener>(base::BindRepeating(
             &MemoryPurgeManagerTest::OnMemoryPressure, base::Unretained(this)));
     base::MemoryPressureListener::SetNotificationsSuppressed(false);
+
+    // Set an initial delay to ensure that the first call to TimeTicks::Now()
+    // before incrementing the counter does not return a null value.
+    FastForwardBy(base::TimeDelta::FromSeconds(1));
   }
 
-  void TearDown() override { memory_pressure_listener_.reset(); }
+  void TearDown() override {
+    memory_pressure_listener_.reset();
+    scoped_task_environment_.FastForwardUntilNoTasksRemain();
+  }
 
  protected:
+  void SetupDelayedPurgeAfterFreezeExperiment() {
+    scoped_feature_list_.InitAndEnableFeatureWithParameters(
+        features::kFreezePurgeMemoryAllPagesFrozen,
+        {{"delay-in-minutes",
+          base::IntToString(kDelayForPurgeAfterFreeze.InMinutes())}});
+  }
+
   void ExpectMemoryPressure(
-      base::MemoryPressureListener::MemoryPressureLevel level) {
-    EXPECT_CALL(*this, OnMemoryPressure(level)).Times(1);
-    base::RunLoop().RunUntilIdle();
+      base::TimeDelta delay = base::TimeDelta::FromMinutes(0)) {
+    FastForwardBy(delay);
+    EXPECT_TRUE(observed_memory_pressure_);
+    observed_memory_pressure_ = false;
   }
 
-  void ExpectNoMemoryPressure() {
-    EXPECT_CALL(*this, OnMemoryPressure(testing::_)).Times(0);
-    base::RunLoop().RunUntilIdle();
+  void ExpectNoMemoryPressure(
+      base::TimeDelta delay = base::TimeDelta::FromMinutes(0)) {
+    FastForwardBy(delay);
+    EXPECT_FALSE(observed_memory_pressure_);
   }
 
+  void FastForwardBy(base::TimeDelta delta) {
+    scoped_task_environment_.FastForwardBy(delta);
+  }
+
+  base::test::ScopedFeatureList scoped_feature_list_;
   base::test::ScopedTaskEnvironment scoped_task_environment_;
   std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
 
+  bool observed_memory_pressure_;
+
   MemoryPurgeManager memory_purge_manager_;
 
  private:
-  MOCK_METHOD1(OnMemoryPressure,
-               void(base::MemoryPressureListener::MemoryPressureLevel));
+  void OnMemoryPressure(base::MemoryPressureListener::MemoryPressureLevel) {
+    observed_memory_pressure_ = true;
+  }
+
   DISALLOW_COPY_AND_ASSIGN(MemoryPurgeManagerTest);
 };
 
 // Verify that OnPageFrozen() triggers a memory pressure notification in a
 // backgrounded renderer.
 TEST_F(MemoryPurgeManagerTest, PageFrozenInBackgroundedRenderer) {
-  memory_purge_manager_.OnPageCreated(false /* is_frozen */);
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kActive);
   memory_purge_manager_.SetRendererBackgrounded(true);
   memory_purge_manager_.OnPageFrozen();
-  ExpectMemoryPressure(base::MemoryPressureListener::MemoryPressureLevel::
-                           MEMORY_PRESSURE_LEVEL_CRITICAL);
+  ExpectMemoryPressure();
 }
 
 // Verify that OnPageFrozen() does not trigger a memory pressure notification in
 // a foregrounded renderer.
 TEST_F(MemoryPurgeManagerTest, PageFrozenInForegroundedRenderer) {
-  memory_purge_manager_.OnPageCreated(false /* is_frozen */);
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kActive);
   memory_purge_manager_.SetRendererBackgrounded(false);
   memory_purge_manager_.OnPageFrozen();
   ExpectNoMemoryPressure();
 }
 
-TEST_F(MemoryPurgeManagerTest, PageUnfrozenUndoMemoryPressureSuppression) {
-  memory_purge_manager_.OnPageCreated(false /* is_frozen */);
+TEST_F(MemoryPurgeManagerTest, PageResumedUndoMemoryPressureSuppression) {
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kActive);
 
   memory_purge_manager_.SetRendererBackgrounded(true);
   memory_purge_manager_.OnPageFrozen();
+  ExpectMemoryPressure();
   EXPECT_TRUE(base::MemoryPressureListener::AreNotificationsSuppressed());
-  memory_purge_manager_.OnPageUnfrozen();
+  memory_purge_manager_.OnPageResumed();
   EXPECT_FALSE(base::MemoryPressureListener::AreNotificationsSuppressed());
 
-  memory_purge_manager_.OnPageDestroyed(false /* was_frozen */);
+  memory_purge_manager_.OnPageDestroyed(PageLifecycleState::kActive);
 }
 
-TEST_F(MemoryPurgeManagerTest,
-       PageFrozenMemorySuppressionOnlyWhenAllPagesFrozen) {
+TEST_F(MemoryPurgeManagerTest, PageFrozenPurgeMemoryAllPagesFrozenDisabled) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures(
+      {} /* enabled */,
+      {features::kFreezePurgeMemoryAllPagesFrozen} /* disabled */);
+
   memory_purge_manager_.SetRendererBackgrounded(true);
 
-  memory_purge_manager_.OnPageCreated(false /* is_frozen */);
-  memory_purge_manager_.OnPageCreated(false /* is_frozen */);
-  memory_purge_manager_.OnPageCreated(false /* is_frozen */);
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kActive);
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kActive);
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kActive);
 
   memory_purge_manager_.OnPageFrozen();
+  ExpectMemoryPressure();
   EXPECT_FALSE(base::MemoryPressureListener::AreNotificationsSuppressed());
 
   memory_purge_manager_.OnPageFrozen();
+  ExpectMemoryPressure();
   EXPECT_FALSE(base::MemoryPressureListener::AreNotificationsSuppressed());
 
   memory_purge_manager_.OnPageFrozen();
+  ExpectMemoryPressure();
   EXPECT_TRUE(base::MemoryPressureListener::AreNotificationsSuppressed());
 
-  memory_purge_manager_.OnPageUnfrozen();
+  memory_purge_manager_.OnPageResumed();
   EXPECT_FALSE(base::MemoryPressureListener::AreNotificationsSuppressed());
 
-  memory_purge_manager_.OnPageDestroyed(false /* was_frozen */);
+  memory_purge_manager_.OnPageDestroyed(PageLifecycleState::kActive);
   EXPECT_FALSE(base::MemoryPressureListener::AreNotificationsSuppressed());
 
-  memory_purge_manager_.OnPageCreated(false /* is_frozen */);
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kActive);
   EXPECT_FALSE(base::MemoryPressureListener::AreNotificationsSuppressed());
 
-  memory_purge_manager_.OnPageDestroyed(false /* was_frozen */);
-  memory_purge_manager_.OnPageDestroyed(true /* was_frozen */);
-  memory_purge_manager_.OnPageDestroyed(true /* was_frozen */);
+  memory_purge_manager_.OnPageDestroyed(PageLifecycleState::kActive);
+  memory_purge_manager_.OnPageDestroyed(PageLifecycleState::kFrozen);
+  memory_purge_manager_.OnPageDestroyed(PageLifecycleState::kFrozen);
 }
 
+TEST_F(MemoryPurgeManagerTest, PageFrozenPurgeMemoryAllPagesFrozenEnabled) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures(
+      {features::kFreezePurgeMemoryAllPagesFrozen} /* enabled */,
+      {} /* disabled */);
+
+  memory_purge_manager_.SetRendererBackgrounded(true);
+
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kActive);
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kActive);
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kActive);
+
+  memory_purge_manager_.OnPageFrozen();
+  ExpectNoMemoryPressure();
+  EXPECT_FALSE(base::MemoryPressureListener::AreNotificationsSuppressed());
+
+  memory_purge_manager_.OnPageFrozen();
+  ExpectNoMemoryPressure();
+  EXPECT_FALSE(base::MemoryPressureListener::AreNotificationsSuppressed());
+
+  memory_purge_manager_.OnPageFrozen();
+  ExpectMemoryPressure();
+  EXPECT_TRUE(base::MemoryPressureListener::AreNotificationsSuppressed());
+
+  memory_purge_manager_.OnPageResumed();
+  EXPECT_FALSE(base::MemoryPressureListener::AreNotificationsSuppressed());
+
+  memory_purge_manager_.OnPageDestroyed(PageLifecycleState::kActive);
+  EXPECT_FALSE(base::MemoryPressureListener::AreNotificationsSuppressed());
+
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kActive);
+  EXPECT_FALSE(base::MemoryPressureListener::AreNotificationsSuppressed());
+
+  memory_purge_manager_.OnPageDestroyed(PageLifecycleState::kActive);
+  memory_purge_manager_.OnPageDestroyed(PageLifecycleState::kFrozen);
+  memory_purge_manager_.OnPageDestroyed(PageLifecycleState::kFrozen);
+}
+
+TEST_F(MemoryPurgeManagerTest, MemoryPurgeWithDelay) {
+  SetupDelayedPurgeAfterFreezeExperiment();
+
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kActive);
+
+  memory_purge_manager_.SetRendererBackgrounded(true);
+  memory_purge_manager_.OnPageFrozen();
+
+  // The memory pressure notification should not occur immediately
+  ExpectNoMemoryPressure();
+
+  // The memory pressure notification should occur after 1 minute
+  ExpectMemoryPressure(kDelayForPurgeAfterFreeze);
+
+  memory_purge_manager_.OnPageDestroyed(PageLifecycleState::kFrozen);
+}
+
+TEST_F(MemoryPurgeManagerTest, CancelMemoryPurgeWithDelay) {
+  SetupDelayedPurgeAfterFreezeExperiment();
+
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kActive);
+
+  memory_purge_manager_.SetRendererBackgrounded(true);
+  memory_purge_manager_.OnPageFrozen();
+  FastForwardBy(base::TimeDelta::FromSeconds(40));
+  ExpectNoMemoryPressure();
+
+  // If the page is resumed before the memory purge timer expires, the purge
+  // should be cancelled.
+  memory_purge_manager_.OnPageResumed();
+  ExpectNoMemoryPressure(kDelayForPurgeAfterFreeze);
+
+  memory_purge_manager_.OnPageDestroyed(PageLifecycleState::kActive);
+}
+
+TEST_F(MemoryPurgeManagerTest, MemoryPurgeWithDelayNewActivePageCreated) {
+  SetupDelayedPurgeAfterFreezeExperiment();
+
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kActive);
+
+  memory_purge_manager_.SetRendererBackgrounded(true);
+  memory_purge_manager_.OnPageFrozen();
+  FastForwardBy(base::TimeDelta::FromSeconds(40));
+  ExpectNoMemoryPressure();
+
+  // All pages are no longer frozen, the memory purge should be cancelled.
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kActive);
+  ExpectNoMemoryPressure(kDelayForPurgeAfterFreeze);
+
+  memory_purge_manager_.OnPageDestroyed(PageLifecycleState::kFrozen);
+  memory_purge_manager_.OnPageDestroyed(PageLifecycleState::kActive);
+}
+
+TEST_F(MemoryPurgeManagerTest, MemoryPurgeWithDelayNewFrozenPageCreated) {
+  SetupDelayedPurgeAfterFreezeExperiment();
+
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kActive);
+
+  memory_purge_manager_.SetRendererBackgrounded(true);
+  memory_purge_manager_.OnPageFrozen();
+  FastForwardBy(base::TimeDelta::FromSeconds(40));
+  ExpectNoMemoryPressure();
+
+  // All pages are still frozen and the memory purge should occur.
+  memory_purge_manager_.OnPageCreated(PageLifecycleState::kFrozen);
+  ExpectMemoryPressure(kDelayForPurgeAfterFreeze);
+
+  memory_purge_manager_.OnPageDestroyed(PageLifecycleState::kFrozen);
+  memory_purge_manager_.OnPageDestroyed(PageLifecycleState::kFrozen);
+}
+
+}  // namespace
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
index 7ddb029..cb665a63 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
@@ -125,6 +125,10 @@
       background_time_budget_pool_(nullptr),
       delegate_(delegate),
       weak_factory_(this) {
+  page_lifecycle_state_tracker_.reset(new PageLifecycleStateTracker(
+      this, kDefaultPageVisibility == PageVisibilityState::kVisible
+                ? PageLifecycleState::kActive
+                : PageLifecycleState::kHiddenBackgrounded));
   main_thread_scheduler->AddPageScheduler(this);
   do_throttle_page_callback_.Reset(base::BindRepeating(
       &PageSchedulerImpl::DoThrottlePage, base::Unretained(this)));
@@ -143,10 +147,6 @@
   } else {
     delay_for_background_tab_freezing_ = kDelayForBackgroundTabFreezing;
   }
-  page_lifecycle_state_tracker_.reset(new PageLifecycleStateTracker(
-      this, kDefaultPageVisibility == PageVisibilityState::kVisible
-                ? PageLifecycleState::kActive
-                : PageLifecycleState::kHiddenBackgrounded));
 }
 
 PageSchedulerImpl::~PageSchedulerImpl() {
@@ -252,7 +252,7 @@
       page_lifecycle_state_tracker_->SetPageLifecycleState(
           PageLifecycleState::kHiddenForegrounded);
     }
-    main_thread_scheduler_->OnPageUnfrozen();
+    main_thread_scheduler_->OnPageResumed();
   }
 }
 
@@ -587,6 +587,10 @@
   SetPageFrozenImpl(true, NotificationPolicy::kNotifyFrames);
 }
 
+PageLifecycleState PageSchedulerImpl::GetPageLifecycleState() const {
+  return page_lifecycle_state_tracker_->GetPageLifecycleState();
+}
+
 PageSchedulerImpl::PageLifecycleStateTracker::PageLifecycleStateTracker(
     PageSchedulerImpl* page_scheduler_impl,
     PageLifecycleState state)
@@ -611,6 +615,11 @@
   current_state_ = new_state;
 }
 
+PageLifecycleState
+PageSchedulerImpl::PageLifecycleStateTracker::GetPageLifecycleState() const {
+  return current_state_;
+}
+
 // static
 base::Optional<PageSchedulerImpl::PageLifecycleStateTransition>
 PageSchedulerImpl::PageLifecycleStateTracker::
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
index e9e0e9a..b521831 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
@@ -107,6 +107,8 @@
   // Return a number of child web frame schedulers for this PageScheduler.
   size_t FrameCount() const;
 
+  PageLifecycleState GetPageLifecycleState() const;
+
   // Generally UKMs are asssociated with the main frame of a page, but the
   // implementation allows to request a recorder from any local frame with
   // the same result (e.g. for OOPIF support), therefore we need to select
@@ -163,6 +165,7 @@
     ~PageLifecycleStateTracker() = default;
 
     void SetPageLifecycleState(PageLifecycleState);
+    PageLifecycleState GetPageLifecycleState() const;
 
    private:
     static base::Optional<PageLifecycleStateTransition>
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin.cc b/third_party/blink/renderer/platform/weborigin/security_origin.cc
index d629c18ca..afd8cd2d 100644
--- a/third_party/blink/renderer/platform/weborigin/security_origin.cc
+++ b/third_party/blink/renderer/platform/weborigin/security_origin.cc
@@ -29,7 +29,10 @@
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 
 #include <stdint.h>
+
 #include <memory>
+#include <string>
+#include <utility>
 
 #include "net/base/url_util.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -433,6 +436,10 @@
 }
 
 bool SecurityOrigin::IsPotentiallyTrustworthy() const {
+  // TODO(lukasza): The code below can hopefully be eventually deleted and
+  // IsOriginPotentiallyTrustworthy can be used instead (from
+  // //services/network/public/cpp/is_potentially_trustworthy.h).
+
   DCHECK_NE(protocol_, "data");
 
   if (IsOpaque())
diff --git a/third_party/blink/web_tests/ASANExpectations b/third_party/blink/web_tests/ASANExpectations
index d648a7e7..b5b04b5 100644
--- a/third_party/blink/web_tests/ASANExpectations
+++ b/third_party/blink/web_tests/ASANExpectations
@@ -48,7 +48,9 @@
 crbug.com/438499 [ Linux ] http/tests/websocket/workers/worker-simple.html [ Timeout ]
 crbug.com/438499 [ Linux ] http/tests/workers/text-encoding.html [ Timeout ]
 crbug.com/438499 [ Linux ] http/tests/devtools/profiler/heap-snapshot-loader.js [ Timeout ]
+crbug.com/438499 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/profiler/heap-snapshot-loader.js [ Timeout ]
 crbug.com/438499 [ Linux ] http/tests/devtools/profiler/heap-snapshot-containment-show-all.js [ Timeout ]
+crbug.com/438499 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/profiler/heap-snapshot-containment-show-all.js [ Timeout ]
 crbug.com/438499 [ Linux ] virtual/threaded/animations/unanimated-style.html [ Timeout ]
 
 # Flakily timeout on Linux ASAN bots.
@@ -56,7 +58,9 @@
 crbug.com/464065 [ Linux ] media/track/css-cue-for-video-in-shadow.html [ Timeout ]
 crbug.com/464065 [ Linux ] media/track/css-cue-for-video-in-shadow-2.html [ Timeout ]
 crbug.com/572723 [ Linux ] http/tests/devtools/sources/debugger/debugger-completions-on-call-frame.js [ Timeout Pass ]
+crbug.com/572723 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/sources/debugger/debugger-completions-on-call-frame.js [ Timeout Pass ]
 crbug.com/700795 [ Linux ] http/tests/devtools/animation/animation-transition-setTiming-crash.js [ Skip ]
+crbug.com/700795 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/animation/animation-transition-setTiming-crash.js [ Skip ]
 crbug.com/928941 [ Linux ] external/wpt/background-fetch/fetch.https.window.html [ Timeout ]
 
 # Intentionally failed allocations, via partitionAllocGenericFlags()
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials b/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials
index f896f9d..d7cbba6 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials
+++ b/third_party/blink/web_tests/FlagExpectations/disable-site-isolation-trials
@@ -13,8 +13,13 @@
 crbug.com/933880 external/wpt/FileAPI/url/url-with-xhr.any.html [ Failure ]

 crbug.com/933880 external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ]

 crbug.com/933880 http/tests/inspector-protocol/network/interception-take-stream.js [ Failure ]

+crbug.com/933880 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/network/interception-take-stream.js [ Failure ]

 crbug.com/933880 http/tests/inspector-protocol/network/raw-headers-for-protected-document.js [ Failure ]

+crbug.com/933880 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/network/raw-headers-for-protected-document.js [ Failure ]

 crbug.com/933880 http/tests/inspector-protocol/network/raw-headers-for-websocket.js [ Failure ]

+crbug.com/933880 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/network/raw-headers-for-websocket.js [ Failure ]

 crbug.com/933880 http/tests/inspector-protocol/network/security-info-on-response.js [ Failure ]

+crbug.com/933880 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/network/security-info-on-response.js [ Failure ]

 crbug.com/933880 http/tests/inspector-protocol/network/xhr-interception-auth-fail.js [ Failure ]

+crbug.com/933880 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/network/xhr-interception-auth-fail.js [ Failure ]

 crbug.com/933880 http/tests/misc/redirect-to-about-blank.html [ Timeout ]

diff --git a/third_party/blink/web_tests/LeakExpectations b/third_party/blink/web_tests/LeakExpectations
index 3da36dd..e3af792 100644
--- a/third_party/blink/web_tests/LeakExpectations
+++ b/third_party/blink/web_tests/LeakExpectations
@@ -23,6 +23,7 @@
 
 crbug.com/786995 virtual/threaded/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.js [ Leak Pass ]
 crbug.com/859640 http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.js  [ Leak Pass ]
+crbug.com/859640 virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.js  [ Leak Pass ]
 
 # Requests with keepalive specified will be kept alive even when the frame is
 # detached, which means leaks reported by the leak detector are by design.
@@ -35,6 +36,7 @@
 # -----------------------------------------------------------------
 crbug.com/780386 external/wpt/html/dom/reflection-grouping.html [ Leak Pass ]
 crbug.com/667560 [ Linux ] http/tests/devtools/console/console-search.js [ Leak Pass ]
+crbug.com/667560 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/console/console-search.js [ Leak Pass ]
 crbug.com/835943 [ Linux ] http/tests/appcache/non-html.xhtml [ Leak Pass ]
 
 crbug.com/860117 [ Linux ] editing/pasteboard/drag-drop-iframe-refresh-crash.html [ Pass Leak ]
@@ -61,12 +63,14 @@
 # Sheriff 2018-07-10
 # Test flaking on Linux Trusty Leak
 crbug.com/862029 [ Linux ] http/tests/devtools/tracing/timeline-misc/timeline-window-filter.js [ Pass Leak ]
+crbug.com/862029 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-misc/timeline-window-filter.js [ Pass Leak ]
 
 # Sheriff 2018-08-15
 crbug.com/874442 [ Linux ] svg/animations/mpath-remove-from-dependents-on-delete-crash.html [ Pass Crash ]
 
 # Sheriff 2018-08-17
 crbug.com/847114 [ Linux ] http/tests/devtools/tracing/decode-resize.js [ Pass Failure ]
+crbug.com/847114 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/tracing/decode-resize.js [ Pass Failure ]
 crbug.com/847114 [ Linux ] virtual/threaded/http/tests/devtools/tracing/decode-resize.js [ Pass Failure ]
 
 # Sheriff 2018-08-29
@@ -92,6 +96,7 @@
 
 #Sheriff 2019-02-21
 crbug.com/934144 [ Linux ] http/tests/devtools/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.js [ Pass Leak ]
+crbug.com/934144 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.js [ Pass Leak ]
 
 #Sheriff 2019-02-25
 crbug.com/894651 [ Linux ] virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_09_rtl_multi_line.html [ Failure Leak ]
diff --git a/third_party/blink/web_tests/MSANExpectations b/third_party/blink/web_tests/MSANExpectations
index 7e56cda..17b6538 100644
--- a/third_party/blink/web_tests/MSANExpectations
+++ b/third_party/blink/web_tests/MSANExpectations
@@ -15,6 +15,7 @@
 crbug.com/422982 [ Linux ] virtual/threaded [ Skip ]
 
 crbug.com/700795 [ Linux ] http/tests/devtools/animation/animation-transition-setTiming-crash.js [ Skip ]
+crbug.com/700795 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/animation/animation-transition-setTiming-crash.js [ Skip ]
 
 crbug.com/454267 [ Linux ] virtual/gpu/fast/canvas/canvas-arc-360-winding.html [ Crash ]
 crbug.com/454267 [ Linux ] virtual/gpu/fast/canvas/canvas-ellipse-360-winding.html [ Crash ]
@@ -44,8 +45,11 @@
 crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-snapshot-with-no-detached-iframe.js [ Timeout ]
 
 crbug.com/667560 [ Linux ] http/tests/devtools/startup/console/console-format-startup.js [ Timeout Pass ]
+crbug.com/667560 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/startup/console/console-format-startup.js [ Timeout Pass ]
 crbug.com/751906 [ Linux ] http/tests/devtools/console/console-correct-suggestions.js [ Timeout Pass ]
+crbug.com/751906 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/console/console-correct-suggestions.js [ Timeout Pass ]
 crbug.com/811820 [ Linux ] http/tests/devtools/tracing-session-id.js [ Timeout Pass ]
+crbug.com/811820 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/tracing-session-id.js [ Timeout Pass ]
 
 crbug.com/736370 [ Linux ] external/wpt/editing/run/removeformat.html [ Timeout ]
 crbug.com/810960 [ Linux ] external/wpt/IndexedDB/nested-cloning-large.html [ Timeout ]
@@ -69,32 +73,50 @@
 crbug.com/729136 [ Linux ] external/wpt/mimesniff/mime-types/parsing.any.worker.html [ Timeout ]
 crbug.com/729136 [ Linux ] fast/css/css-selector-deeply-nested.html [ Timeout ]
 crbug.com/729136 [ Linux ] http/tests/devtools/forced-layout-in-microtask.js [ Timeout ]
+crbug.com/729136 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/forced-layout-in-microtask.js [ Timeout ]
 crbug.com/729136 [ Linux ] http/tests/devtools/tracing/timeline-xhr-response-type-blob-event.js [ Timeout ]
+crbug.com/729136 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-xhr-response-type-blob-event.js [ Timeout ]
 crbug.com/729136 [ Linux ] http/tests/devtools/components/file-path-scoring.js [ Timeout ]
+crbug.com/729136 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/components/file-path-scoring.js [ Timeout ]
 crbug.com/729136 [ Linux ] http/tests/devtools/elements/styles-4/styles-should-not-force-sync-style-recalc.js [ Timeout ]
+crbug.com/729136 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/elements/styles-4/styles-should-not-force-sync-style-recalc.js [ Timeout ]
 crbug.com/729136 [ Linux ] webaudio/mixing.html [ Timeout ]
 
 crbug.com/739365 [ Linux ] virtual/layout_ng/fast/block/float/assert-when-moving-float.html [ Skip ]
 
 # Tests timing out on WebKit Linux Trusty MSAN
 crbug.com/760543 [ Linux ] http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.js [ Pass Timeout ]
+crbug.com/760543 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.js [ Pass Timeout ]
 crbug.com/760543 [ Linux ] http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.js [ Pass Timeout ]
+crbug.com/760543 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.js [ Pass Timeout ]
 crbug.com/760543 [ Linux ] http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.js [ Pass Timeout ]
+crbug.com/760543 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.js [ Pass Timeout ]
 crbug.com/760543 [ Linux ] http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.js [ Pass Timeout ]
+crbug.com/760543 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.js [ Pass Timeout ]
 crbug.com/760543 [ Linux ] http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.js [ Pass Timeout ]
+crbug.com/760543 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.js [ Pass Timeout ]
 crbug.com/760543 [ Linux ] http/tests/devtools/tracing/timeline-misc/timeline-event-causes.js [ Pass Timeout ]
+crbug.com/760543 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.js [ Pass Timeout ]
 crbug.com/760543 [ Linux ] http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.js [ Pass Timeout ]
+crbug.com/760543 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.js [ Pass Timeout ]
 crbug.com/760543 [ Linux ] http/tests/devtools/tracing/timeline-time/timeline-usertiming.js [ Pass Timeout ]
+crbug.com/760543 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-time/timeline-usertiming.js [ Pass Timeout ]
 crbug.com/760543 [ Linux ] http/tests/devtools/tracing/timeline-paint/timeline-paint.js [ Pass Timeout ]
+crbug.com/760543 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-paint/timeline-paint.js [ Pass Timeout ]
 crbug.com/760543 [ Linux ] http/tests/devtools/oopif/oopif-performance-cpu-profiles.js [ Pass Timeout ]
+crbug.com/760543 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/oopif/oopif-performance-cpu-profiles.js [ Pass Timeout ]
 crbug.com/902685 [ Linux ] http/tests/devtools/isolated-code-cache/same-origin-test.js [ Pass Timeout ]
+crbug.com/902685 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/isolated-code-cache/same-origin-test.js [ Pass Timeout ]
 crbug.com/902685 [ Linux ] http/tests/devtools/isolated-code-cache/cross-origin-test.js [ Pass Timeout ]
+crbug.com/902685 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/isolated-code-cache/cross-origin-test.js [ Pass Timeout ]
 crbug.com/902685 [ Linux ] virtual/site-isolated-code-cache/http/tests/devtools/isolated-code-cache/same-origin-test.js [ Pass Timeout ]
 crbug.com/902685 [ Linux ] virtual/site-isolated-code-cache/http/tests/devtools/isolated-code-cache/cross-origin-test.js [ Pass Timeout ]
 
 # Timing out consistenly on WebKit Linux Trusty MSAN
 crbug.com/798957 [ Linux ] http/tests/devtools/audits2/audits2-limited-run.js [ Skip ]
+crbug.com/798957 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/audits2/audits2-limited-run.js [ Skip ]
 crbug.com/798957 [ Linux ] http/tests/devtools/audits2/audits2-successful-run.js [ Skip ]
+crbug.com/798957 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/audits2/audits2-successful-run.js [ Skip ]
 crbug.com/824455 [ Linux ] external/wpt/webaudio/idlharness.https.html [ Skip ]
 
 # Memory allocation hooks are disabled on ASAN/MSAN
@@ -105,6 +127,7 @@
 
 # The following test is flaky and timing out on chromium.webkit/WebKit Linux Trusty MSAN.
 crbug.com/851497 http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.js [ Pass Timeout ]
+crbug.com/851497 virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.js [ Pass Timeout ]
 
 crbug.com/862750 [ Linux ] inspector-protocol/memory/sampling-native-profile-blink-gc.js [ Pass Crash ]
 crbug.com/862750 [ Linux ] virtual/sampling-heap-profiler/inspector-protocol/memory/sampling-native-profile-blink-gc.js [ Pass Crash ]
@@ -114,6 +137,7 @@
 
 crbug.com/856601 [ Linux ] fast/css/visited-link-hang.html [ Pass Timeout ]
 crbug.com/856601 [ Linux ] http/tests/devtools/elements/styles-4/styles-inline-element-style-changes-should-not-force-style-recalc.js [ Pass Timeout ]
+crbug.com/856601 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/elements/styles-4/styles-inline-element-style-changes-should-not-force-style-recalc.js [ Pass Timeout ]
 crbug.com/856601 [ Linux ] external/wpt/event-timing/event-timing-retrievability.html [ Pass Timeout ]
 
 # Slow idlharness.js tests on MSAN
@@ -203,6 +227,7 @@
 
 # Sheriff 2018-11-22
 crbug.com/856601 [ Linux ] http/tests/devtools/elements/elements-save-to-temp-var.js [ Pass Timeout ]
+crbug.com/856601 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/elements/elements-save-to-temp-var.js [ Pass Timeout ]
 
 # Sheriff 2018-12-13
 crbug.com/914900 [ Linux ] external/wpt/content-security-policy/embedded-enforcement/idlharness.window.html [ Pass Timeout ]
@@ -210,6 +235,7 @@
 crbug.com/914900 [ Linux ] external/wpt/fetch/api/idl.any.worker.html [ Pass Timeout ]
 crbug.com/914900 [ Linux ] external/wpt/secure-contexts/idlharness.any.worker.html [ Pass Timeout ]
 crbug.com/914900 [ Linux ] http/tests/devtools/network/preview-searchable.js [ Pass Timeout ]
+crbug.com/914900 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/network/preview-searchable.js [ Pass Timeout ]
 crbug.com/914900 [ Linux ] virtual/outofblink-cors/external/wpt/xhr/idlharness.any.worker.html [ Pass Timeout ]
 
 # Sheriff 2019-01-28
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index 2565b84..dc1a2a66 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -2204,6 +2204,7 @@
 # 3) site isolation is enabled without also enabling
 #    IsolatedCodeCache (tests disabled by the test expectation below).
 Bug(none) http/tests/devtools/isolated-code-cache/cross-origin-test.js [ WontFix ]
+Bug(none) virtual/binary-for-devtools/http/tests/devtools/isolated-code-cache/cross-origin-test.js [ WontFix ]
 # ==== Tests incompatible with the default WPT Origin Isolation end here ==^^
 
 external/wpt/css/css-overscroll-behavior/overscrollBehavior-manual.html [ WontFix ]
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index 5878b9bf..e5c0334 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -78,47 +78,76 @@
 
 # Most DevTools tests are slow in Debug.
 webkit.org/b/90488 [ Debug ] http/tests/devtools/ [ Slow ]
+webkit.org/b/90488 [ Debug ] virtual/binary-for-devtools/http/tests/devtools/ [ Slow ]
 webkit.org/b/90488 [ Debug ] inspector-protocol/ [ Slow ]
 
 # DevTools console, debugger and profiler tests are slow in Release as well.
 crbug.com/451577 http/tests/devtools/console [ Slow ]
+crbug.com/451577 virtual/binary-for-devtools/http/tests/devtools/console [ Slow ]
 crbug.com/450493 http/tests/devtools/sources/ [ Slow ]
+crbug.com/450493 virtual/binary-for-devtools/http/tests/devtools/sources/ [ Slow ]
 crbug.com/450493 http/tests/devtools/startup/sources/ [ Slow ]
+crbug.com/450493 virtual/binary-for-devtools/http/tests/devtools/startup/sources/ [ Slow ]
 crbug.com/450493 http/tests/devtools/csp/ [ Slow ]
+crbug.com/450493 virtual/binary-for-devtools/http/tests/devtools/csp/ [ Slow ]
 crbug.com/450493 http/tests/devtools/profiler/ [ Slow ]
+crbug.com/450493 virtual/binary-for-devtools/http/tests/devtools/profiler/ [ Slow ]
 crbug.com/420008 http/tests/devtools/tracing/ [ Slow ]
+crbug.com/420008 virtual/binary-for-devtools/http/tests/devtools/tracing/ [ Slow ]
 crbug.com/420008 virtual/threaded/http/tests/devtools/tracing/ [ Slow ]
 crbug.com/902685 http/tests/devtools/isolated-code-cache/ [ Slow ]
+crbug.com/902685 virtual/binary-for-devtools/http/tests/devtools/isolated-code-cache/ [ Slow ]
 crbug.com/902685 virtual/site-isolated-code-cache/http/tests/devtools/isolated-code-cache/ [ Slow ]
 crbug.com/902685 virtual/not-site-per-process/http/tests/devtools/isolated-code-cache/ [ Slow ]
 crbug.com/902685 http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test.js [ Slow ]
+crbug.com/902685 virtual/binary-for-devtools/http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test.js [ Slow ]
 crbug.com/902685 virtual/wasm-site-isolated-code-cache/http/tests/devtools/wasm-isolated-code-cache/wasm-cache-test.js [ Slow ]
 
 # Misc DevTools tests that are slow
 crbug.com/246190 [ Release ] http/tests/devtools/indexeddb/ [ Slow ]
+crbug.com/246190 [ Release ] virtual/binary-for-devtools/http/tests/devtools/indexeddb/ [ Slow ]
 crbug.com/451577 [ Mac ] http/tests/devtools/extensions/extensions-sidebar.js [ Slow ]
+crbug.com/451577 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/extensions/extensions-sidebar.js [ Slow ]
 crbug.com/451577 [ Mac ] http/tests/devtools/extensions/extensions-events.js [ Slow ]
+crbug.com/451577 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/extensions/extensions-events.js [ Slow ]
 crbug.com/667560 http/tests/devtools/startup/console/console-format-startup.js [ Slow ]
+crbug.com/667560 virtual/binary-for-devtools/http/tests/devtools/startup/console/console-format-startup.js [ Slow ]
 crbug.com/679833 http/tests/devtools/network/network-datareceived.js [ Slow ]
+crbug.com/679833 virtual/binary-for-devtools/http/tests/devtools/network/network-datareceived.js [ Slow ]
 webkit.org/b/90488 [ Release ] http/tests/devtools/compiler-source-mapping-debug.js [ Slow ]
+webkit.org/b/90488 [ Release ] virtual/binary-for-devtools/http/tests/devtools/compiler-source-mapping-debug.js [ Slow ]
 crbug.com/243492 inspector-protocol/injected-script-discard.js [ Slow ]
 crbug.com/327078 http/tests/devtools/network/long-script-content.js [ Slow ]
+crbug.com/327078 virtual/binary-for-devtools/http/tests/devtools/network/long-script-content.js [ Slow ]
 crbug.com/420008 [ Release ] http/tests/devtools/editor/text-editor-word-jumps.js [ Slow ]
+crbug.com/420008 [ Release ] virtual/binary-for-devtools/http/tests/devtools/editor/text-editor-word-jumps.js [ Slow ]
 crbug.com/420008 [ Release ] http/tests/devtools/console-xhr-logging.js [ Slow ]
+crbug.com/420008 [ Release ] virtual/binary-for-devtools/http/tests/devtools/console-xhr-logging.js [ Slow ]
 crbug.com/596486 [ Linux ] http/tests/devtools/elements/insert-node.js [ Slow ]
+crbug.com/596486 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/elements/insert-node.js [ Slow ]
 crbug.com/504565 [ Mac ] http/tests/devtools/search/sources-search-scope.js [ Slow ]
+crbug.com/504565 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/search/sources-search-scope.js [ Slow ]
 crbug.com/451577 http/tests/devtools/resource-tree/resource-tree-crafted-frame-add.js [ Slow ]
+crbug.com/451577 virtual/binary-for-devtools/http/tests/devtools/resource-tree/resource-tree-crafted-frame-add.js [ Slow ]
 crbug.com/451577 http/tests/devtools/resource-tree/resource-tree-frame-in-crafted-frame.js [ Slow ]
+crbug.com/451577 virtual/binary-for-devtools/http/tests/devtools/resource-tree/resource-tree-frame-in-crafted-frame.js [ Slow ]
 crbug.com/510337 http/tests/devtools/elements/styles-1/edit-value-url-with-color.js [ Slow ]
+crbug.com/510337 virtual/binary-for-devtools/http/tests/devtools/elements/styles-1/edit-value-url-with-color.js [ Slow ]
 crbug.com/451577 [ Mac ] http/tests/devtools/extensions/extensions-reload.js [ Slow ]
+crbug.com/451577 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/extensions/extensions-reload.js [ Slow ]
 crbug.com/451577 [ Mac ] http/tests/devtools/extensions/extensions-resources.js [ Slow ]
+crbug.com/451577 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/extensions/extensions-resources.js [ Slow ]
 crbug.com/451577 [ Win10 ] http/tests/devtools/extensions/extensions-sidebar.js [ Slow ]
+crbug.com/451577 [ Win10 ] virtual/binary-for-devtools/http/tests/devtools/extensions/extensions-sidebar.js [ Slow ]
 crbug.com/451577 [ Mac ] http/tests/devtools/layers/layer-canvas-log.js [ Slow ]
+crbug.com/451577 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/layers/layer-canvas-log.js [ Slow ]
 crbug.com/451577 [ Mac ] http/tests/devtools/network/network-domain-filter.js [ Slow ]
+crbug.com/451577 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/network/network-domain-filter.js [ Slow ]
 
 crbug.com/510337 cssom/cssvalue-comparison.html [ Slow ]
 
 crbug.com/680917 http/tests/devtools/audits2/ [ Slow ]
+crbug.com/680917 virtual/binary-for-devtools/http/tests/devtools/audits2/ [ Slow ]
 
 # These tests are intentionally SLOW because of throttled loading.
 crbug.com/73609 http/tests/media/video-play-stall.html [ Slow ]
@@ -173,20 +202,25 @@
 crbug.com/492664 external/wpt/css/css-writing-modes/text-orientation-script-001o.html [ Slow ]
 
 crbug.com/336481 http/tests/devtools/jump-to-previous-editing-location.js [ Slow ]
+crbug.com/336481 virtual/binary-for-devtools/http/tests/devtools/jump-to-previous-editing-location.js [ Slow ]
 crbug.com/346259 http/tests/websocket/no-crash-on-cookie-flood.html [ Slow ]
 
 crbug.com/522646 http/tests/media/encrypted-media/encrypted-media-encrypted-event-different-origin.html [ Slow ]
 crbug.com/411164 [ Win ] http/tests/security/powerfulFeatureRestrictions/serviceworker-on-insecure-origin.html [ Slow ]
 crbug.com/411164 [ Win ] virtual/outofblink-cors/http/tests/security/powerfulFeatureRestrictions/serviceworker-on-insecure-origin.html [ Slow ]
 crbug.com/510337 http/tests/devtools/console/console-format.js [ Slow ]
+crbug.com/510337 virtual/binary-for-devtools/http/tests/devtools/console/console-format.js [ Slow ]
 crbug.com/357427 http/tests/workers/terminate-during-sync-operation-file.html [ Slow ]
 crbug.com/357427 http/tests/workers/terminate-during-sync-operation-filesystem.html [ Slow ]
 crbug.com/402379 [ Debug ] storage/indexeddb/cursor-continue-validity.html [ Slow ]
 crbug.com/402379 [ Debug ] storage/indexeddb/mozilla/indexes.html [ Slow ]
 crbug.com/480769 http/tests/devtools/service-workers/service-workers-redundant.js [ Slow ]
+crbug.com/480769 virtual/binary-for-devtools/http/tests/devtools/service-workers/service-workers-redundant.js [ Slow ]
 crbug.com/480769 http/tests/devtools/service-workers/service-worker-agents.js [ Slow ]
+crbug.com/480769 virtual/binary-for-devtools/http/tests/devtools/service-workers/service-worker-agents.js [ Slow ]
 crbug.com/504703 inspector-protocol/debugger/debugger-step-into-dedicated-worker.js [ Slow ]
 crbug.com/548765 http/tests/devtools/console-fetch-logging.js [ Slow ]
+crbug.com/548765 virtual/binary-for-devtools/http/tests/devtools/console-fetch-logging.js [ Slow ]
 
 crbug.com/419993 [ Debug ] fast/css/giant-stylesheet-crash.html [ Slow ]
 
@@ -205,6 +239,7 @@
 
 
 crbug.com/528419 http/tests/devtools/elements/styles-2/pseudo-elements.js [ Slow ]
+crbug.com/528419 virtual/binary-for-devtools/http/tests/devtools/elements/styles-2/pseudo-elements.js [ Slow ]
 
 crbug.com/802029 fast/dom/shadow/focus-controller-recursion-crash.html [ Slow ]
 
@@ -254,7 +289,9 @@
 
 # These tests were previously marked Slow in ASANExpectations.
 crbug.com/451577 [ Linux ] http/tests/devtools/elements/user-properties.js [ Slow ]
+crbug.com/451577 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/elements/user-properties.js [ Slow ]
 crbug.com/451577 [ Linux ] http/tests/devtools/layers/layer-canvas-log.js [ Slow ]
+crbug.com/451577 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/layers/layer-canvas-log.js [ Slow ]
 
 # These imported tests exercise tens of thousands of code points and generate large results.
 crbug.com/736056 external/wpt/encoding/legacy-mb-japanese [ Slow ]
@@ -324,6 +361,7 @@
 crbug.com/800359 external/wpt/mimesniff/mime-types/parsing.any.worker.html [ Slow ]
 
 crbug.com/808185 [ Win Release ] http/tests/devtools/editor/text-editor-ctrl-d-1.js [ Slow ]
+crbug.com/808185 [ Win Release ] virtual/binary-for-devtools/http/tests/devtools/editor/text-editor-ctrl-d-1.js [ Slow ]
 
 # OffscreenCanvas non-virtual convert-to-blob tests
 # These two tests are running without idle-task support in non-virtual
@@ -462,8 +500,11 @@
 crbug.com/874695 external/wpt/xhr/xmlhttprequest-timeout-worker-synconworker.html [ Slow ]
 crbug.com/874695 external/wpt/xhr/xmlhttprequest-timeout-worker-twice.html [ Slow ]
 crbug.com/874695 http/tests/devtools/sources/debugger-breakpoints/breakpoints-ui-shifted-breakpoint.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/sources/debugger-breakpoints/breakpoints-ui-shifted-breakpoint.js [ Slow ]
 crbug.com/874695 http/tests/devtools/sources/sourcemap-hot-reload.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/sources/sourcemap-hot-reload.js [ Slow ]
 crbug.com/874695 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.js [ Slow ]
 crbug.com/874695 virtual/outofblink-cors/external/wpt/fetch/http-cache/cc-request.html [ Slow ]
 crbug.com/874695 virtual/outofblink-cors/external/wpt/service-workers/service-worker/fetch-frame-resource.https.html [ Slow ]
 crbug.com/874695 virtual/outofblink-cors/external/wpt/xhr/sync-no-timeout.any.html [ Slow ]
@@ -853,21 +894,37 @@
 crbug.com/874695 http/tests/credentialmanager/credentialscontainer-get-origins.html [ Slow ]
 crbug.com/874695 http/tests/credentialmanager/register-then-sign.html [ Slow ]
 crbug.com/874695 http/tests/devtools/audits2/audits2-limited-run.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/audits2/audits2-limited-run.js [ Slow ]
 crbug.com/874695 http/tests/devtools/audits2/audits2-successful-run.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/audits2/audits2-successful-run.js [ Slow ]
 crbug.com/874695 http/tests/devtools/console/console-correct-suggestions.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/console/console-correct-suggestions.js [ Slow ]
 crbug.com/874695 http/tests/devtools/editor/text-editor-formatter.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/editor/text-editor-formatter.js [ Slow ]
 crbug.com/874695 http/tests/devtools/inspect-iframe-from-different-domain.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/inspect-iframe-from-different-domain.js [ Slow ]
 crbug.com/874695 http/tests/devtools/oopif/oopif-cookies-refresh.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/oopif/oopif-cookies-refresh.js [ Slow ]
 crbug.com/874695 http/tests/devtools/persistence/persistence-mimetype-on-rename.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/persistence/persistence-mimetype-on-rename.js [ Slow ]
 crbug.com/874695 http/tests/devtools/service-workers/user-agent-override.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/service-workers/user-agent-override.js [ Slow ]
 crbug.com/874695 http/tests/devtools/sources/debugger-breakpoints/breakpoints-ui-in-multiple-workers.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/sources/debugger-breakpoints/breakpoints-ui-in-multiple-workers.js [ Slow ]
 crbug.com/874695 http/tests/devtools/sources/debugger-breakpoints/dom-breakpoints.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/sources/debugger-breakpoints/dom-breakpoints.js [ Slow ]
 crbug.com/874695 http/tests/devtools/sources/debugger/debugger-proto-property.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/sources/debugger/debugger-proto-property.js [ Slow ]
 crbug.com/874695 http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/sources/debugger-frameworks/frameworks-dom-xhr-event-breakpoints.js [ Slow ]
 crbug.com/874695 http/tests/devtools/sources/debugger/live-edit-no-reveal.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/sources/debugger/live-edit-no-reveal.js [ Slow ]
 crbug.com/874695 http/tests/devtools/tracing/decode-resize.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/tracing/decode-resize.js [ Slow ]
 crbug.com/874695 http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js [ Slow ]
 crbug.com/874695 http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.js [ Slow ]
 crbug.com/874695 external/wpt/event-timing/event-timing-bufferbeforeonload.html [ Slow ]
 crbug.com/874695 external/wpt/event-timing/event-timing-crossiframe.html [ Slow ]
 crbug.com/874695 external/wpt/event-timing/event-timing-observethenonload.html [ Slow ]
@@ -949,10 +1006,13 @@
 crbug.com/874695 http/tests/images/png-progressive-load.html [ Slow ]
 crbug.com/874695 http/tests/images/webp-progressive-load.html [ Slow ]
 crbug.com/874695 http/tests/inspector-protocol/request-mixed-content-status-blockable.js [ Slow ]
+crbug.com/874695 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/request-mixed-content-status-blockable.js [ Slow ]
 crbug.com/874695 virtual/not-site-per-process/http/tests/inspector-protocol/request-mixed-content-status-blockable.js [ Slow ]
 crbug.com/874695 http/tests/inspector-protocol/request-mixed-content-status-none.js [ Slow ]
+crbug.com/874695 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/request-mixed-content-status-none.js [ Slow ]
 crbug.com/874695 virtual/not-site-per-process/http/tests/inspector-protocol/request-mixed-content-status-none.js [ Slow ]
 crbug.com/874695 http/tests/inspector-protocol/request-mixed-content-status-optionally-blockable.js [ Slow ]
+crbug.com/874695 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/request-mixed-content-status-optionally-blockable.js [ Slow ]
 crbug.com/874695 virtual/not-site-per-process/http/tests/inspector-protocol/request-mixed-content-status-optionally-blockable.js [ Slow ]
 crbug.com/874695 http/tests/media/controls/toggle-class-with-state-source-buffer.html [ Slow ]
 crbug.com/874695 http/tests/media/preload-conditions.html [ Slow ]
@@ -1293,7 +1353,9 @@
 crbug.com/874695 virtual/streaming-preload/http/tests/fetch/workers/thorough/scheme-blob-base-https-other-https.html [ Slow ]
 crbug.com/874695 virtual/streaming-preload/http/tests/fetch/workers/thorough/scheme-data-base-https-other-https.html [ Slow ]
 crbug.com/874695 http/tests/devtools/sxg/sxg-cert-not-found.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/sxg/sxg-cert-not-found.js [ Slow ]
 crbug.com/874695 http/tests/devtools/sxg/sxg-disable-cache.js [ Slow ]
+crbug.com/874695 virtual/binary-for-devtools/http/tests/devtools/sxg/sxg-disable-cache.js [ Slow ]
 crbug.com/874695 virtual/threaded/animations/svg/animated-filter-svg-element.html [ Slow ]
 crbug.com/874695 virtual/disable-blink-gen-property-trees/animations/svg/animated-filter-svg-element.html [ Slow ]
 crbug.com/874695 virtual/threaded/external/wpt/css/css-scroll-snap/snap-at-user-scroll-end-manual.html [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 524cb999..b0054e6 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -165,10 +165,15 @@
 # Tests temporarily disabled with Site Isolation - uninvestigated bugs:
 # TODO(lukasza, alexmos): Burn down this list.
 crbug.com/608015 http/tests/inspector-protocol/access-inspected-object.js [ Failure Timeout ]
+crbug.com/608015 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/access-inspected-object.js [ Failure Timeout ]
 crbug.com/623268 http/tests/inspector-protocol/request-mixed-content-status-blockable.js [ Timeout ]
+crbug.com/623268 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/request-mixed-content-status-blockable.js [ Timeout ]
 crbug.com/623268 http/tests/inspector-protocol/request-mixed-content-status-none.js [ Timeout ]
+crbug.com/623268 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/request-mixed-content-status-none.js [ Timeout ]
 crbug.com/623268 http/tests/inspector-protocol/request-mixed-content-status-optionally-blockable.js [ Timeout ]
+crbug.com/623268 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/request-mixed-content-status-optionally-blockable.js [ Timeout ]
 crbug.com/678482 http/tests/devtools/debugger/fetch-breakpoints.js [ Timeout Pass ]
+crbug.com/678482 virtual/binary-for-devtools/http/tests/devtools/debugger/fetch-breakpoints.js [ Timeout Pass ]
 crbug.com/678491 http/tests/misc/webtiming-no-origin.html [ Crash Pass ]
 crbug.com/765779 http/tests/loading/bad-server-subframe.html [ Failure ]
 crbug.com/793127 external/wpt/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html [ Crash ]
@@ -185,7 +190,9 @@
 crbug.com/895001 http/tests/media/autoplay/webaudio-autoplay-iframe-with-gesture.html [ Timeout Pass ]
 crbug.com/895001 virtual/user-activation-v2/http/tests/media/autoplay/webaudio-autoplay-iframe-with-gesture.html [ Timeout Pass ]
 crbug.com/901502 http/tests/devtools/oopif/oopif-storage.js [ Pass Failure ]
+crbug.com/901502 virtual/binary-for-devtools/http/tests/devtools/oopif/oopif-storage.js [ Pass Failure ]
 crbug.com/906879 http/tests/inspector-protocol/network/navigation-blocking-xorigin-iframe.js [ Pass Failure ]
+crbug.com/906879 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/network/navigation-blocking-xorigin-iframe.js [ Pass Failure ]
 # ====== Site Isolation failures until here ======
 
 # ====== Oilpan-only failures from here ======
@@ -197,7 +204,9 @@
 # ====== Browserside navigation from here ======
 # These tests started failing when browser-side navigation was turned on.
 crbug.com/762529 http/tests/devtools/network/network-datareceived.js [ Failure ]
+crbug.com/762529 virtual/binary-for-devtools/http/tests/devtools/network/network-datareceived.js [ Failure ]
 crbug.com/759632 http/tests/devtools/network/network-datasaver-warning.js [ Failure ]
+crbug.com/759632 virtual/binary-for-devtools/http/tests/devtools/network/network-datasaver-warning.js [ Failure ]
 # ====== Browserside navigation until here ======
 
 crbug.com/915472 inspector-protocol/worker/worker-autoattach-order.js [ Failure Pass ]
@@ -273,6 +282,7 @@
 crbug.com/309675 compositing/gestures/gesture-tapHighlight-simple-longPress.html [ Failure ]
 
 crbug.com/845267 [ Mac ] http/tests/inspector-protocol/page/page-lifecycleEvents.js [ Failure Pass ]
+crbug.com/845267 [ Mac ] virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/page/page-lifecycleEvents.js [ Failure Pass ]
 
 # SwiftShader Failures
 crbug.com/726075 [ Win ] compositing/3d-cube.html [ Failure ]
@@ -359,6 +369,7 @@
 # These tests are no longer applicable in BlinkGenPropertyTree mode.
 # TODO(wangxianzhu): Remove them when we remove non-BlinkGenPropertyTree code.
 Bug(none) http/tests/devtools/layers/layer-sticky-position-constraint-get.js [ Skip ]
+Bug(none) virtual/binary-for-devtools/http/tests/devtools/layers/layer-sticky-position-constraint-get.js [ Skip ]
 Bug(none) inspector-protocol/layers/get-layers.js [ Skip ]
 
 # Before we fully launch BlinkGenPropertyTrees, run visual/disable-blink-gen-property-trees/ on Linux.
@@ -671,9 +682,6 @@
 crbug.com/711704 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-rule7-outside-right-001.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-bfc-006.xht [ Failure ]
 
-### virtual/layout_ng/external/wpt/css/CSS2/normal-flow
-crbug.com/704961 [ Mac ] virtual/layout_ng/external/wpt/css/CSS2/normal-flow/width-inherit-001.xht [ Failure ]
-
 # Inline: border in continuations. Fail in Blink.
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/block-in-inline-insert-001f.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/block-in-inline-insert-002f.xht [ Failure ]
@@ -692,7 +700,6 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/replaced-intrinsic-002.xht [ Failure ]
 
 ### virtual/layout_ng/external/wpt/css/CSS2/positioning
-crbug.com/704961 [ Mac ] virtual/layout_ng/external/wpt/css/CSS2/positioning/abspos-027.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/position-relative-035.xht [ Failure ]
 
 ### virtual/layout_ng/fast/block/basic
@@ -707,7 +714,6 @@
 crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/float/028.html [ Failure ]
 crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/float/float-in-float-hit-testing.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/clear-intruding-floats-when-moving-to-inline-parent-3.html [ Failure Crash Pass ]
-crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/float/floats-and-text-indent.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-in-float-painting.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-list-changed-before-layout-crash.html [ Crash Pass ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-not-removed-from-next-sibling4.html [ Crash Pass ]
@@ -717,16 +723,12 @@
 crbug.com/635619 virtual/layout_ng/fast/block/float/nopaint-after-layer-destruction2.html [ Failure ]
 crbug.com/810370 virtual/layout_ng/fast/block/float/overhanging-float-remove-from-fixed-position-block.html [ Failure ]
 crbug.com/810370 virtual/layout_ng/fast/block/float/overhanging-float-remove-from-fixed-position-block2.html [ Failure ]
-crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/float/overhanging-tall-block.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/rubybase-children-moved-crash.html [ Crash Pass ]
 crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/float/width-update-after-clear.html [ Failure ]
 
 ### virtual/layout_ng/fast/block/margin-collapse
 crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/margin-collapse/103.html [ Failure ]
 
-### virtual/layout_ng/fast/inline
-crbug.com/635619 [ Mac ] virtual/layout_ng/fast/inline/left-right-center-inline-alignment-in-ltr-and-rtl-blocks.html [ Failure ]
-
 ### virtual/layout_ng/overflow
 crbug.com/724701 virtual/layout_ng/overflow/overflow-basic-004.html [ Failure ]
 
@@ -748,9 +750,9 @@
 
 # Maybe a Mac-specific rebaselining issue.
 crbug.com/846557 [ Mac ] virtual/layout_ng_experimental/css3/flexbox/button.html [ Skip ]
-crbug.com/591099 [ Mac ] virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-vertical-align-effect.html [ Failure ]
 
 crbug.com/835810 [ Win7 ] http/tests/devtools/startup/dom-storage-open.js [ Pass Timeout ]
+crbug.com/835810 [ Win7 ] virtual/binary-for-devtools/http/tests/devtools/startup/dom-storage-open.js [ Pass Timeout ]
 
 ### Image/text failures
 #crbug.com/714962 virtual/layout_ng/fast/inline/001.html [ Failure ]
@@ -771,19 +773,8 @@
 crbug.com/714962 virtual/layout_ng/fast/inline/inline-borders-with-bidi-override.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/inline/outline-continuations.html [ Failure ]
 
-### virtual/layout_ng/external/wpt/css/CSS2/normal-flow/
-crbug.com/714962 [ Mac ] virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-valign-001.xht [ Failure ]
-crbug.com/714962 [ Mac ] virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-valign-002.xht [ Failure ]
-crbug.com/714962 [ Mac ] virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-table-002a.xht [ Failure ]
-crbug.com/714962 [ Mac ] virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-table-002b.xht [ Failure ]
-crbug.com/714962 [ Mac ] virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-table-valign-001.xht [ Failure ]
-
 ### virtual/layout_ng/fast/block/float/
 crbug.com/714962 [ Mac ] virtual/layout_ng/fast/block/float/002.html [ Failure ]
-crbug.com/714962 [ Mac ] virtual/layout_ng/fast/block/float/017.html [ Failure ]
-crbug.com/714962 [ Mac ] virtual/layout_ng/fast/block/float/float-should-dirty-line-even-when-it-doesnt-intersect-it-3.html [ Failure ]
-crbug.com/714962 [ Mac ] virtual/layout_ng/fast/block/float/max-width-clear-float-with-overflow-hidden.html [ Failure ]
-crbug.com/714962 [ Mac ] virtual/layout_ng/fast/block/float/trailing-float-with-content.html [ Failure ]
 
 ### virtual/layout_ng/fast/writing-mode/
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/auto-sizing-orthogonal-flows.html [ Failure ]
@@ -801,8 +792,6 @@
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/japanese-lr-selection.html [ Failure ]
 crbug.com/714962 [ Mac ] virtual/layout_ng/fast/writing-mode/japanese-lr-text.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/japanese-rl-selection.html [ Failure ]
-crbug.com/714962 [ Mac ] virtual/layout_ng/fast/writing-mode/margins.html [ Failure ]
-crbug.com/714962 [ Mac ] virtual/layout_ng/fast/writing-mode/orthogonal-inline-block.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/percentage-height-orthogonal-writing-modes.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/vertical-align-table-baseline.html [ Failure ]
 crbug.com/714962 virtual/layout_ng/fast/writing-mode/vertical-baseline-alignment.html [ Failure ]
@@ -812,7 +801,6 @@
 crbug.com/714962 [ Mac ] virtual/layout_ng/fast/writing-mode/border-vertical-lr.html [ Failure ]
 crbug.com/714962 [ Mac ] virtual/layout_ng/fast/writing-mode/english-lr-text.html [ Failure ]
 crbug.com/714962 [ Win ] virtual/layout_ng/fast/writing-mode/english-lr-text.html [ Failure ]
-crbug.com/714962 [ Mac ] virtual/layout_ng/fast/writing-mode/japanese-rl-text.html [ Failure ]
 crbug.com/714962 [ Mac ] virtual/layout_ng/fast/writing-mode/text-orientation-basic.html [ Failure ]
 
 # Crashes/asserts due to inline item reuse.
@@ -1838,12 +1826,17 @@
 
 ### sheriff 2018-05-28
 crbug.com/840238 http/tests/devtools/elements/shadow/shadow-distribution.js [ Failure ]
+crbug.com/840238 virtual/binary-for-devtools/http/tests/devtools/elements/shadow/shadow-distribution.js [ Failure ]
 
 crbug.com/667560 [ Debug ] http/tests/devtools/elements/styles-3/styles-change-node-while-editing.js [ Pass Failure ]
+crbug.com/667560 [ Debug ] virtual/binary-for-devtools/http/tests/devtools/elements/styles-3/styles-change-node-while-editing.js [ Pass Failure ]
 crbug.com/778515 http/tests/devtools/elements/styles-3/styles-add-new-rule.js [ Pass Failure ]
+crbug.com/778515 virtual/binary-for-devtools/http/tests/devtools/elements/styles-3/styles-add-new-rule.js [ Pass Failure ]
 
 crbug.com/778391 http/tests/devtools/elements/styles-3/styles-add-new-rule-tab.js [ Pass Failure ]
+crbug.com/778391 virtual/binary-for-devtools/http/tests/devtools/elements/styles-3/styles-add-new-rule-tab.js [ Pass Failure ]
 crbug.com/778391 http/tests/devtools/elements/styles-3/styles-disable-inherited.js [ Pass Failure ]
+crbug.com/778391 virtual/binary-for-devtools/http/tests/devtools/elements/styles-3/styles-disable-inherited.js [ Pass Failure ]
 
 crbug.com/767269 [ Win ] inspector-protocol/layout-fonts/cjk-ideograph-fallback-by-lang.js [ Pass Failure ]
 
@@ -1919,8 +1912,6 @@
 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 ]
 crbug.com/492664 [ Mac ] external/wpt/css/css-writing-modes/bidi-isolate-002.html [ Failure ]
-crbug.com/492664 [ Win ] external/wpt/css/css-writing-modes/bidi-override-005.html [ Failure ]
-crbug.com/492664 [ Win ] external/wpt/css/css-writing-modes/bidi-plaintext-001.html [ Failure ]
 
 crbug.com/280342 [ Mac ] http/tests/media/progress-events-generated-correctly.html [ Failure Pass ]
 crbug.com/280342 [ Linux ] http/tests/media/progress-events-generated-correctly.html [ Failure Pass ]
@@ -1982,6 +1973,7 @@
 crbug.com/761798 [ Mac ] inspector-protocol/emulation/device-emulation-desktop.js [ Failure ]
 
 crbug.com/771233 [ Win10 ] http/tests/devtools/audits2/ [ Skip ]
+crbug.com/771233 [ Win10 ] virtual/binary-for-devtools/http/tests/devtools/audits2/ [ Skip ]
 
 crbug.com/923269 virtual/gpu/fast/canvas/OffscreenCanvas-copyImage.html [ Failure ]
 crbug.com/923269 fast/canvas/OffscreenCanvas-copyImage.html [ Failure ]
@@ -2064,11 +2056,15 @@
 crbug.com/597221 virtual/user-activation-v2/fast/dom/Window/window-postmessage-clone-deep-array.html [ Failure ]
 
 crbug.com/498539 http/tests/devtools/tracing/timeline-misc/timeline-bound-function.js [ Pass Failure ]
+crbug.com/498539 virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-misc/timeline-bound-function.js [ Pass Failure ]
 crbug.com/498539 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-bound-function.js [ Pass Failure ]
 
 crbug.com/498539 crbug.com/794869 crbug.com/798548 [ Win7 ] http/tests/devtools/elements/styles-4/styles-update-from-js.js [ Crash Pass Failure ]
+crbug.com/498539 crbug.com/794869 crbug.com/798548 [ Win7 ] virtual/binary-for-devtools/http/tests/devtools/elements/styles-4/styles-update-from-js.js [ Crash Pass Failure ]
 crbug.com/498539 crbug.com/794869 crbug.com/798548 [ Mac ] http/tests/devtools/elements/styles-4/styles-update-from-js.js [ Crash Pass Failure ]
+crbug.com/498539 crbug.com/794869 crbug.com/798548 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/elements/styles-4/styles-update-from-js.js [ Crash Pass Failure ]
 crbug.com/498539 crbug.com/794869 crbug.com/798548 [ Linux ] http/tests/devtools/elements/styles-4/styles-update-from-js.js [ Crash Pass Failure ]
+crbug.com/498539 crbug.com/794869 crbug.com/798548 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/elements/styles-4/styles-update-from-js.js [ Crash Pass Failure ]
 
 crbug.com/889952 fast/selectors/selection-window-inactive.html [ Pass Failure ]
 
@@ -2084,7 +2080,6 @@
 # Text::inDocument() returns false but should not.
 crbug.com/264138 dom/legacy_dom_conformance/xhtml/level3/core/nodecomparedocumentposition38.xhtml [ Failure ]
 
-crbug.com/410145 [ Win ] fast/table/column-in-inline.html [ Failure ]
 crbug.com/411164 [ Win ] http/tests/security/powerfulFeatureRestrictions/serviceworker-on-insecure-origin.html [ Pass ]
 crbug.com/411164 [ Win ] virtual/outofblink-cors/http/tests/security/powerfulFeatureRestrictions/serviceworker-on-insecure-origin.html [ Pass ]
 
@@ -2160,7 +2155,6 @@
 crbug.com/626703 external/wpt/css/css-text/line-breaking/line-breaking-ic-002.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/line-breaking/line-breaking-ic-003.html [ Failure ]
 crbug.com/626703 [ Win10 ] external/wpt/css/css-text/text-align/text-align-justify-004.html [ Failure ]
-crbug.com/626703 [ Win7 ] external/wpt/css/css-text/text-justify/text-justify-001.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/text-transform/text-transform-capitalize-026.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/text-transform/text-transform-capitalize-028.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/text-transform/text-transform-tailoring-001.html [ Failure ]
@@ -2325,8 +2319,6 @@
 crbug.com/492664 [ Mac ] external/wpt/css/css-writing-modes/sizing-orthog-htb-in-vrl-008.xht [ Failure ]
 crbug.com/492664 [ Mac ] external/wpt/css/css-writing-modes/sizing-orthog-htb-in-vrl-020.xht [ Failure ]
 
-crbug.com/498845 [ Win ] fast/multicol/vertical-rl/float-content-break.html [ Failure ]
-
 crbug.com/381684 [ Mac ] fonts/family-fallback-gardiner.html [ Skip ]
 crbug.com/381684 [ Win ] fonts/family-fallback-gardiner.html [ Skip ]
 crbug.com/467635 fast/dom/HTMLImageElement/image-sizes-meta-viewport.html [ Skip ]
@@ -2390,7 +2382,9 @@
 # These contain faulty expectations. https://chromium-review.googlesource.com/c/v8/v8/+/1350790 should fix the
 # faulty return values but to allow landing that patch, the tests have to be deactivated in the meanwhile.
 crbug.com/924308 http/tests/devtools/console/console-dir-es6.js [ Pass Failure ]
+crbug.com/924308 virtual/binary-for-devtools/http/tests/devtools/console/console-dir-es6.js [ Pass Failure ]
 crbug.com/924308 http/tests/devtools/console/console-format-es6-2.js [ Pass Failure ]
+crbug.com/924308 virtual/binary-for-devtools/http/tests/devtools/console/console-format-es6-2.js [ Pass Failure ]
 
 # We only want to run one of the web-animations-api tests in stable mode.
 crbug.com/441553 virtual/stable/web-animations-api [ Skip ]
@@ -2434,6 +2428,7 @@
 crbug.com/901906 virtual/threaded/fast/scroll-behavior/smooth-scroll/track-scroll.html [ Pass Failure ]
 
 crbug.com/599670 [ Win ] http/tests/devtools/resource-parameters-ipv6.js [ Pass Failure Crash ]
+crbug.com/599670 [ Win ] virtual/binary-for-devtools/http/tests/devtools/resource-parameters-ipv6.js [ Pass Failure Crash ]
 crbug.com/472330 fast/borders/border-image-outset-split-inline-vertical-lr.html [ Failure ]
 crbug.com/472330 fast/writing-mode/box-shadow-vertical-lr.html [ Failure ]
 crbug.com/472330 fast/writing-mode/box-shadow-vertical-rl.html [ Failure ]
@@ -2561,8 +2556,11 @@
 crbug.com/906847 inspector-protocol/runtime/runtime-getProperties.js [ Skip ]
 crbug.com/906847 inspector-protocol/debugger/debugger-scope-skip-variables-with-empty-name.js [ Skip ]
 crbug.com/v8/8672 http/tests/devtools/bindings/suspendtarget-bindings.js [ Skip ]
+crbug.com/v8/8672 virtual/binary-for-devtools/http/tests/devtools/bindings/suspendtarget-bindings.js [ Skip ]
 crbug.com/v8/8672 http/tests/devtools/bindings/suspendtarget-navigator.js [ Skip ]
+crbug.com/v8/8672 virtual/binary-for-devtools/http/tests/devtools/bindings/suspendtarget-navigator.js [ Skip ]
 crbug.com/v8/8672 http/tests/devtools/tracing/decode-resize.js [ Skip ]
+crbug.com/v8/8672 virtual/binary-for-devtools/http/tests/devtools/tracing/decode-resize.js [ Skip ]
 
 # These testcases are incorrect, mark them as failing until they're fixed in the testsuite.
 # https://lists.w3.org/Archives/Public/www-style/2016Jan/0275.html
@@ -2584,9 +2582,7 @@
 crbug.com/467127 external/wpt/css/css-flexbox/getcomputedstyle/flexbox_computedstyle_flex-basis-0percent.html [ Failure ]
 crbug.com/467127 external/wpt/css/css-flexbox/getcomputedstyle/flexbox_computedstyle_flex-shorthand-number.html [ Failure ]
 crbug.com/467127 [ Mac ] external/wpt/css/css-flexbox/ttwf-reftest-flex-wrap-reverse.html [ Failure ]
-crbug.com/467127 [ Win ] external/wpt/css/css-flexbox/ttwf-reftest-flex-wrap-reverse.html [ Failure ]
 crbug.com/467127 [ Mac ] external/wpt/css/css-flexbox/ttwf-reftest-flex-wrap.html [ Failure ]
-crbug.com/467127 [ Win ] external/wpt/css/css-flexbox/ttwf-reftest-flex-wrap.html [ Failure ]
 
 crbug.com/467127 external/wpt/css/css-flexbox/negative-margins-001.html [ Failure ]
 crbug.com/467127 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-content-horiz-001a.xhtml [ Failure ]
@@ -2670,6 +2666,7 @@
 crbug.com/483653 accessibility/scroll-containers.html [ Skip ]
 
 crbug.com/491764 http/tests/devtools/service-workers/user-agent-override.js [ Pass Timeout ]
+crbug.com/491764 virtual/binary-for-devtools/http/tests/devtools/service-workers/user-agent-override.js [ Pass Timeout ]
 
 # Fails with leak detector.
 crbug.com/769885 [ Linux ] virtual/android/fullscreen/full-screen-frameset.html [ Skip ]
@@ -2685,9 +2682,6 @@
 crbug.com/321237 [ Mac ] fast/selectors/007a.html [ Failure ]
 crbug.com/321237 [ Mac ] fast/text-autosizing/inherited-multiplier.html [ Failure ]
 crbug.com/321237 [ Win ] fast/text-autosizing/inherited-multiplier.html [ Failure ]
-crbug.com/321237 [ Mac ] virtual/stable/fast/css3-text/css3-text-decoration/stable/first-letter-text-decoration.html [ Failure ]
-crbug.com/321237 [ Win ] fast/multicol/span/pseudo-before-after-in-content.html [ Failure ]
-crbug.com/321237 [ Win ] fast/selectors/004.html [ Failure ]
 
 crbug.com/501659 fast/xsl/xslt-missing-namespace-in-xslt.xml [ Failure ]
 
@@ -2757,6 +2751,7 @@
 crbug.com/543369 [ Linux ] fast/forms/select-popup/popup-menu-appearance-tall.html [ Failure Pass ]
 
 crbug.com/548765 http/tests/devtools/console-fetch-logging.js [ Failure Pass ]
+crbug.com/548765 virtual/binary-for-devtools/http/tests/devtools/console-fetch-logging.js [ Failure Pass ]
 
 ### See crbug.com/891427 comment near the top of this file:
 ###crbug.com/564109 [ Win ]  http/tests/webfont/font-display-intervention.html [ Pass Failure Timeout ]
@@ -2916,11 +2911,14 @@
 # Untriaged failures after https://crrev.com/c/543695/.
 # These need to be updated but appear not to be related to that change.
 crbug.com/626703 http/tests/devtools/indexeddb/database-refresh-view.js [ Pass Failure ]
+crbug.com/626703 virtual/binary-for-devtools/http/tests/devtools/indexeddb/database-refresh-view.js [ Pass Failure ]
 crbug.com/626703 http/tests/devtools/extensions/extensions-sidebar.js [ Pass Failure ]
+crbug.com/626703 virtual/binary-for-devtools/http/tests/devtools/extensions/extensions-sidebar.js [ Pass Failure ]
 crbug.com/751952 fast/text/international/complex-text-rectangle.html [ Timeout Pass ]
 crbug.com/751952 [ Mac ] editing/selection/modify_extend/extend_by_character.html [ Failure Pass ]
 crbug.com/751952 [ Win ] editing/selection/modify_extend/extend_by_character.html [ Failure Pass ]
 crbug.com/751952 http/tests/devtools/console/console-uncaught-promise.js [ Pass Failure ]
+crbug.com/751952 virtual/binary-for-devtools/http/tests/devtools/console/console-uncaught-promise.js [ Pass Failure ]
 
 crbug.com/800898 external/wpt/FileAPI/url/url-with-fetch.any.worker.html [ Pass Failure ]
 crbug.com/800898 external/wpt/FileAPI/url/url-with-xhr.any.worker.html [ Pass Failure ]
@@ -3041,6 +3039,12 @@
 crbug.com/939181 virtual/not-site-per-process/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html [ Failure Timeout ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-002.html [ Failure ]
+crbug.com/626703 virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-getStats.https.html [ Timeout ]
+crbug.com/626703 external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-003.html [ Failure ]
+crbug.com/626703 [ Mac10.13 ] virtual/streaming-preload/external/wpt/html/semantics/scripting-1/the-script-element/async_005.htm [ Timeout ]
+crbug.com/626703 external/wpt/webrtc/RTCPeerConnection-getStats.https.html [ Timeout ]
 crbug.com/626703 external/wpt/css/css-text/shaping/shaping-021.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/shaping/shaping-001.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/shaping/shaping_cchar-000.html [ Failure ]
@@ -3164,7 +3168,6 @@
 crbug.com/626703 external/wpt/css/css-values/ic-unit-008.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-values/ic-unit-012.html [ Failure ]
 crbug.com/626703 external/wpt/html/semantics/document-metadata/the-link-element/stylesheet-not-removed-until-next-stylesheet-loads.html [ Timeout ]
-crbug.com/626703 external/wpt/infrastructure/reftest/size.html [ Failure ]
 crbug.com/626703 external/wpt/svg/interact/manual/event-attribute-001-manual.svg [ Skip ]
 crbug.com/626703 [ Retina ] virtual/streaming-preload/external/wpt/html/semantics/scripting-1/the-script-element/async_005.htm [ Timeout ]
 crbug.com/626703 external/wpt/css/css-text/tab-size/tab-size-spacing-001.html [ Failure ]
@@ -3580,7 +3583,6 @@
 crbug.com/626703 external/wpt/css/css-scoping/shadow-directionality-002.tentative.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-scoping/shadow-directionality-001.tentative.html [ Failure ]
 crbug.com/626703 external/wpt/screen-orientation/orientation-reading.html [ Timeout ]
-crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/float-retry-push-image.html [ Failure ]
 crbug.com/626703 external/wpt/html/browsers/the-window-object/window-open-noopener.html?_parent [ Timeout ]
 crbug.com/626703 external/wpt/html/browsers/the-window-object/window-open-noopener.html?_top [ Timeout ]
 crbug.com/626703 external/wpt/html/browsers/the-window-object/window-open-noopener.html?_self [ Failure ]
@@ -4297,7 +4299,6 @@
 crbug.com/707359 [ Mac ] fast/css-grid-layout/grid-self-baseline-04.html [ Failure ]
 crbug.com/707359 [ Mac ] fast/css-grid-layout/grid-self-baseline-horiz-04.html [ Failure ]
 crbug.com/926253 [ Linux Debug ] fast/css-grid-layout/grid-self-baseline-04.html [ Failure ]
-crbug.com/926253 fast/css-intrinsic-dimensions/height-css-tables-collapsed.html [ Failure ]
 crbug.com/926253 [ Linux Debug ] fast/css-intrinsic-dimensions/height-css-tables.html [ Failure ]
 ### Flakes found on all platforms. See crbug.com/936095
 ### crbug.com/926253 [ Linux Debug ] fast/css-intrinsic-dimensions/height-tables-collapsed.html [ Failure ]
@@ -4331,6 +4332,7 @@
 crbug.com/657646 [ Win ] fast/text/font-features/caps-native-synthesis.html [ Failure Pass ]
 
 crbug.com/664450 http/tests/devtools/console/console-on-animation-worklet.js [ Skip ]
+crbug.com/664450 virtual/binary-for-devtools/http/tests/devtools/console/console-on-animation-worklet.js [ Skip ]
 
 crbug.com/826419 external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-remove-track-inband.html [ Skip ]
 
@@ -4409,6 +4411,7 @@
 crbug.com/688670 external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-rendering-after-controls-removed.html [ Pass Failure ]
 
 crbug.com/849670 http/tests/devtools/service-workers/service-worker-v8-cache.js [ Pass Timeout ]
+crbug.com/849670 virtual/binary-for-devtools/http/tests/devtools/service-workers/service-worker-v8-cache.js [ Pass Timeout ]
 
 crbug.com/664858 virtual/threaded/fast/scroll-behavior/overflow-scroll-animates.html [ Skip ]
 crbug.com/664858 virtual/threaded/fast/scroll-behavior/smooth-scroll/horizontal-smooth-scroll-in-rtl.html [ Skip ]
@@ -4450,6 +4453,7 @@
 # ====== Tests from enabling .any.js/.worker.js tests end here ========
 
 crbug.com/789139 http/tests/devtools/sources/debugger/live-edit-no-reveal.js [ Failure Pass Timeout Crash ]
+crbug.com/789139 virtual/binary-for-devtools/http/tests/devtools/sources/debugger/live-edit-no-reveal.js [ Failure Pass Timeout Crash ]
 
 # ====== Begin of display: contents tests ======
 
@@ -4476,6 +4480,7 @@
 crbug.com/678499 virtual/feature-policy-for-sandbox/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-preload-allowed.php [ Failure Pass ]
 
 crbug.com/747751 [ Win ] http/tests/devtools/application-panel/resources-panel-resource-preview.js [ Failure Pass ]
+crbug.com/747751 [ Win ] virtual/binary-for-devtools/http/tests/devtools/application-panel/resources-panel-resource-preview.js [ Failure Pass ]
 
 crbug.com/689781 external/wpt/media-source/mediasource-duration.html [ Failure Pass ]
 crbug.com/689781 [ Win Mac ] http/tests/media/media-source/mediasource-duration.html [ Failure Pass ]
@@ -4490,9 +4495,13 @@
 
 # Arrow function name inferring
 crbug.com/916975 http/tests/devtools/console/console-repeat-count.js [ Pass Failure ]
+crbug.com/916975 virtual/binary-for-devtools/http/tests/devtools/console/console-repeat-count.js [ Pass Failure ]
 crbug.com/916975 http/tests/devtools/service-workers/lazy-addeventlisteners.js [ Pass Failure ]
+crbug.com/916975 virtual/binary-for-devtools/http/tests/devtools/service-workers/lazy-addeventlisteners.js [ Pass Failure ]
 crbug.com/916975 http/tests/devtools/sources/debugger-ui/call-stack-show-more.js [ Pass Failure ]
+crbug.com/916975 virtual/binary-for-devtools/http/tests/devtools/sources/debugger-ui/call-stack-show-more.js [ Pass Failure ]
 crbug.com/916975 http/tests/devtools/tracing/timeline-misc/timeline-event-causes.js [ Pass Failure ]
+crbug.com/916975 virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.js [ Pass Failure ]
 crbug.com/916975 inspector-protocol/css/media-query-listener-exception.js [ Pass Failure ]
 crbug.com/916975 virtual/threaded/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.js [ Pass Failure ]
 
@@ -4546,6 +4555,7 @@
 
 # Sheriff failures 2017-03-21
 crbug.com/703518 http/tests/devtools/tracing/worker-js-frames.js [ Failure Pass ]
+crbug.com/703518 virtual/binary-for-devtools/http/tests/devtools/tracing/worker-js-frames.js [ Failure Pass ]
 crbug.com/703518 virtual/threaded/http/tests/devtools/tracing/worker-js-frames.js [ Failure Pass ]
 crbug.com/674720 http/tests/loading/preload-img-test.html [ Pass Failure ]
 
@@ -4730,9 +4740,13 @@
 crbug.com/757165 [ Win ] fast/spatial-navigation/snav-unit-overflow-and-scroll-in-direction.html [ Pass Failure Timeout Crash ]
 crbug.com/757165 [ Win ] fast/spatial-navigation/snav-z-index.html [ Pass Failure Timeout Crash ]
 crbug.com/757165 [ Win ] http/tests/devtools/console/console-filter-test.js [ Skip ]
+crbug.com/757165 [ Win ] virtual/binary-for-devtools/http/tests/devtools/console/console-filter-test.js [ Skip ]
 crbug.com/757165 [ Win ] http/tests/devtools/console/console-links-in-errors-with-trace.js [ Skip ]
+crbug.com/757165 [ Win ] virtual/binary-for-devtools/http/tests/devtools/console/console-links-in-errors-with-trace.js [ Skip ]
 crbug.com/757165 [ Win ] http/tests/devtools/extensions/extensions-panel.js [ Skip ]
+crbug.com/757165 [ Win ] virtual/binary-for-devtools/http/tests/devtools/extensions/extensions-panel.js [ Skip ]
 crbug.com/757165 [ Win ] http/tests/devtools/sources/ui-source-code-metadata.js [ Skip ]
+crbug.com/757165 [ Win ] virtual/binary-for-devtools/http/tests/devtools/sources/ui-source-code-metadata.js [ Skip ]
 crbug.com/757165 [ Win ] http/tests/misc/client-hints-accept-meta-preloader.html [ Skip ]
 crbug.com/757165 [ Win ] inspector-protocol/debugger/debugger-evaluate-in-worker-while-pause-in-page.js [ Skip ]
 crbug.com/757165 [ Win ] paint/invalidation/filters/filter-repaint-accelerated-child-with-filter-child.html [ Skip ]
@@ -4785,18 +4799,24 @@
 
 # Tests occasionaly timing out (flaky) on WebKit Win7 dbg builder
 crbug.com/757955 [ Win7 Debug ] http/tests/devtools/sources/debugger-pause/pause-on-elements-panel.js [ Pass Timeout ]
+crbug.com/757955 [ Win7 Debug ] virtual/binary-for-devtools/http/tests/devtools/sources/debugger-pause/pause-on-elements-panel.js [ Pass Timeout ]
 crbug.com/757955 [ Win7 Debug ] storage/indexeddb/mozilla/cursors.html [ Pass Timeout ]
 crbug.com/757955 [ Win7 Debug ] storage/indexeddb/objectstore-cursor.html [ Pass Timeout ]
 crbug.com/757955 http/tests/devtools/tracing/timeline-paint/layer-tree.js [ Pass Failure Timeout ]
+crbug.com/757955 virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-paint/layer-tree.js [ Pass Failure Timeout ]
 
 # This test has a fixed number of time which can depend on performance.
 
 crbug.com/669329 http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.js [ Pass Failure Crash ]
+crbug.com/669329 virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.js [ Pass Failure Crash ]
 crbug.com/669329 virtual/threaded/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.js [ Pass Failure Crash ]
 
 crbug.com/799619 [ Debug ] http/tests/devtools/profiler/heap-snapshot-inspect-dom-wrapper.js [ Pass Timeout ]
+crbug.com/799619 [ Debug ] virtual/binary-for-devtools/http/tests/devtools/profiler/heap-snapshot-inspect-dom-wrapper.js [ Pass Timeout ]
 crbug.com/939037 [ Win7 ] http/tests/devtools/profiler/heap-snapshot-location.js [ Pass Timeout ]
+crbug.com/939037 [ Win7 ] virtual/binary-for-devtools/http/tests/devtools/profiler/heap-snapshot-location.js [ Pass Timeout ]
 crbug.com/939037 [ Mac Linux ] http/tests/devtools/profiler/heap-snapshot-location.js [ Pass Timeout ]
+crbug.com/939037 [ Mac Linux ] virtual/binary-for-devtools/http/tests/devtools/profiler/heap-snapshot-location.js [ Pass Timeout ]
 
 crbug.com/769347 [ Mac ] fast/dom/inert/inert-node-is-uneditable.html [ Failure ]
 
@@ -4876,8 +4896,10 @@
 # Sheriff failures 2017-10-23
 crbug.com/772411 http/tests/media/autoplay-crossorigin.html [ Timeout Failure Pass ]
 crbug.com/777222 http/tests/devtools/inspect-iframe-from-different-domain.js [ Pass Failure Timeout ]
+crbug.com/777222 virtual/binary-for-devtools/http/tests/devtools/inspect-iframe-from-different-domain.js [ Pass Failure Timeout ]
 
 crbug.com/778745 http/tests/inspector-protocol/cachestorage/read-cached-response.js [ Pass Failure ]
+crbug.com/778745 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/cachestorage/read-cached-response.js [ Pass Failure ]
 
 # Sheriff failures 2017-10-24
 crbug.com/773122 crbug.com/777813 [ Win ] fast/text/font-ascent-mac.html [ Failure Pass ]
@@ -4906,12 +4928,15 @@
 
 # Sheriff failures 2017-11-15
 crbug.com/785179 [ Win7 Debug ] http/tests/devtools/console/console-viewport-stick-to-bottom.js [ Skip ]
+crbug.com/785179 [ Win7 Debug ] virtual/binary-for-devtools/http/tests/devtools/console/console-viewport-stick-to-bottom.js [ Skip ]
 
 # Sheriff failures 2017-11-16
 crbug.com/785980 [ Win ] http/tests/devtools/network/network-xhr-same-url-as-main-resource.js [ Failure Pass ]
+crbug.com/785980 [ Win ] virtual/binary-for-devtools/http/tests/devtools/network/network-xhr-same-url-as-main-resource.js [ Failure Pass ]
 
 # Sheriff failures 2017-11-28
 crbug.com/785179 [ Mac10.11 Debug ] http/tests/devtools/console/console-viewport-stick-to-bottom.js [ Pass Failure ]
+crbug.com/785179 [ Mac10.11 Debug ] virtual/binary-for-devtools/http/tests/devtools/console/console-viewport-stick-to-bottom.js [ Pass Failure ]
 
 # Sheriff failures 2017-11-29
 crbug.com/789567 scrollbars/custom-scrollbar-inactive-pseudo.html [ Failure Pass ]
@@ -4926,6 +4951,7 @@
 
 # Sheriff failures 2017-12-04
 crbug.com/667560 http/tests/devtools/elements/styles-4/inline-style-sourcemap.js [ Pass Failure ]
+crbug.com/667560 virtual/binary-for-devtools/http/tests/devtools/elements/styles-4/inline-style-sourcemap.js [ Pass Failure ]
 
 # Double tap on modern media controls is a bit more complicated on Mac but
 # since we are not targeting Mac yet we can come back and fix this later.
@@ -4970,7 +4996,9 @@
 
 # Sheriff failures 2018-01-02
 crbug.com/798592 [ Win7 ] http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles.js [ Pass Failure ]
+crbug.com/798592 [ Win7 ] virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles.js [ Pass Failure ]
 crbug.com/798592 [ Mac ] http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles.js [ Pass Failure ]
+crbug.com/798592 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles.js [ Pass Failure ]
 crbug.com/798592 [ Win7 ] virtual/threaded/http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles.js [ Pass Failure ]
 crbug.com/798592 [ Mac ] virtual/threaded/http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles.js [ Pass Failure ]
 
@@ -5040,9 +5068,12 @@
 crbug.com/813704 http/tests/images/png-partial-load-as-document.html [ Failure Pass ]
 
 crbug.com/806645 [ Win7 ] http/tests/devtools/elements/elements-panel-rewrite-href.js [ Failure Pass ]
+crbug.com/806645 [ Win7 ] virtual/binary-for-devtools/http/tests/devtools/elements/elements-panel-rewrite-href.js [ Failure Pass ]
 crbug.com/806645 [ Mac ] http/tests/devtools/elements/elements-panel-rewrite-href.js [ Failure Pass ]
+crbug.com/806645 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/elements/elements-panel-rewrite-href.js [ Failure Pass ]
 
 crbug.com/813216 [ Win7 ] http/tests/devtools/elements/styles-3/style-rule-from-imported-stylesheet.js  [ Failure Pass ]
+crbug.com/813216 [ Win7 ] virtual/binary-for-devtools/http/tests/devtools/elements/styles-3/style-rule-from-imported-stylesheet.js  [ Failure Pass ]
 
 # MHT works only when loaded from local FS (file://..).
 crbug.com/778467 [ Fuchsia ] mhtml/mhtml_in_iframe.html [ Failure ]
@@ -5056,9 +5087,11 @@
 ### See crbug.com/891427 comment near the top of this file:
 ###crbug.com/816914 [ Mac ] fast/canvas/canvas-drawImage-live-video.html [ Failure Pass ]
 crbug.com/817167 http/tests/devtools/oopif/oopif-cookies-refresh.js [ Failure Timeout Pass ]
+crbug.com/817167 virtual/binary-for-devtools/http/tests/devtools/oopif/oopif-cookies-refresh.js [ Failure Timeout Pass ]
 
 # Sheriff 2018-03-02
 crbug.com/818076 http/tests/devtools/oopif/oopif-elements-navigate-in.js [ Failure Pass ]
+crbug.com/818076 virtual/binary-for-devtools/http/tests/devtools/oopif/oopif-elements-navigate-in.js [ Failure Pass ]
 crbug.com/818154 [ Linux Debug ] virtual/gpu-rasterization/images/gif-loop-count.html [ Failure Pass ]
 
 # Sheriff 2018-03-05
@@ -5066,7 +5099,9 @@
 
 # Prefetching Signed Exchange DevTools tests are flaky.
 crbug.com/851363 http/tests/devtools/sxg/sxg-prefetch-fail.js [ Pass Failure ]
+crbug.com/851363 virtual/binary-for-devtools/http/tests/devtools/sxg/sxg-prefetch-fail.js [ Pass Failure ]
 crbug.com/851363 http/tests/devtools/sxg/sxg-prefetch.js [ Pass Failure ]
+crbug.com/851363 virtual/binary-for-devtools/http/tests/devtools/sxg/sxg-prefetch.js [ Pass Failure ]
 
 # Sheriff 2018-03-22
 crbug.com/824775 [ Win ] media/controls/video-controls-with-cast-rendering.html [ Pass Failure ]
@@ -5131,6 +5166,7 @@
 crbug.com/831796 fast/events/autoscroll-in-textfield.html [ Failure Pass ]
 crbug.com/831685 [ Linux ] external/wpt/2dcontext/compositing/2d.composite.canvas.lighter.html [ Pass Timeout ]
 crbug.com/831673 http/tests/devtools/reveal-objects.js [ Pass Timeout ]
+crbug.com/831673 virtual/binary-for-devtools/http/tests/devtools/reveal-objects.js [ Pass Timeout ]
 crbug.com/831496 virtual/gpu/fast/canvas/fillrect_gradient.html [ Pass Timeout ]
 crbug.com/831482 [ Linux ] virtual/gpu-rasterization/images/cross-fade-background-size.html [ Pass Timeout ]
 crbug.com/831249 [ Linux ] virtual/gpu/fast/canvas/canvas-filter-svg-inline.html [ Pass Timeout ]
@@ -5166,27 +5202,35 @@
 
 # Sheriff 2018-05-22
 crbug.com/845610 [ Win ] http/tests/inspector-protocol/target/target-browser-context.js [ Pass Failure ]
+crbug.com/845610 [ Win ] virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/target/target-browser-context.js [ Pass Failure ]
 
 # Sheriff 2018-05-25
 crbug.com/846547 fast/webgl/webgl-composite-modes.html [ Pass Failure ]
 crbug.com/846471 http/tests/devtools/coverage/reveal-autoformat.js [ Pass Timeout ]
+crbug.com/846471 virtual/binary-for-devtools/http/tests/devtools/coverage/reveal-autoformat.js [ Pass Timeout ]
 crbug.com/846656 external/wpt/css/selectors/focus-visible-002-manual.html [ Pass Timeout ]
 
 # Sheriff 2018-05-28
 # Merged failing devtools/editor tests.
 crbug.com/749738 http/tests/devtools/editor/text-editor-word-jumps.js [ Timeout Pass ]
+crbug.com/749738 virtual/binary-for-devtools/http/tests/devtools/editor/text-editor-word-jumps.js [ Timeout Pass ]
 crbug.com/846997 http/tests/devtools/editor/text-editor-ctrl-d-1.js [ Timeout Pass ]
+crbug.com/846997 virtual/binary-for-devtools/http/tests/devtools/editor/text-editor-ctrl-d-1.js [ Timeout Pass ]
 crbug.com/849284 [ Mac ] http/tests/devtools/editor/text-editor-ctrl-d-2.js [ Timeout Pass ]
+crbug.com/849284 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/editor/text-editor-ctrl-d-2.js [ Timeout Pass ]
 crbug.com/846982 http/tests/devtools/editor/text-editor-formatter.js [ Timeout Pass ]
+crbug.com/846982 virtual/binary-for-devtools/http/tests/devtools/editor/text-editor-formatter.js [ Timeout Pass ]
 crbug.com/846981 fast/webgl/texImage-imageBitmap-from-imageData-resize.html [ Pass Timeout ]
 ### See crbug.com/891427 comment near the top of this file:
 ###crbug.com/847114 [ Linux ] http/tests/devtools/tracing/decode-resize.js [ Pass Failure ]
+###crbug.com/847114 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/tracing/decode-resize.js [ Pass Failure ]
 ###crbug.com/847114 [ Linux ] virtual/threaded/http/tests/devtools/tracing/decode-resize.js [ Pass Failure ]
 
 crbug.com/843135 virtual/gpu/fast/canvas/canvas-arc-circumference-fill.html [ Pass Failure ]
 
 # Sheriff 2018-05-31
 crbug.com/848398 http/tests/devtools/oopif/oopif-performance-cpu-profiles.js [ Pass Timeout Failure ]
+crbug.com/848398 virtual/binary-for-devtools/http/tests/devtools/oopif/oopif-performance-cpu-profiles.js [ Pass Timeout Failure ]
 
 # Sheriff 2018-06-01
 crbug.com/848851 virtual/exotic-color-space/images/image-hover-display-alt.html [ Failure Pass ]
@@ -5211,7 +5255,9 @@
 # Sheriff 2018-06-07
 crbug.com/850395 virtual/gpu/fast/canvas/canvas-filter-stroke-paint-pattern.html [ Pass Failure ]
 crbug.com/850358 http/tests/devtools/editor/text-editor-enter-behaviour.js [ Pass Failure Timeout ]
+crbug.com/850358 virtual/binary-for-devtools/http/tests/devtools/editor/text-editor-enter-behaviour.js [ Pass Failure Timeout ]
 crbug.com/849978 http/tests/devtools/elements/styles-4/stylesheet-source-url-comment.js [ Pass Failure Timeout ]
+crbug.com/849978 virtual/binary-for-devtools/http/tests/devtools/elements/styles-4/stylesheet-source-url-comment.js [ Pass Failure Timeout ]
 
 # Sheriff 2018-06-08
 crbug.com/850170 virtual/reporting-api/external/wpt/content-security-policy/reporting-api/reporting-api-doesnt-send-reports-without-violation.https.sub.html [ Pass Crash Timeout ]
@@ -5220,6 +5266,7 @@
 
 # Sheriff 2018-06-11
 crbug.com/850202 [ Linux ] http/tests/devtools/network/network-filters.js [ Pass Failure Timeout ]
+crbug.com/850202 [ Linux ] virtual/binary-for-devtools/http/tests/devtools/network/network-filters.js [ Pass Failure Timeout ]
 
 crbug.com/853360 [ Mac ] fast/css/input-search-padding.html [ Failure ]
 crbug.com/853360 [ Mac ] fast/forms/calendar-picker/calendar-picker-appearance-ar.html [ Failure ]
@@ -5269,6 +5316,7 @@
 
 # Sheriff 2018-06-29
 crbug.com/859169 [ Linux Debug ] http/tests/devtools/layers/layer-scroll-rects-get.js [ Failure Pass ]
+crbug.com/859169 [ Linux Debug ] virtual/binary-for-devtools/http/tests/devtools/layers/layer-scroll-rects-get.js [ Failure Pass ]
 
 # User Activation
 crbug.com/736415 external/wpt/html/user-activation/activation-api-iframe.tenative.html [ Failure ]
@@ -5311,7 +5359,9 @@
 crbug.com/867376 [ Linux ] css3/filters/filter-repaint-composited-fallback-crash.html [ Timeout Pass ]
 crbug.com/867376 [ Mac ] external/wpt/encoding/textdecoder-fatal-single-byte.any.html [ Timeout Pass ]
 crbug.com/867376 [ Mac ] http/tests/devtools/elements/elements-inspect-iframe-from-different-domain.js [ Timeout Pass ]
+crbug.com/867376 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/elements/elements-inspect-iframe-from-different-domain.js [ Timeout Pass ]
 crbug.com/867376 [ Mac ] http/tests/devtools/elements/css-variables/resolve-inherited-css-variables.js [ Timeout Pass ]
+crbug.com/867376 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/elements/css-variables/resolve-inherited-css-variables.js [ Timeout Pass ]
 crbug.com/867376 [ Linux ] virtual/gpu/fast/canvas/canvas-blending-image-over-color.html [ Timeout Pass ]
 crbug.com/867376 [ Linux ] virtual/gpu/fast/canvas/canvas-blending-image-over-image.html [ Timeout Pass ]
 crbug.com/867376 [ Linux ] virtual/gpu-rasterization/images/color-profile-mask-image-svg.html [ Timeout Pass ]
@@ -5444,6 +5494,7 @@
 crbug.com/869364 css3/filters/filter-repaint-composited-fallback.html [ Pass Timeout ]
 crbug.com/869364 external/wpt/IndexedDB/parallel-cursors-upgrade.html [ Pass Timeout ]
 crbug.com/869364 http/tests/devtools/console/console-correct-suggestions.js [ Pass Timeout ]
+crbug.com/869364 virtual/binary-for-devtools/http/tests/devtools/console/console-correct-suggestions.js [ Pass Timeout ]
 crbug.com/869364 virtual/gpu/fast/canvas/OffscreenCanvas-filter.html [ Pass Timeout ]
 
 # Sheriff 2018-08-01
@@ -5479,6 +5530,7 @@
 
 # Test frequently times out on Mac CQ bots.
 crbug.com/874703 [ Mac ] http/tests/devtools/extensions/extensions-panel.js [ Timeout Pass ]
+crbug.com/874703 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/extensions/extensions-panel.js [ Timeout Pass ]
 
 # Wake Lock api test timeouts
 crbug.com/872530 external/wpt/wake-lock/wakelock-applicability-manual.https.html [ Pass Timeout ]
@@ -5587,6 +5639,7 @@
 
 # Sheriff 2018-09-25
 crbug.com/888609 [ Mac ] http/tests/devtools/coverage/gutter-css.js [ Pass Timeout ]
+crbug.com/888609 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/coverage/gutter-css.js [ Pass Timeout ]
 
 # Sheriff 2018-10-03
 crbug.com/891530 [ Linux ] virtual/android/rootscroller/remove-rootscroller-crash.html [ Pass Timeout ]
@@ -5648,7 +5701,9 @@
 
 # Sheriff 2018-10-31
 crbug.com/900326 [ Win7 ] http/tests/devtools/network/preview-searchable.js [ Timeout Pass ]
+crbug.com/900326 [ Win7 ] virtual/binary-for-devtools/http/tests/devtools/network/preview-searchable.js [ Timeout Pass ]
 crbug.com/900326 [ Mac10.12 ] http/tests/devtools/network/preview-searchable.js [ Timeout Pass ]
+crbug.com/900326 [ Mac10.12 ] virtual/binary-for-devtools/http/tests/devtools/network/preview-searchable.js [ Timeout Pass ]
 crbug.com/874695 crbug.com/900641 crbug.com/913865 [ Linux Mac ] compositing/transitions/transform-on-large-layer.html [ Timeout Pass Crash ]
 crbug.com/900730 [ Mac ] rootscroller/gesture-scroll-document-not-root-scroller.html [ Pass Failure Timeout Crash ]
 
@@ -5683,6 +5738,7 @@
 
 # See also crbug.com/907150
 crbug.com/667560 http/tests/devtools/console-cross-origin-iframe-logging.js [ Pass Failure Timeout ]
+crbug.com/667560 virtual/binary-for-devtools/http/tests/devtools/console-cross-origin-iframe-logging.js [ Pass Failure Timeout ]
 crbug.com/907412 [ Mac10.13 ] external/wpt/domxpath/xml_xpath_runner.html [ Pass Timeout ]
 
 #Sheriff 2018-11-22
@@ -5706,11 +5762,13 @@
 
 # Sheriff 2018-12-06
 crbug.com/912793 http/tests/devtools/sources/debugger-breakpoints/restore-locations-for-breakpoint-with-broken-source-map.js [ Pass Failure ]
+crbug.com/912793 virtual/binary-for-devtools/http/tests/devtools/sources/debugger-breakpoints/restore-locations-for-breakpoint-with-broken-source-map.js [ Pass Failure ]
 crbug.com/912793 virtual/android/fullscreen/full-screen-iframe-allowed-video.html [ Pass Failure ]
 
 # Sheriff 2018-12-07
 crbug.com/912821 [ Mac ] virtual/threaded/http/tests/devtools/tracing/user-timing.js [ Pass Failure ]
 crbug.com/912821 [ Mac ] http/tests/devtools/tracing/user-timing.js [ Pass Failure ]
+crbug.com/912821 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/tracing/user-timing.js [ Pass Failure ]
 
 crbug.com/913173 fast/backgrounds/background-svg-scaling-zoom.html [ Failure Pass ]
 
@@ -5826,9 +5884,13 @@
 crbug.com/922951 fast/text/international/inline-plaintext-relayout-with-leading-neutrals.html [ Skip ]
 crbug.com/922951 http/tests/cache/subresource-fragment-identifier.html [ Skip ]
 crbug.com/922951 http/tests/devtools/audits2/audits2-successful-run.js [ Skip ]
+crbug.com/922951 virtual/binary-for-devtools/http/tests/devtools/audits2/audits2-successful-run.js [ Skip ]
 crbug.com/922951 http/tests/devtools/tracing-session-id.js [ Skip ]
+crbug.com/922951 virtual/binary-for-devtools/http/tests/devtools/tracing-session-id.js [ Skip ]
 crbug.com/922951 http/tests/devtools/tracing/console-timeline.js [ Skip ]
+crbug.com/922951 virtual/binary-for-devtools/http/tests/devtools/tracing/console-timeline.js [ Skip ]
 crbug.com/922951 http/tests/devtools/tracing/timeline-network-received-data.js [ Skip ]
+crbug.com/922951 virtual/binary-for-devtools/http/tests/devtools/tracing/timeline-network-received-data.js [ Skip ]
 crbug.com/922951 http/tests/history/back-to-post.html [ Skip ]
 crbug.com/922951 http/tests/images/feature-policy-unoptimized-images-cached-image.html [ Skip ]
 crbug.com/922951 http/tests/security/offscreencanvas-placeholder-read-blocked-no-crossorigin.html [ Skip ]
@@ -5960,13 +6022,16 @@
 # These started failing when network service was enabled by default.
 crbug.com/933880 external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ]
 crbug.com/933880 http/tests/inspector-protocol/network/interception-take-stream.js [ Failure ]
+crbug.com/933880 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/network/interception-take-stream.js [ Failure ]
 crbug.com/933880 http/tests/inspector-protocol/network/xhr-interception-auth-fail.js [ Failure ]
+crbug.com/933880 virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/network/xhr-interception-auth-fail.js [ Failure ]
 # This passes in content_shell but not in chrome with network service disabled,
 # because content_shell does not add the about: handler. With network service
 # enabled this fails in both content_shell and chrome.
 crbug.com/933880 http/tests/misc/redirect-to-about-blank.html [ Failure Timeout ]
 crbug.com/933880 [ Win ] external/wpt/kv-storage/key-types.https.html [ Timeout ]
 crbug.com/849284 [ Win ] http/tests/devtools/editor/text-editor-ctrl-d-2.js [ Failure Timeout ]
+crbug.com/849284 [ Win ] virtual/binary-for-devtools/http/tests/devtools/editor/text-editor-ctrl-d-2.js [ Failure Timeout ]
 crbug.com/849284 [ Win ] virtual/outofblink-cors/http/tests/fetch/serviceworker-proxied/thorough/redirect.html [ Timeout ]
 
 # Sheriff 2019-02-21
@@ -5977,9 +6042,11 @@
 crbug.com/934636 virtual/feature-policy-for-sandbox/http/tests/security/cross-origin-indexeddb-allowed.html [ Crash Pass ]
 crbug.com/934636 virtual/outofblink-cors/http/tests/security/cross-origin-indexeddb-allowed.html [ Crash Pass ]
 crbug.com/934768 [ Mac ] http/tests/devtools/tracing/worker-events.js [ Failure Pass ]
+crbug.com/934768 [ Mac ] virtual/binary-for-devtools/http/tests/devtools/tracing/worker-events.js [ Failure Pass ]
 crbug.com/934768 [ Mac ] virtual/threaded/http/tests/devtools/tracing/worker-events.js [ Failure Pass ]
 crbug.com/934818 [ Mac Debug ] virtual/threaded/http/tests/devtools/tracing/decode-resize.js [ Failure Pass ]
 crbug.com/935027 http/tests/devtools/animation/animation-transition-setTiming-crash.js [ Crash Pass ]
+crbug.com/935027 virtual/binary-for-devtools/http/tests/devtools/animation/animation-transition-setTiming-crash.js [ Crash Pass ]
 
 # Sheriff 2019-02-25
 crbug.com/935587 [ Mac ] virtual/video-surface-layer/media/stable/video-object-fit-stable.html [ Failure Pass ]
@@ -5992,8 +6059,6 @@
 crbug.com/935690 virtual/video-surface-layer/media/video-played-ranges-1.html [ Failure ]
 
 # Sheriff 2019-02-26
-crbug.com/935689 [ Mac ] external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/system-alphabetic-invalid.html [ Failure ]
-crbug.com/935689 [ Mac ] external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/system-cyclic-invalid.html [ Failure ]
 crbug.com/936083 external/wpt/import-maps/builtin-import-scheme.tentative.html [ Failure Pass ]
 crbug.com/936095 fast/css-intrinsic-dimensions/height-tables-collapsed.html [ Failure Pass ]
 crbug.com/934818 [ Linux ] virtual/threaded/http/tests/devtools/tracing/decode-resize.js [ Failure Pass ]
@@ -6004,6 +6069,7 @@
 # Sheriff 2019-02-27
 crbug.com/936279 external/wpt/import-maps/fallback-disallowed.sub.tentative.html [ Failure Pass Timeout ]
 crbug.com/936479 [ Mac10.13 ] http/tests/devtools/sources/debugger/async-callstack-fetch.js [ Failure Crash Pass ]
+crbug.com/936479 [ Mac10.13 ] virtual/binary-for-devtools/http/tests/devtools/sources/debugger/async-callstack-fetch.js [ Failure Crash Pass ]
 crbug.com/936615 [ Win7 ] external/wpt/kv-storage/values.https.html [ Timeout Pass ]
 
 # Device Sensor Events were restricted to secure browsing contexts in M74, with a flag available until M76 to undo the change in case of an emergency.
@@ -6033,30 +6099,40 @@
 crbug.com/937170 [ Linux Win7 ] external/wpt/IndexedDB/interleaved-cursors-large.html [ Pass Timeout Crash ]
 crbug.com/937312 [ Win7 ] external/wpt/background-fetch/fetch.https.window.html [ Pass Timeout ]
 crbug.com/937378 [ Win7 ] http/tests/devtools/service-workers/service-workers-force-update-on-page-load.js [ Pass Timeout ]
+crbug.com/937378 [ Win7 ] virtual/binary-for-devtools/http/tests/devtools/service-workers/service-workers-force-update-on-page-load.js [ Pass Timeout ]
 crbug.com/864994 [ Linux Win7 ] external/wpt/encoding/legacy-mb-korean/euc-kr/euckr-decode-ksc_5601.html [ Timeout Failure Pass ]
 crbug.com/937416 [ Linux Mac ] http/tests/devtools/resource-tree/resource-tree-htmlimports.js [ Pass Failure ]
+crbug.com/937416 [ Linux Mac ] virtual/binary-for-devtools/http/tests/devtools/resource-tree/resource-tree-htmlimports.js [ Pass Failure ]
 crbug.com/937416 http/tests/devtools/resource-tree/resource-tree-frame-navigate.js [ Pass Failure ]
+crbug.com/937416 virtual/binary-for-devtools/http/tests/devtools/resource-tree/resource-tree-frame-navigate.js [ Pass Failure ]
 crbug.com/937546 [ Win7 ] http/tests/security/xss-DENIED-cross-origin-stack-overflow.html [ Pass Timeout ]
 # Sheriff 2019-03-02
 crbug.com/937639 [ Linux Debug ] external/wpt/html/browsers/browsing-the-web/read-media/pageload-image-in-popup.html [ Pass Failure ]
 
 # Sheriff 2019-03-04
 crbug.com/937811 [ Linux Release ] http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-2.js [ Pass Failure ]
+crbug.com/937811 [ Linux Release ] virtual/binary-for-devtools/http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-2.js [ Pass Failure ]
 crbug.com/937811 [ Linux Release ] http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-3.js [ Pass Failure ]
+crbug.com/937811 [ Linux Release ] virtual/binary-for-devtools/http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-3.js [ Pass Failure ]
 crbug.com/937811 [ Win Release ] http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-2.js [ Pass Failure ]
+crbug.com/937811 [ Win Release ] virtual/binary-for-devtools/http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-2.js [ Pass Failure ]
 crbug.com/937811 [ Win Release ] http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-3.js [ Pass Failure ]
+crbug.com/937811 [ Win Release ] virtual/binary-for-devtools/http/tests/devtools/elements/shadow/elements-panel-shadow-selection-on-refresh-3.js [ Pass Failure ]
 crbug.com/935689 [ Linux Debug ] external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/symbols-function.html [ Failure Pass ]
 crbug.com/937858 [ Debug ] external/wpt/ambient-light/AmbientLightSensor.https.html [ Pass Failure ]
 crbug.com/937902 [ Linux Debug ] virtual/disable-blink-gen-property-trees/compositing/overflow/overflow-scroll-with-local-background.html [ Pass Failure ]
 crbug.com/937991 [ Win7 Release ] http/tests/devtools/cache-storage/cache-data.js [ Pass Timeout ]
+crbug.com/937991 [ Win7 Release ] virtual/binary-for-devtools/http/tests/devtools/cache-storage/cache-data.js [ Pass Timeout ]
 
 # Sheriff 2019-03-05
 crbug.com/938200 http/tests/devtools/network/network-blocked-reason.js [ Timeout Pass ]
+crbug.com/938200 virtual/binary-for-devtools/http/tests/devtools/network/network-blocked-reason.js [ Timeout Pass ]
 crbug.com/938780 [ Mac ] virtual/threaded/external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-root-scroller.https.html [ Failure ]
 
 # Sheriff 2019-03-06
 crbug.com/938591 [ Linux ] fast/events/middleClickAutoscroll-nested-divs-forbidden.html [ Failure Pass ]
 crbug.com/938884 [ Win7 Mac ] http/tests/devtools/elements/styles-3/styles-add-blank-property.js [ Pass Timeout ]
+crbug.com/938884 [ Win7 Mac ] virtual/binary-for-devtools/http/tests/devtools/elements/styles-3/styles-add-blank-property.js [ Pass Timeout ]
 
 # Caused a revert of a good change.
 crbug.com/931533 media/video-played-collapse.html [ Pass Failure ]
@@ -6079,3 +6155,4 @@
 crbug.com/836242 [ Win ] fast/loader/reload-zero-byte-plugin.html [ Pass Failure ]
 crbug.com/806357 virtual/threaded/fast/events/pointerevents/pinch/pointerevent_touch-action-pinch_zoom_touch.html [ Pass Failure Crash ]
 crbug.com/941931 [ Linux Win ] http/tests/security/contentSecurityPolicy/1.1/plugintypes-affects-cross-site-child-disallowed.html [ Pass Failure ]
+crbug.com/942134 [ Win ] virtual/exotic-color-space/images/feature-policy-oversized-images.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 3eb6369..97c5dee 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -289,6 +289,16 @@
     "args": ["--enable-threaded-compositing"]
   },
   {
+    "prefix": "binary-for-devtools",
+    "base": "http/tests/devtools",
+    "args": ["--enable-internal-devtools-binary-protocol"]
+  },
+  {
+    "prefix": "binary-for-inspector-protocol",
+    "base": "http/tests/inspector-protocol",
+    "args": ["--enable-internal-devtools-binary-protocol"]
+  },
+  {
     "prefix": "composite-after-paint",
     "base": "compositing",
     "args": ["--enable-blink-features=CompositeAfterPaint"]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
index 3c5ad49..eb6a3fa4 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
@@ -6121,18 +6121,6 @@
      {}
     ]
    ],
-   "pointerlock/mouse_buttons_back_forward-manual.html": [
-    [
-     "/pointerlock/mouse_buttons_back_forward-manual.html",
-     {}
-    ]
-   ],
-   "pointerlock/movementX_Y_basic-manual.html": [
-    [
-     "/pointerlock/movementX_Y_basic-manual.html",
-     {}
-    ]
-   ],
    "pointerlock/movementX_Y_no-jumps-manual.html": [
     [
      "/pointerlock/movementX_Y_no-jumps-manual.html",
@@ -6169,24 +6157,6 @@
      {}
     ]
    ],
-   "pointerlock/pointerlock_remove_target-manual.html": [
-    [
-     "/pointerlock/pointerlock_remove_target-manual.html",
-     {}
-    ]
-   ],
-   "pointerlock/pointerlock_remove_target_on_mouseup-manual.html": [
-    [
-     "/pointerlock/pointerlock_remove_target_on_mouseup-manual.html",
-     {}
-    ]
-   ],
-   "pointerlock/pointerlock_shadow-manual.html": [
-    [
-     "/pointerlock/pointerlock_shadow-manual.html",
-     {}
-    ]
-   ],
    "presentation-api/controlling-ua/PresentationAvailability_onchange-manual.https.html": [
     [
      "/presentation-api/controlling-ua/PresentationAvailability_onchange-manual.https.html",
@@ -6939,6 +6909,18 @@
      {}
     ]
    ],
+   "animation-worklet/worklet-animation-cancel.https.html": [
+    [
+     "/animation-worklet/worklet-animation-cancel.https.html",
+     [
+      [
+       "/animation-worklet/worklet-animation-cancel-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "animation-worklet/worklet-animation-local-time-after-duration.https.html": [
     [
      "/animation-worklet/worklet-animation-local-time-after-duration.https.html",
@@ -7011,6 +6993,18 @@
      {}
     ]
    ],
+   "animation-worklet/worklet-animation-start-delay.https.html": [
+    [
+     "/animation-worklet/worklet-animation-start-delay.https.html",
+     [
+      [
+       "/animation-worklet/worklet-animation-start-delay-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "animation-worklet/worklet-animation-with-scroll-timeline-and-display-none.https.html": [
     [
      "/animation-worklet/worklet-animation-with-scroll-timeline-and-display-none.https.html",
@@ -48291,6 +48285,54 @@
      {}
     ]
    ],
+   "css/css-grid/grid-items/grid-item-overflow-auto-max-height-percentage.html": [
+    [
+     "/css/css-grid/grid-items/grid-item-overflow-auto-max-height-percentage.html",
+     [
+      [
+       "/css/css-grid/grid-items/grid-item-overflow-auto-max-height-percentage-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-item-percentage-sizes-001.html": [
+    [
+     "/css/css-grid/grid-items/grid-item-percentage-sizes-001.html",
+     [
+      [
+       "/css/css-grid/grid-items/grid-item-percentage-sizes-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-item-percentage-sizes-002.html": [
+    [
+     "/css/css-grid/grid-items/grid-item-percentage-sizes-002.html",
+     [
+      [
+       "/css/css-grid/grid-items/grid-item-percentage-sizes-002-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-item-percentage-sizes-003.html": [
+    [
+     "/css/css-grid/grid-items/grid-item-percentage-sizes-003.html",
+     [
+      [
+       "/css/css-grid/grid-items/grid-item-percentage-sizes-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-grid/grid-items/grid-items-001.html": [
     [
      "/css/css-grid/grid-items/grid-items-001.html",
@@ -64047,6 +64089,18 @@
      {}
     ]
    ],
+   "css/css-text/overflow-wrap/overflow-wrap-break-word-007.html": [
+    [
+     "/css/css-text/overflow-wrap/overflow-wrap-break-word-007.html",
+     [
+      [
+       "/css/css-text/overflow-wrap/reference/overflow-wrap-break-word-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-text/overflow-wrap/overflow-wrap-break-word-fit-content-001.html": [
     [
      "/css/css-text/overflow-wrap/overflow-wrap-break-word-fit-content-001.html",
@@ -67155,6 +67209,18 @@
      {}
     ]
    ],
+   "css/css-text/white-space/pre-wrap-008.html": [
+    [
+     "/css/css-text/white-space/pre-wrap-008.html",
+     [
+      [
+       "/css/css-text/white-space/reference/white-space-break-spaces-005-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-text/white-space/pre-wrap-011.html": [
     [
      "/css/css-text/white-space/pre-wrap-011.html",
@@ -67835,6 +67901,18 @@
      {}
     ]
    ],
+   "css/css-text/word-break/word-break-break-all-015.html": [
+    [
+     "/css/css-text/word-break/word-break-break-all-015.html",
+     [
+      [
+       "/css/css-text/word-break/reference/word-break-break-all-010-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-text/word-break/word-break-break-all-020.html": [
     [
      "/css/css-text/word-break/word-break-break-all-020.html",
@@ -74595,6 +74673,18 @@
      {}
     ]
    ],
+   "css/css-transforms/transform-flattening-001.html": [
+    [
+     "/css/css-transforms/transform-flattening-001.html",
+     [
+      [
+       "about:blank",
+       "!="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-transforms/transform-generated-001.html": [
     [
      "/css/css-transforms/transform-generated-001.html",
@@ -118032,6 +118122,16 @@
      {}
     ]
    ],
+   "animation-worklet/worklet-animation-cancel-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "animation-worklet/worklet-animation-duration-ref.html": [
+    [
+     {}
+    ]
+   ],
    "animation-worklet/worklet-animation-local-time-after-duration-ref.html": [
     [
      {}
@@ -118052,6 +118152,11 @@
      {}
     ]
    ],
+   "animation-worklet/worklet-animation-start-delay-ref.html": [
+    [
+     {}
+    ]
+   ],
    "animation-worklet/worklet-animation-with-scroll-timeline-and-overflow-hidden-ref.html": [
     [
      {}
@@ -140207,6 +140312,26 @@
      {}
     ]
    ],
+   "css/css-grid/grid-items/grid-item-overflow-auto-max-height-percentage-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-item-percentage-sizes-001-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-item-percentage-sizes-002-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-item-percentage-sizes-003-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-grid/grid-items/grid-items-sizing-alignment-001-ref.html": [
     [
      {}
@@ -161982,6 +162107,21 @@
      {}
     ]
    ],
+   "feature-policy/resources/feature-policy-idle-detection-worker.html": [
+    [
+     {}
+    ]
+   ],
+   "feature-policy/resources/feature-policy-idle-detection-worker.js": [
+    [
+     {}
+    ]
+   ],
+   "feature-policy/resources/feature-policy-idle-detection.html": [
+    [
+     {}
+    ]
+   ],
    "feature-policy/resources/feature-policy-nested-subframe-policy.https.sub.html": [
     [
      {}
@@ -173197,26 +173337,6 @@
      {}
     ]
    ],
-   "html/semantics/forms/form-submission-target/rel-base-target-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "html/semantics/forms/form-submission-target/rel-button-target-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "html/semantics/forms/form-submission-target/rel-form-target-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "html/semantics/forms/form-submission-target/rel-input-target-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "html/semantics/forms/form-submission-target/resources/endpoint.html": [
     [
      {}
@@ -175817,6 +175937,16 @@
      {}
     ]
    ],
+   "idle-detection/idle-detection-allowed-by-feature-policy.https.sub.html.headers": [
+    [
+     {}
+    ]
+   ],
+   "idle-detection/idle-detection-disabled-by-feature-policy.https.sub.html.headers": [
+    [
+     {}
+    ]
+   ],
    "idle-detection/idle-detection.idl": [
     [
      {}
@@ -175827,6 +175957,16 @@
      {}
     ]
    ],
+   "idle-detection/resources/idle-detection-allowed-by-feature-policy-worker.js": [
+    [
+     {}
+    ]
+   ],
+   "idle-detection/resources/idle-detection-disabled-by-feature-policy-worker.js": [
+    [
+     {}
+    ]
+   ],
    "imagebitmap-renderingcontext/META.yml": [
     [
      {}
@@ -180622,6 +180762,11 @@
      {}
     ]
    ],
+   "portals/resources/portal-activate-data-portal.html": [
+    [
+     {}
+    ]
+   ],
    "portals/resources/portal-activate-event-portal.html": [
     [
      {}
@@ -184182,6 +184327,41 @@
      {}
     ]
    ],
+   "resource-timing/resources/document-navigated.html": [
+    [
+     {}
+    ]
+   ],
+   "resource-timing/resources/document-refreshed.html": [
+    [
+     {}
+    ]
+   ],
+   "resource-timing/resources/document-that-navigates.html": [
+    [
+     {}
+    ]
+   ],
+   "resource-timing/resources/document-that-refreshes.html": [
+    [
+     {}
+    ]
+   ],
+   "resource-timing/resources/embed-navigate-back.html": [
+    [
+     {}
+    ]
+   ],
+   "resource-timing/resources/embed-navigate.html": [
+    [
+     {}
+    ]
+   ],
+   "resource-timing/resources/embed-refresh.html": [
+    [
+     {}
+    ]
+   ],
    "resource-timing/resources/empty.js": [
     [
      {}
@@ -184232,6 +184412,26 @@
      {}
     ]
    ],
+   "resource-timing/resources/iframe-TAO-crossorigin-port.sub.html": [
+    [
+     {}
+    ]
+   ],
+   "resource-timing/resources/iframe-navigate-back.html": [
+    [
+     {}
+    ]
+   ],
+   "resource-timing/resources/iframe-navigate.html": [
+    [
+     {}
+    ]
+   ],
+   "resource-timing/resources/iframe-refresh.html": [
+    [
+     {}
+    ]
+   ],
    "resource-timing/resources/iframe-reload-TAO.sub.html": [
     [
      {}
@@ -184302,6 +184502,16 @@
      {}
     ]
    ],
+   "resource-timing/resources/navigate_back.html": [
+    [
+     {}
+    ]
+   ],
+   "resource-timing/resources/nested-contexts.js": [
+    [
+     {}
+    ]
+   ],
    "resource-timing/resources/nested.css": [
     [
      {}
@@ -184312,6 +184522,21 @@
      {}
     ]
    ],
+   "resource-timing/resources/object-navigate-back.html": [
+    [
+     {}
+    ]
+   ],
+   "resource-timing/resources/object-navigate.html": [
+    [
+     {}
+    ]
+   ],
+   "resource-timing/resources/object-refresh.html": [
+    [
+     {}
+    ]
+   ],
    "resource-timing/resources/resource_timing_test0.css": [
     [
      {}
@@ -184757,6 +184982,11 @@
      {}
     ]
    ],
+   "screen-orientation/lock-unlock-check-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "screen-orientation/onchange-event-expected.txt": [
     [
      {}
@@ -184772,6 +185002,11 @@
      {}
     ]
    ],
+   "screen-orientation/resources/orientation-utils.js": [
+    [
+     {}
+    ]
+   ],
    "screen-orientation/resources/sandboxed-iframe-locking.html": [
     [
      {}
@@ -184892,6 +185127,11 @@
      {}
     ]
    ],
+   "selection/Document-open-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "selection/META.yml": [
     [
      {}
@@ -188112,6 +188352,21 @@
      {}
     ]
    ],
+   "signed-exchange/resources/register-sw-after-fallback.html": [
+    [
+     {}
+    ]
+   ],
+   "signed-exchange/resources/register-sw.html": [
+    [
+     {}
+    ]
+   ],
+   "signed-exchange/resources/service-worker.js": [
+    [
+     {}
+    ]
+   ],
    "signed-exchange/resources/sxg-location.html": [
     [
      {}
@@ -188167,6 +188422,16 @@
      {}
     ]
    ],
+   "signed-exchange/resources/sxg/register-sw-after-fallback.sxg": [
+    [
+     {}
+    ]
+   ],
+   "signed-exchange/resources/sxg/register-sw-from-sxg.sxg": [
+    [
+     {}
+    ]
+   ],
    "signed-exchange/resources/sxg/sxg-cert-not-found-on-alt-origin.sxg": [
     [
      {}
@@ -188287,6 +188552,16 @@
      {}
     ]
    ],
+   "signed-exchange/service-workers/sxg-sw-register-after-fallback.tentative.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "signed-exchange/service-workers/sxg-sw-register.tentative.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "speech-api/META.yml": [
     [
      {}
@@ -201322,6 +201597,11 @@
      {}
     ]
    ],
+   "webxr/resources/webxr_math_utils.js": [
+    [
+     {}
+    ]
+   ],
    "webxr/resources/webxr_test_asserts.js": [
     [
      {}
@@ -211836,6 +212116,18 @@
      {}
     ]
    ],
+   "animation-worklet/worklet-animation-creation.https.html": [
+    [
+     "/animation-worklet/worklet-animation-creation.https.html",
+     {}
+    ]
+   ],
+   "animation-worklet/worklet-animation-duration.https.html": [
+    [
+     "/animation-worklet/worklet-animation-duration.https.html",
+     {}
+    ]
+   ],
    "animation-worklet/worklet-animation-pause.https.html": [
     [
      "/animation-worklet/worklet-animation-pause.https.html",
@@ -235018,6 +235310,12 @@
      {}
     ]
    ],
+   "element-timing/observe-video-poster.html": [
+    [
+     "/element-timing/observe-video-poster.html",
+     {}
+    ]
+   ],
    "element-timing/progressively-loaded-image.html": [
     [
      "/element-timing/progressively-loaded-image.html",
@@ -248132,6 +248430,12 @@
      {}
     ]
    ],
+   "html/browsers/the-window-object/document-attribute.window.js": [
+    [
+     "/html/browsers/the-window-object/document-attribute.window.html",
+     {}
+    ]
+   ],
    "html/browsers/the-window-object/focus.window.js": [
     [
      "/html/browsers/the-window-object/focus.window.html",
@@ -248204,6 +248508,12 @@
      {}
     ]
    ],
+   "html/browsers/the-window-object/self-et-al.window.js": [
+    [
+     "/html/browsers/the-window-object/self-et-al.window.html",
+     {}
+    ]
+   ],
    "html/browsers/the-window-object/window-aliases.html": [
     [
      "/html/browsers/the-window-object/window-aliases.html",
@@ -259844,6 +260154,36 @@
      {}
     ]
    ],
+   "idle-detection/idle-detection-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html": [
+    [
+     "/idle-detection/idle-detection-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html",
+     {}
+    ]
+   ],
+   "idle-detection/idle-detection-allowed-by-feature-policy-attribute.https.sub.html": [
+    [
+     "/idle-detection/idle-detection-allowed-by-feature-policy-attribute.https.sub.html",
+     {}
+    ]
+   ],
+   "idle-detection/idle-detection-allowed-by-feature-policy.https.sub.html": [
+    [
+     "/idle-detection/idle-detection-allowed-by-feature-policy.https.sub.html",
+     {}
+    ]
+   ],
+   "idle-detection/idle-detection-default-feature-policy.https.sub.html": [
+    [
+     "/idle-detection/idle-detection-default-feature-policy.https.sub.html",
+     {}
+    ]
+   ],
+   "idle-detection/idle-detection-disabled-by-feature-policy.https.sub.html": [
+    [
+     "/idle-detection/idle-detection-disabled-by-feature-policy.https.sub.html",
+     {}
+    ]
+   ],
    "idle-detection/idlharness.https.any.js": [
     [
      "/idle-detection/idlharness.https.any.html",
@@ -264732,6 +265072,12 @@
      {}
     ]
    ],
+   "navigation-timing/nav2_test_redirect_chain_xserver_partial_opt_in.html": [
+    [
+     "/navigation-timing/nav2_test_redirect_chain_xserver_partial_opt_in.html",
+     {}
+    ]
+   ],
    "navigation-timing/nav2_test_redirect_none.html": [
     [
      "/navigation-timing/nav2_test_redirect_none.html",
@@ -264774,6 +265120,18 @@
      {}
     ]
    ],
+   "navigation-timing/nav2_test_unloadEvents_with_cross_origin_redirect_chain_partial_opt_in.html": [
+    [
+     "/navigation-timing/nav2_test_unloadEvents_with_cross_origin_redirect_chain_partial_opt_in.html",
+     {}
+    ]
+   ],
+   "navigation-timing/nav2_test_unloadEvents_with_cross_origin_redirect_opt_in.html": [
+    [
+     "/navigation-timing/nav2_test_unloadEvents_with_cross_origin_redirect_opt_in.html",
+     {}
+    ]
+   ],
    "navigation-timing/nav2_test_unloadEvents_with_cross_origin_redirects.html": [
     [
      "/navigation-timing/nav2_test_unloadEvents_with_cross_origin_redirects.html",
@@ -275574,6 +275932,55 @@
      {}
     ]
    ],
+   "pointerlock/mouse_buttons_back_forward.html": [
+    [
+     "/pointerlock/mouse_buttons_back_forward.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
+   "pointerlock/movementX_Y_basic.html": [
+    [
+     "/pointerlock/movementX_Y_basic.html",
+     {
+      "testdriver": true,
+      "timeout": "long"
+     }
+    ]
+   ],
+   "pointerlock/pointerlock_remove_target.html": [
+    [
+     "/pointerlock/pointerlock_remove_target.html",
+     {
+      "testdriver": true,
+      "timeout": "long"
+     }
+    ]
+   ],
+   "pointerlock/pointerlock_remove_target_on_mouseup.html": [
+    [
+     "/pointerlock/pointerlock_remove_target_on_mouseup.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
+   "pointerlock/pointerlock_shadow.html": [
+    [
+     "/pointerlock/pointerlock_shadow.html",
+     {
+      "testdriver": true,
+      "timeout": "long"
+     }
+    ]
+   ],
+   "portals/portal-activate-data.html": [
+    [
+     "/portals/portal-activate-data.html",
+     {}
+    ]
+   ],
    "portals/portal-activate-event.html": [
     [
      "/portals/portal-activate-event.html",
@@ -285938,6 +286345,12 @@
      {}
     ]
    ],
+   "resource-timing/TAO-crossorigin-port.sub.html": [
+    [
+     "/resource-timing/TAO-crossorigin-port.sub.html",
+     {}
+    ]
+   ],
    "resource-timing/buffer-full-add-after-full-event.html": [
     [
      "/resource-timing/buffer-full-add-after-full-event.html",
@@ -286026,6 +286439,14 @@
      {}
     ]
    ],
+   "resource-timing/nested-context-navigations.html": [
+    [
+     "/resource-timing/nested-context-navigations.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
    "resource-timing/no-entries-for-cross-origin-css-fetched.sub.html": [
     [
      "/resource-timing/no-entries-for-cross-origin-css-fetched.sub.html",
@@ -286184,18 +286605,18 @@
      {}
     ]
    ],
-   "resource-timing/resource_memory_cached.sub.html": [
-    [
-     "/resource-timing/resource_memory_cached.sub.html",
-     {}
-    ]
-   ],
    "resource-timing/resource_reparenting.html": [
     [
      "/resource-timing/resource_reparenting.html",
      {}
     ]
    ],
+   "resource-timing/resource_reuse.sub.html": [
+    [
+     "/resource-timing/resource_reuse.sub.html",
+     {}
+    ]
+   ],
    "resource-timing/resource_script_types.html": [
     [
      "/resource-timing/resource_script_types.html",
@@ -286338,6 +286759,14 @@
      {}
     ]
    ],
+   "screen-orientation/lock-unlock-check.html": [
+    [
+     "/screen-orientation/lock-unlock-check.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "screen-orientation/onchange-event-subframe.html": [
     [
      "/screen-orientation/onchange-event-subframe.html",
@@ -289102,6 +289531,18 @@
      {}
     ]
    ],
+   "signed-exchange/service-workers/sxg-sw-register-after-fallback.tentative.https.html": [
+    [
+     "/signed-exchange/service-workers/sxg-sw-register-after-fallback.tentative.https.html",
+     {}
+    ]
+   ],
+   "signed-exchange/service-workers/sxg-sw-register.tentative.https.html": [
+    [
+     "/signed-exchange/service-workers/sxg-sw-register.tentative.https.html",
+     {}
+    ]
+   ],
    "signed-exchange/sxg-double-prefetch.tentative.html": [
     [
      "/signed-exchange/sxg-double-prefetch.tentative.html",
@@ -300424,6 +300865,12 @@
      {}
     ]
    ],
+   "webxr/xrRigidTransform_matrix.https.html": [
+    [
+     "/webxr/xrRigidTransform_matrix.https.html",
+     {}
+    ]
+   ],
    "webxr/xrSession_cancelAnimationFrame.https.html": [
     [
      "/webxr/xrSession_cancelAnimationFrame.https.html",
@@ -311222,7 +311669,7 @@
    "support"
   ],
   "2dcontext/META.yml": [
-   "53b11d271cc6181435059f99880a28e0e3f6d5a0",
+   "0f79f2591292a3b2d82e6d42f22f82368381dc08",
    "support"
   ],
   "2dcontext/OWNERS": [
@@ -318038,7 +318485,7 @@
    "support"
   ],
   "WebIDL/META.yml": [
-   "82ae5236f0d9e000f73fe2be9299c74b81938106",
+   "a8dc9c4410e949fa78bdbe2268edf3f125934487",
    "support"
   ],
   "WebIDL/OWNERS": [
@@ -318242,7 +318689,7 @@
    "manual"
   ],
   "accelerometer/META.yml": [
-   "6554be89580e7328117fc35880f70cf623ce0ee9",
+   "7df27e1f40b09a70c9dcee46e9b1e40bbf355595",
    "support"
   ],
   "accelerometer/OWNERS": [
@@ -318990,7 +319437,7 @@
    "manual"
   ],
   "ambient-light/META.yml": [
-   "04fce804971f9050c79960c4f5a344ae1b9fe2bc",
+   "c3f69ba181e69906ebeb1fe42f1e4255f17c47c5",
    "support"
   ],
   "ambient-light/OWNERS": [
@@ -319069,6 +319516,26 @@
    "761e66e7d76f4aaf64c7744d0d04a06e3ba16cd1",
    "testharness"
   ],
+  "animation-worklet/worklet-animation-cancel-ref.html": [
+   "d44927374703ef2b38d3ed0c9570609b62baec65",
+   "support"
+  ],
+  "animation-worklet/worklet-animation-cancel.https.html": [
+   "3a28c7515db455ba50ed50135c5a5bb8534ae580",
+   "reftest"
+  ],
+  "animation-worklet/worklet-animation-creation.https.html": [
+   "3e403feb4366457a800f38030481a7b12f9d24f2",
+   "testharness"
+  ],
+  "animation-worklet/worklet-animation-duration-ref.html": [
+   "81b01bdca813caccb4a3b5e635db21d4f9411a63",
+   "support"
+  ],
+  "animation-worklet/worklet-animation-duration.https.html": [
+   "1526004eaf17d5e420e3989a91ba49bc61f4b704",
+   "testharness"
+  ],
   "animation-worklet/worklet-animation-local-time-after-duration-ref.html": [
    "96acf1ad96c7c41e870429d55142269f4468bb97",
    "support"
@@ -319113,6 +319580,14 @@
    "ac3f05f4234ac1036e388536c4237686b07e6037",
    "reftest"
   ],
+  "animation-worklet/worklet-animation-start-delay-ref.html": [
+   "efef6f842bf0f9d3ce05e6335a3f48d17e625167",
+   "support"
+  ],
+  "animation-worklet/worklet-animation-start-delay.https.html": [
+   "c8683f7daccb40b85c56f098a8061854f4ed293a",
+   "reftest"
+  ],
   "animation-worklet/worklet-animation-with-fill-mode.https.html": [
    "725d10de438ce60d1b6eece5109e9016cc3fc9e8",
    "testharness"
@@ -319286,7 +319761,7 @@
    "testharness"
   ],
   "battery-status/META.yml": [
-   "eded36c5e2f2487376caae21cda9cc36a5090168",
+   "12a2f12c32e9c58912a209e369af59d6ceee3aa4",
    "support"
   ],
   "battery-status/OWNERS": [
@@ -319502,7 +319977,7 @@
    "support"
   ],
   "bluetooth/META.yml": [
-   "501396bac744058ef594b19a935732ba0f277219",
+   "607edb6365b4cde7dc2c292d31c9c4175c466ea8",
    "support"
   ],
   "bluetooth/OWNERS": [
@@ -320542,7 +321017,7 @@
    "support"
   ],
   "common/META.yml": [
-   "594c8b170f5043a944fdd4de17d4bd65eba242fb",
+   "958883a1b07e7db13249153fc85c69d2a40363a3",
    "support"
   ],
   "common/PrefixedLocalStorage.js": [
@@ -320698,7 +321173,7 @@
    "support"
   ],
   "common/sleep.py": [
-   "afc0a7c26e1c2aa63a54bcf39d74cf9c7adf6d75",
+   "2e803b1b262423e219be592fab548ada982bc439",
    "support"
   ],
   "common/slow.py": [
@@ -324038,7 +324513,7 @@
    "testharness"
   ],
   "cookies/META.yml": [
-   "946da8833ac886c2f00488880e3b7a10926efe63",
+   "d0743949b6a122d8bd0adf7b1ed0181f0c51429d",
    "support"
   ],
   "cookies/OWNERS": [
@@ -326326,7 +326801,7 @@
    "support"
   ],
   "css/CSS2/META.yml": [
-   "4ac0804d36d9c7222097a410c32af89c92475ddb",
+   "e9bc44dc8fdda34cc1dd23a1600c77adeacfacfb",
    "support"
   ],
   "css/CSS2/OWNERS": [
@@ -341470,7 +341945,7 @@
    "support"
   ],
   "css/css-backgrounds/META.yml": [
-   "d90a6e083b663ed9a6ef67ba4a92ebd723747550",
+   "d673be5f4f29bf82619aba6f40ed7e287e902582",
    "support"
   ],
   "css/css-backgrounds/OWNERS": [
@@ -345402,7 +345877,7 @@
    "support"
   ],
   "css/css-color/META.yml": [
-   "a8d93c12a945781a88b89874aff7a3b2d72393dd",
+   "a0e70aa6539e88373bc8615c3f4e1453010e85d5",
    "support"
   ],
   "css/css-color/OWNERS": [
@@ -347842,7 +348317,7 @@
    "reftest"
   ],
   "css/css-flexbox/META.yml": [
-   "764d8cbd16850b81fb885927da8556157b890a55",
+   "0bcad0b51f759e6ea9a05e2fee919677bc790dd3",
    "support"
   ],
   "css/css-flexbox/OWNERS": [
@@ -358738,7 +359213,7 @@
    "reftest"
   ],
   "css/css-grid/META.yml": [
-   "af20bb4be80fabd4211684420c232293ac0815ad",
+   "e49946f4f7012e2aefbc2fb01573a2e01a903e55",
    "support"
   ],
   "css/css-grid/OWNERS": [
@@ -360637,6 +361112,38 @@
    "f50e9ef312418f4d3b737bd55b4a7e5c75f09230",
    "testharness"
   ],
+  "css/css-grid/grid-items/grid-item-overflow-auto-max-height-percentage-ref.html": [
+   "96a3ca1d5032e10e0c4491cc17541084543daab2",
+   "support"
+  ],
+  "css/css-grid/grid-items/grid-item-overflow-auto-max-height-percentage.html": [
+   "62273b87e49170853bc14e36ecc3fb7b148ff6ac",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-item-percentage-sizes-001-ref.html": [
+   "109087157512a0dbd7a20c408a8927a828eafae1",
+   "support"
+  ],
+  "css/css-grid/grid-items/grid-item-percentage-sizes-001.html": [
+   "97532e495c1fd71adbbbcc12642dcd313848fae7",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-item-percentage-sizes-002-ref.html": [
+   "568642631b1ddc557cf57e2bb7039919f1ac1152",
+   "support"
+  ],
+  "css/css-grid/grid-items/grid-item-percentage-sizes-002.html": [
+   "2ceba537f0ccd4366cd4b7e1e691bb2d5f1e5a52",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-item-percentage-sizes-003-ref.html": [
+   "41070a8f013c0ae4a5094d0c3d32aa1fda834bca",
+   "support"
+  ],
+  "css/css-grid/grid-items/grid-item-percentage-sizes-003.html": [
+   "fccf4fe0a6ed1f128ff7ec2b322a4a2916c873b1",
+   "reftest"
+  ],
   "css/css-grid/grid-items/grid-items-001.html": [
    "99701de8a365345decc575ee00a6270ec03d6433",
    "reftest"
@@ -362606,7 +363113,7 @@
    "support"
   ],
   "css/css-logical/META.yml": [
-   "98d838c04e110e484cae63998cf4ee6c2dd559ed",
+   "cf789d631b1f61c6fee66d29fc5984d155180702",
    "support"
   ],
   "css/css-logical/OWNERS": [
@@ -366246,7 +366753,7 @@
    "testharness"
   ],
   "css/css-position/META.yml": [
-   "00eb3b13129df2b90c59ba3f2b22fd9a4f1727e4",
+   "c1ce1ff602eee4668b9cb5d0168c4372193a8d3a",
    "support"
   ],
   "css/css-position/OWNERS": [
@@ -366930,7 +367437,7 @@
    "testharness"
   ],
   "css/css-properties-values-api/registered-property-initial.html": [
-   "82a012e2f68532761b18428c3eaed9479ec8c7e5",
+   "d35b14be569f3c74d0b3d04e98fed00ed2f956d5",
    "testharness"
   ],
   "css/css-properties-values-api/resources/utils.js": [
@@ -367790,7 +368297,7 @@
    "testharness"
   ],
   "css/css-scrollbars/META.yml": [
-   "9209d5d1f4174d1e22258c0571db89b51f4f3a59",
+   "f7c0439e202113c9611405ae967b33c2b12cfcee",
    "support"
   ],
   "css/css-scrollbars/auto-scrollbar-inline-children.html": [
@@ -367942,7 +368449,7 @@
    "support"
   ],
   "css/css-shapes/META.yml": [
-   "99136818e66dc50978bc0f7c25a2129556e72f21",
+   "2e433aa66f914de66e36f0f4f99237254a7def29",
    "support"
   ],
   "css/css-shapes/OWNERS": [
@@ -369366,7 +369873,7 @@
    "reftest"
   ],
   "css/css-sizing/range-percent-intrinsic-size-2-ref.html": [
-   "83eff4b45c2c1e1b53be64242775e8a6016ffe1c",
+   "207b60d8f27ad3b1bb2b24a866d5de38807256e6",
    "support"
   ],
   "css/css-sizing/range-percent-intrinsic-size-2.html": [
@@ -369374,7 +369881,7 @@
    "reftest"
   ],
   "css/css-sizing/range-percent-intrinsic-size-2a-ref.html": [
-   "815b0a1021cb9113c39fad85b5052429dc74533f",
+   "861d34c6a08d21fd9145a9697660646f31eda02d",
    "support"
   ],
   "css/css-sizing/range-percent-intrinsic-size-2a.html": [
@@ -369402,7 +369909,7 @@
    "reftest"
   ],
   "css/css-style-attr/META.yml": [
-   "72438735ccd461ff343a0891348dc5810e41416a",
+   "067e03cfbc7376daf0e1b5eba0dc1c35e21fe69f",
    "support"
   ],
   "css/css-style-attr/reference/ref-green-on-green.xht": [
@@ -369646,7 +370153,7 @@
    "support"
   ],
   "css/css-syntax/META.yml": [
-   "17489e1bc2132f4c2acbc4ec901eccb8f7e4d365",
+   "359219c09965b90066e4fb31d952d621d0d0dc5b",
    "support"
   ],
   "css/css-syntax/OWNERS": [
@@ -370886,7 +371393,7 @@
    "reftest"
   ],
   "css/css-text/META.yml": [
-   "042b858557d9e6fc66a12e96724b69a02c314d47",
+   "e7914c0fc7ff9e6999f8847dc1800968472483f2",
    "support"
   ],
   "css/css-text/OWNERS": [
@@ -373421,6 +373928,10 @@
    "6dc1b4dff52459d7f5516da64f4e09be313257d1",
    "reftest"
   ],
+  "css/css-text/overflow-wrap/overflow-wrap-break-word-007.html": [
+   "0491b921e1aed4b030ca5cf0214afad7bdf3aba1",
+   "reftest"
+  ],
   "css/css-text/overflow-wrap/overflow-wrap-break-word-fit-content-001.html": [
    "2c83c46aa50f6d51efbb4d05635d86f7c166042d",
    "reftest"
@@ -375637,6 +376148,10 @@
    "de69880ed43c499974e60eafd3d135b6fb5b6632",
    "reftest"
   ],
+  "css/css-text/white-space/pre-wrap-008.html": [
+   "1ddbb7fe356e2cd9af2a35aa848541db2ab8fe23",
+   "reftest"
+  ],
   "css/css-text/white-space/pre-wrap-011.html": [
    "5f86cff5b3889ea1a810b30c14d680c4fa7dbcae",
    "reftest"
@@ -376190,21 +376705,25 @@
    "reftest"
   ],
   "css/css-text/word-break/word-break-break-all-011.html": [
-   "fade439dd9a9d4505e3ab7b9060a2f962eb6fd95",
+   "74ca60503f6eb76678ec6d94c8e7f9a2349cfcd4",
    "reftest"
   ],
   "css/css-text/word-break/word-break-break-all-012.html": [
-   "cd3d44056ec9715c0a9599bf5b7cad180620af74",
+   "6cbcbad92c4483021d645a3ba529a4441c26ba7d",
    "reftest"
   ],
   "css/css-text/word-break/word-break-break-all-013.html": [
-   "85dce08b6418088292c50e30dab9f497b31fb6ac",
+   "5029e4d891b221eca7da7e4991ec0d1809ea4d03",
    "reftest"
   ],
   "css/css-text/word-break/word-break-break-all-014.html": [
    "674b0545e05a5d25f056ac9850abd11791de6a58",
    "reftest"
   ],
+  "css/css-text/word-break/word-break-break-all-015.html": [
+   "9602a1f2cf0bab45bc7f70dbe3fa0aeb75d6df79",
+   "reftest"
+  ],
   "css/css-text/word-break/word-break-break-all-020.html": [
    "ac1840131c3f214b993ffd58dcd2124523f89b6b",
    "reftest"
@@ -376386,7 +376905,7 @@
    "reftest_node"
   ],
   "css/css-transforms/META.yml": [
-   "33c1fce3379cc08c33a5641ea0b88864735dcd0c",
+   "b948e3a31ed377091417bbf32d02791965b15a92",
    "support"
   ],
   "css/css-transforms/OWNERS": [
@@ -379229,6 +379748,10 @@
    "ba46b847a34aa1f7dde3b46c457e7292d4c7a016",
    "support"
   ],
+  "css/css-transforms/transform-flattening-001.html": [
+   "85d29779b5aa9f0a4a6ee638aafedeb9fcd204a7",
+   "reftest"
+  ],
   "css/css-transforms/transform-generated-001-notref.html": [
    "f0c2792682a4fd0a884552f266fa9269d2836e26",
    "support"
@@ -384306,7 +384829,7 @@
    "testharness"
   ],
   "css/css-ui/META.yml": [
-   "e78564bcc0d50add555e6767a596662e3c303c6e",
+   "7ce4b54a22c78576dc2318ebd651dfd1cce374ad",
    "support"
   ],
   "css/css-ui/OWNERS": [
@@ -387818,7 +388341,7 @@
    "reftest"
   ],
   "css/css-writing-modes/META.yml": [
-   "c74fff07de51aa354967058536c882ce515be8df",
+   "c11da73b6b438ca69cc6425f5118a4f9aa36a34f",
    "support"
   ],
   "css/css-writing-modes/OWNERS": [
@@ -396682,7 +397205,7 @@
    "support"
   ],
   "css/selectors/META.yml": [
-   "3f86842591ed35be1b36757e58e900899e8e0627",
+   "8e506d671d4b1e741d3450bd66603edbb3de9f30",
    "support"
   ],
   "css/selectors/OWNERS": [
@@ -403942,7 +404465,7 @@
    "testharness"
   ],
   "device-memory/META.yml": [
-   "b393c6b8337c09b3a7f140520319e61d3acbf56d",
+   "b8dd4761adff3e18b6552d4a8f02abdcd30a3ea6",
    "support"
   ],
   "device-memory/OWNERS": [
@@ -406637,6 +407160,10 @@
    "f127152cf8693481703e5a38306204232e4a9ce5",
    "testharness"
   ],
+  "element-timing/observe-video-poster.html": [
+   "40961382ffba6b828ac551cc046265de7d89eac1",
+   "testharness"
+  ],
   "element-timing/progressively-loaded-image.html": [
    "cf54e1e5c7a281bc59ba4172cd8ee3d7efdab099",
    "testharness"
@@ -408018,7 +408545,7 @@
    "testharness"
   ],
   "encrypted-media/META.yml": [
-   "3168f7d96f847daf23d9f859e548cb07b0f1c74c",
+   "b09e3b3c4e860bb92f1bc434c2f13462085f0af2",
    "support"
   ],
   "encrypted-media/OWNERS": [
@@ -408886,7 +409413,7 @@
    "support"
   ],
   "event-timing/META.yml": [
-   "feede41dcef66e8842a081b6053b4e57515f9c1c",
+   "aa27fb61c310d91b629ff0d7b19cd01ce469e645",
    "support"
   ],
   "event-timing/event-timing-bufferbeforeonload.html": [
@@ -409278,7 +409805,7 @@
    "testharness"
   ],
   "feature-policy/META.yml": [
-   "44ab62ca7243653c47ae8d887f7b4c9697718c0f",
+   "a4136f77e3fbd8524939de235eaff9c0211bfdba",
    "support"
   ],
   "feature-policy/OWNERS": [
@@ -410005,6 +410532,18 @@
    "59652e2e7ae0056a6cc4be7f004b6d0151fb9d44",
    "support"
   ],
+  "feature-policy/resources/feature-policy-idle-detection-worker.html": [
+   "1ef5298abf1b2062f98c8aba5675decd36c5313d",
+   "support"
+  ],
+  "feature-policy/resources/feature-policy-idle-detection-worker.js": [
+   "c6b8a7c88729c4106db162a9850b92e74b92d6ed",
+   "support"
+  ],
+  "feature-policy/resources/feature-policy-idle-detection.html": [
+   "e542e3b8912228e87bf6265bbab803dfe2756b1e",
+   "support"
+  ],
   "feature-policy/resources/feature-policy-nested-subframe-policy.https.sub.html": [
    "3d9530c26f668a0ca37464b052e5940a79b1197c",
    "support"
@@ -412774,7 +413313,7 @@
    "support"
   ],
   "gamepad/META.yml": [
-   "5f99b9db8eb163c24bf9a330039a8a7a1659ba6d",
+   "b008a9e614c1454e9b127b4d59a0d54cea2385bc",
    "support"
   ],
   "gamepad/OWNERS": [
@@ -412794,7 +413333,7 @@
    "testharness"
   ],
   "generic-sensor/META.yml": [
-   "1cfe809776ba04c66560bc9ef6cce0aa476b7082",
+   "bf48f80f8083f0ca13f432d16a7b3b22b3435526",
    "support"
   ],
   "generic-sensor/OWNERS": [
@@ -413110,7 +413649,7 @@
    "manual"
   ],
   "gyroscope/META.yml": [
-   "67f22d5374b0385db98fc885918d3b2f23a2f66b",
+   "6a48535e3c7416eb1d54b1a6e6837230ba498b39",
    "support"
   ],
   "gyroscope/OWNERS": [
@@ -413190,7 +413729,7 @@
    "testharness"
   ],
   "html-media-capture/META.yml": [
-   "706dbdf8b6a4bebc09ba4e988936194b8e9a62a2",
+   "3dd015f3ecb7d95f6677031448823cf5028f546f",
    "support"
   ],
   "html-media-capture/OWNERS": [
@@ -413762,7 +414301,7 @@
    "support"
   ],
   "html/browsers/browsing-the-web/read-media/pageload-image-in-popup.html": [
-   "4d811199b146ec49a5425c6dadee81a51fc1a8c1",
+   "e9284824f44f2daf663a4155ebf7c203a7e39290",
    "testharness"
   ],
   "html/browsers/browsing-the-web/read-media/pageload-image.html": [
@@ -415425,6 +415964,10 @@
    "88a3beba6f10b80b0b90acdc0b0f957e1a17cefc",
    "testharness"
   ],
+  "html/browsers/the-window-object/document-attribute.window.js": [
+   "f13acdb8a3261410c0f3100fea49f1ba110ea9ab",
+   "testharness"
+  ],
   "html/browsers/the-window-object/focus.window.js": [
    "6ec7feee281e756ae6452e0f9b17d9b93032d010",
    "testharness"
@@ -415533,6 +416076,10 @@
    "1fb0ed7c1e62da55b890c6434bee6e46637e0209",
    "testharness"
   ],
+  "html/browsers/the-window-object/self-et-al.window.js": [
+   "1b0fa1211a701253b61d1eced344faa8763ad6ef",
+   "testharness"
+  ],
   "html/browsers/the-window-object/support/closed.html": [
    "3b70598e34d0e9b46a8ba2150a1589fecfb90ea8",
    "support"
@@ -426361,34 +426908,18 @@
    "f37bc33f6f93ca94940ffeb0066945eb9aa020ee",
    "testharness"
   ],
-  "html/semantics/forms/form-submission-target/rel-base-target-expected.txt": [
-   "6d848622efe8cf1ac7a49ac1f458517e51147db8",
-   "support"
-  ],
   "html/semantics/forms/form-submission-target/rel-base-target.html": [
    "222be95d2e8a9da39525fbf6d8048e6cdfd7a982",
    "testharness"
   ],
-  "html/semantics/forms/form-submission-target/rel-button-target-expected.txt": [
-   "c2ff926d578885e946f148903c330ac2a878e380",
-   "support"
-  ],
   "html/semantics/forms/form-submission-target/rel-button-target.html": [
    "76fa8685905ad233f9312be3f6bf09503158a666",
    "testharness"
   ],
-  "html/semantics/forms/form-submission-target/rel-form-target-expected.txt": [
-   "88e33b90d9131401e3e53638d311198e3ff3ae2c",
-   "support"
-  ],
   "html/semantics/forms/form-submission-target/rel-form-target.html": [
    "58611f41a9fdaea1611513e02dad87e017728f9a",
    "testharness"
   ],
-  "html/semantics/forms/form-submission-target/rel-input-target-expected.txt": [
-   "b67908139dc6327eabc12a1a5da4b6f4c61de6eb",
-   "support"
-  ],
   "html/semantics/forms/form-submission-target/rel-input-target.html": [
    "b80e0240bae3802b04118249ec2b94e16a91e9e6",
    "testharness"
@@ -432541,6 +433072,34 @@
    "ef5de2164ed8d58fd27bcbd92eb891892ad28e25",
    "testharness"
   ],
+  "idle-detection/idle-detection-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html": [
+   "f8f57348dfa10cf671f82902f4ec7d4ca5fcd7c6",
+   "testharness"
+  ],
+  "idle-detection/idle-detection-allowed-by-feature-policy-attribute.https.sub.html": [
+   "422c45c3de6a74134be261142d455a2003a30999",
+   "testharness"
+  ],
+  "idle-detection/idle-detection-allowed-by-feature-policy.https.sub.html": [
+   "3c019b7e0e476b82e812a3821119c0365eee2fd2",
+   "testharness"
+  ],
+  "idle-detection/idle-detection-allowed-by-feature-policy.https.sub.html.headers": [
+   "729e9429e6a4ad7375474297d4fd7e7599eb04e0",
+   "support"
+  ],
+  "idle-detection/idle-detection-default-feature-policy.https.sub.html": [
+   "7ecf7a4f67700fa86fea55d744656875f1960820",
+   "testharness"
+  ],
+  "idle-detection/idle-detection-disabled-by-feature-policy.https.sub.html": [
+   "cb455f40bab08010511f17eea4b764872bfbf9b1",
+   "testharness"
+  ],
+  "idle-detection/idle-detection-disabled-by-feature-policy.https.sub.html.headers": [
+   "f27e1a262717ea1ed666f59035a88a1d481a7460",
+   "support"
+  ],
   "idle-detection/idle-detection.idl": [
    "4b502c975ce3b25a94518ce5d98c842b57c6a70d",
    "support"
@@ -432557,8 +433116,16 @@
    "d88d1ad1c55afaee243e1e9146827b073c380613",
    "support"
   ],
+  "idle-detection/resources/idle-detection-allowed-by-feature-policy-worker.js": [
+   "103ce5e9bdb0fae14cd88b4f760c93afce47ae2b",
+   "support"
+  ],
+  "idle-detection/resources/idle-detection-disabled-by-feature-policy-worker.js": [
+   "66218a5c4420b5644ddefa276fb52f2718907525",
+   "support"
+  ],
   "imagebitmap-renderingcontext/META.yml": [
-   "f6a06f4e7d7625855e271ec5422629ca5e734560",
+   "4239a85f5eeb8de0660d138c5a3d48a17545a9eb",
    "support"
   ],
   "imagebitmap-renderingcontext/OWNERS": [
@@ -434430,7 +434997,7 @@
    "support"
   ],
   "lint.whitelist": [
-   "85d31ced2d6879dd162d4cd3f50229bf851e7f7b",
+   "12b32126b6677b19836943aee6c604296f9a597d",
    "support"
   ],
   "loading/preloader-css-import-no-quote.tentative.html": [
@@ -434534,7 +435101,7 @@
    "testharness"
   ],
   "magnetometer/META.yml": [
-   "88b900c569340a167ac2a8aa967099bfdfff388b",
+   "d7d395ee8f2a942327858b189dd8a6b2a249c14e",
    "support"
   ],
   "magnetometer/Magnetometer-disabled-by-feature-policy.https-expected.txt": [
@@ -434670,11 +435237,11 @@
    "reftest"
   ],
   "mathml/presentation-markup/fractions/frac-linethickness-001-ref.html": [
-   "c703edb764fe883e05e47e26464149aa64af1070",
+   "d4be8ea03bfc29506af0e26a3d94d5eeafaaf472",
    "support"
   ],
   "mathml/presentation-markup/fractions/frac-linethickness-001.html": [
-   "83e15c83dc0bcb911eb52a6b74b86a13c2f1e31e",
+   "eca82878caec21ea50ed0d3562ac3449e54c7567",
    "reftest"
   ],
   "mathml/presentation-markup/fractions/frac-linethickness-002-ref.html": [
@@ -435862,7 +436429,7 @@
    "support"
   ],
   "mediacapture-depth/META.yml": [
-   "e083c9b8c3ab0b20b24976d8ab94f5d04fb243dd",
+   "434612091df41dcf66859c46c66ed8cdaa6ba316",
    "support"
   ],
   "mediacapture-depth/dictionary-helper.js": [
@@ -436126,7 +436693,7 @@
    "testharness"
   ],
   "mediacapture-streams/META.yml": [
-   "1ed650e97c451ef1266fd8435e2260d6bf617b67",
+   "960dc3a5ac47e9c14e8651504cb8057242f7a3be",
    "support"
   ],
   "mediacapture-streams/MediaDevices-IDL-all-expected.txt": [
@@ -436242,7 +436809,7 @@
    "manual"
   ],
   "mediacapture-streams/MediaStreamTrack-getCapabilities.https-expected.txt": [
-   "c245e7eb9b089b3a9fe1d272215dc969054323c7",
+   "e7f474c303398f0d34de45d621f6b87dfe4da808",
    "support"
   ],
   "mediacapture-streams/MediaStreamTrack-getCapabilities.https.html": [
@@ -439133,6 +439700,10 @@
    "74b85c9dbb5e03266c0ba0145ad45d67a025fd0c",
    "testharness"
   ],
+  "navigation-timing/nav2_test_redirect_chain_xserver_partial_opt_in.html": [
+   "c0dd249545a640ec0cdd759b2114ab725a609039",
+   "testharness"
+  ],
   "navigation-timing/nav2_test_redirect_none.html": [
    "97437e1a5ef2b61ae65762bfa351630eb4714cdf",
    "testharness"
@@ -439161,6 +439732,14 @@
    "fb7247d10b7566a93b955e0b9145e3089f329cf4",
    "testharness"
   ],
+  "navigation-timing/nav2_test_unloadEvents_with_cross_origin_redirect_chain_partial_opt_in.html": [
+   "0b3978641b9a74f7f9d85c50cefe48210a8f1473",
+   "testharness"
+  ],
+  "navigation-timing/nav2_test_unloadEvents_with_cross_origin_redirect_opt_in.html": [
+   "d3ff55087a1715f14a6b089b7bf80e8037ae8a1a",
+   "testharness"
+  ],
   "navigation-timing/nav2_test_unloadEvents_with_cross_origin_redirects.html": [
    "8a7f57d746009367d099d141620bcfdfd88acc7d",
    "testharness"
@@ -439418,7 +439997,7 @@
    "support"
   ],
   "notifications/META.yml": [
-   "2cb7972705c7b9ef00375dfa4258e92edb15fb21",
+   "0daa86e6f487e90830b400bf7f2b871700d024b8",
    "support"
   ],
   "notifications/OWNERS": [
@@ -439546,7 +440125,7 @@
    "manual"
   ],
   "offscreen-canvas/META.yml": [
-   "bcb30ed276642fbbe2d055c6a1d131e097daac69",
+   "d3e4c387e8b5b9d27ea3dea6febdc1d9a662e4f0",
    "support"
   ],
   "offscreen-canvas/OWNERS": [
@@ -446078,7 +446657,7 @@
    "testharness"
   ],
   "orientation-sensor/META.yml": [
-   "99d6166664ca11196582e9bd058d225df833a4e2",
+   "427385826fca7a770a816abc5d98cc324f647f68",
    "support"
   ],
   "orientation-sensor/OWNERS": [
@@ -446270,7 +446849,7 @@
    "testharness"
   ],
   "paint-timing/META.yml": [
-   "24acb2587d1a375bfee12c56c56dd457ee6152cd",
+   "1892a41ed1cffcc8ba704f28bd59f5aa64c2b46a",
    "support"
   ],
   "paint-timing/OWNERS": [
@@ -446494,7 +447073,7 @@
    "testharness"
   ],
   "payment-method-id/META.yml": [
-   "e0931f4f8f584199e85f31501cc6a717e57fe4ab",
+   "5e9fe05abae6f862301ef85f9905d91eb4e42121",
    "support"
   ],
   "payment-method-id/OWNERS": [
@@ -446534,7 +447113,7 @@
    "support"
   ],
   "payment-request/PaymentAddress/attributes-and-toJSON-method-manual.https.html": [
-   "45f3f0a5672cf64501718aa43dc5aac87249bab9",
+   "226fd88ff84ab58baa39da7f0691b18c50b3ff72",
    "manual"
   ],
   "payment-request/PaymentCurrencyAmount/currencySystem-member.https-expected.txt": [
@@ -446834,7 +447413,7 @@
    "manual"
   ],
   "payment-request/payment-response/onpayerdetailchange-attribute-manual.https.html": [
-   "c8dd92636c6392b2436c8235340355c4529e12c1",
+   "f3f3f76357c1467f4032c5749849bd0063b41010",
    "manual"
   ],
   "payment-request/payment-response/onpayerdetailchange-attribute.https.html": [
@@ -446914,7 +447493,7 @@
    "support"
   ],
   "payment-request/show-method-postmessage-manual.https.html": [
-   "05fce4f248e8ff116065988d1d4d3d2875967ce5",
+   "920e0a9992eba1f604d5d0246f1c7e7e7b42bd1d",
    "manual"
   ],
   "payment-request/updateWith-method-pmi-handling-manual.https.html": [
@@ -447102,7 +447681,7 @@
    "testharness"
   ],
   "pointerevents/META.yml": [
-   "be61ddddaf62acb3396ada6779ad3f50e6caa709",
+   "1962feaf8af08b003e519fa525271e70451984d5",
    "support"
   ],
   "pointerevents/OWNERS": [
@@ -447517,13 +448096,13 @@
    "f176343a487de4d71bda196657c7958ac62f1553",
    "testharness"
   ],
-  "pointerlock/mouse_buttons_back_forward-manual.html": [
-   "4515ebabcbd3dfef30b89512609078b7d89a2a92",
-   "manual"
+  "pointerlock/mouse_buttons_back_forward.html": [
+   "95490d2d4df442bba56aed62205bdf3bc34e55a3",
+   "testharness"
   ],
-  "pointerlock/movementX_Y_basic-manual.html": [
-   "083b7075decf4ecaf782e319139fb52b07fdafe9",
-   "manual"
+  "pointerlock/movementX_Y_basic.html": [
+   "b09d896ecfb90eea17c294c77582ba53b07283da",
+   "testharness"
   ],
   "pointerlock/movementX_Y_no-jumps-manual.html": [
    "11b8d2a49e0a3b59b76174e652b55ef7d5bf939e",
@@ -447549,17 +448128,17 @@
    "8373a345ea03ca44812efbe6cb2b1d1054050b3e",
    "manual"
   ],
-  "pointerlock/pointerlock_remove_target-manual.html": [
-   "a38b06e120535c12f3c93fa2bc035ff46541325e",
-   "manual"
+  "pointerlock/pointerlock_remove_target.html": [
+   "0ffc9d10a0acd1f026b0e34e8392a8a5408fed84",
+   "testharness"
   ],
-  "pointerlock/pointerlock_remove_target_on_mouseup-manual.html": [
-   "71b9eb693713556a7cf263c8a9cc00880e57758c",
-   "manual"
+  "pointerlock/pointerlock_remove_target_on_mouseup.html": [
+   "4f7a15309c97cc91ec990be25bb803a85bb9c92c",
+   "testharness"
   ],
-  "pointerlock/pointerlock_shadow-manual.html": [
-   "8e70915bb89740cb4edfe6a0b92057900bd294db",
-   "manual"
+  "pointerlock/pointerlock_shadow.html": [
+   "21f3a928cd410471aa7fd32b6a7d427535007041",
+   "testharness"
   ],
   "portals/META.yml": [
    "2b3241dd18b60e7e5343aa46d31253f12d415cd1",
@@ -447569,6 +448148,10 @@
    "29134d490f7bdfb09255e190fe91576629057c78",
    "support"
   ],
+  "portals/portal-activate-data.html": [
+   "e2417cb7332010cccd66435743f300313614c0e6",
+   "testharness"
+  ],
   "portals/portal-activate-event.html": [
    "33d91e37d9d9ac77c5243a60b42ce841645d248e",
    "testharness"
@@ -447613,6 +448196,10 @@
    "4a8414ab5656593811772c3728e4ee83eb034457",
    "support"
   ],
+  "portals/resources/portal-activate-data-portal.html": [
+   "cba38a005f57a547c984db0152c918046ced471d",
+   "support"
+  ],
   "portals/resources/portal-activate-event-portal.html": [
    "b2759c3701aaba4f5887a8b90bf4ee30e8153661",
    "support"
@@ -448310,7 +448897,7 @@
    "support"
   ],
   "referrer-policy/META.yml": [
-   "a622289c0562dbac99de0a9dbd3b9a70e0783923",
+   "8ead043aad0a6aa79dad5c2c9e9b757df5869265",
    "support"
   ],
   "referrer-policy/OWNERS": [
@@ -457382,7 +457969,7 @@
    "testharness"
   ],
   "resource-timing/META.yml": [
-   "a2ce7c48f501436168ab93f791f1964e91a14fef",
+   "76176970d4d93e6a66bf2bc62aec5dd62ccd12c1",
    "support"
   ],
   "resource-timing/OWNERS": [
@@ -457393,6 +457980,10 @@
    "26e0a8017d6c2c7b51c94998f34a79fa20eb1e12",
    "support"
   ],
+  "resource-timing/TAO-crossorigin-port.sub.html": [
+   "0601217d0ae3a7bc057853dd23901650ccfe4633",
+   "testharness"
+  ],
   "resource-timing/buffer-full-add-after-full-event.html": [
    "73ad841e92fddff1e05395241d69a0079e7a84da",
    "testharness"
@@ -457449,6 +458040,10 @@
    "a7542f191c10ea7b42110b5fc80e7abf43174bb5",
    "testharness"
   ],
+  "resource-timing/nested-context-navigations.html": [
+   "483cc5b82d5debf942dd0013a340f9d5f550834c",
+   "testharness"
+  ],
   "resource-timing/no-entries-for-cross-origin-css-fetched.sub-expected.txt": [
    "a256bb2dc766a40f21115049572246bf003499ba",
    "support"
@@ -457565,14 +458160,14 @@
    "9912da7c3400138d73245acc372463ca174e6f58",
    "testharness"
   ],
-  "resource-timing/resource_memory_cached.sub.html": [
-   "89b5874978c97cd25e31da263d07c9f91c69bbfa",
-   "testharness"
-  ],
   "resource-timing/resource_reparenting.html": [
    "7d4947fa7703d13a5adb465ff5eebbb4456cace9",
    "testharness"
   ],
+  "resource-timing/resource_reuse.sub.html": [
+   "ff69a2ce73d1fee315ac1134cdbc5c1ff6ccf9fd",
+   "testharness"
+  ],
   "resource-timing/resource_script_types.html": [
    "898fa0cee2cb29f69c11d70d831c2eade5b75036",
    "testharness"
@@ -457610,7 +458205,7 @@
    "testharness"
   ],
   "resource-timing/resources/TAOResponse.py": [
-   "fefc75b7b7fc68872b36f56bcb0fa59dd41d2918",
+   "d98098ccc83e56bfba7f48ae5dc39ffd6e9b969f",
    "support"
   ],
   "resource-timing/resources/all_resource_types.htm": [
@@ -457641,6 +458236,34 @@
    "fbd7bc3b6e21ee39478c8a63780bb673dafe96a4",
    "support"
   ],
+  "resource-timing/resources/document-navigated.html": [
+   "fa87355c3ed18f5011146a373c4029d3272bb6a8",
+   "support"
+  ],
+  "resource-timing/resources/document-refreshed.html": [
+   "7e4ca09891ed35e244b15151a2a6077af74e865f",
+   "support"
+  ],
+  "resource-timing/resources/document-that-navigates.html": [
+   "cb567bf3d2ad12154155aef6ad1da7be2a1f3d78",
+   "support"
+  ],
+  "resource-timing/resources/document-that-refreshes.html": [
+   "75522782a62dbe3b98b2f1a09c5babc7063b7510",
+   "support"
+  ],
+  "resource-timing/resources/embed-navigate-back.html": [
+   "3c3def1d1a1d04279ad2bbceb220879398943681",
+   "support"
+  ],
+  "resource-timing/resources/embed-navigate.html": [
+   "20a73c662b4f7b00daa96feda64cde16fc6a6490",
+   "support"
+  ],
+  "resource-timing/resources/embed-refresh.html": [
+   "4a49fd0b4c1b54c0f03200f7ed2cb2ae27239788",
+   "support"
+  ],
   "resource-timing/resources/empty.js": [
    "3b44754e301ded90e559f6343df641e476803542",
    "support"
@@ -457681,6 +458304,22 @@
    "31a769eb3666492a3804f1c3deca73df526c0a4f",
    "support"
   ],
+  "resource-timing/resources/iframe-TAO-crossorigin-port.sub.html": [
+   "39f5d13054a79281ed0131315f834645e6e7790c",
+   "support"
+  ],
+  "resource-timing/resources/iframe-navigate-back.html": [
+   "c5c1fc1ad4dfaaedc441ae8854079402e56d1106",
+   "support"
+  ],
+  "resource-timing/resources/iframe-navigate.html": [
+   "2a1a7e063619fe62c7acf87b99acda26d2cbcf32",
+   "support"
+  ],
+  "resource-timing/resources/iframe-refresh.html": [
+   "4ce3ea0424297ac7a8664fc7f7a6dcbff64d6f14",
+   "support"
+  ],
   "resource-timing/resources/iframe-reload-TAO.sub.html": [
    "577aff7758c779893f010658d216f34802a4edfe",
    "support"
@@ -457737,6 +458376,14 @@
    "d1802a1e02d9aacad091e814cc2955d244d2f977",
    "support"
   ],
+  "resource-timing/resources/navigate_back.html": [
+   "345eee1fccca5cf2ea94865a41a41f6e897ede15",
+   "support"
+  ],
+  "resource-timing/resources/nested-contexts.js": [
+   "0c202243702aec81426a2dfbca05ce1118c5978b",
+   "support"
+  ],
   "resource-timing/resources/nested.css": [
    "90d61b04acc4443430c42331d8c7f21993b0ae4d",
    "support"
@@ -457745,6 +458392,18 @@
    "c104f3c8f0695a96646cf24a730eef0342f95876",
    "support"
   ],
+  "resource-timing/resources/object-navigate-back.html": [
+   "64e5f584731fdf5fe89e8e60e19fea6bd0f24125",
+   "support"
+  ],
+  "resource-timing/resources/object-navigate.html": [
+   "cbb862e7e00fcb7391107fdfe7e7870388f62a4a",
+   "support"
+  ],
+  "resource-timing/resources/object-refresh.html": [
+   "b14cf7f17c9d807eaa904f92d170e9ee96435464",
+   "support"
+  ],
   "resource-timing/resources/resource_timing_test0.css": [
    "8bc8326ba675adcc8aa809dd0b885dba3285782d",
    "support"
@@ -457838,7 +458497,7 @@
    "support"
   ],
   "resources/chromium/device.mojom.js": [
-   "436d3038b85e4d6f92fa25cd93a41af667e85d26",
+   "6488cbc69c29170d9441d2210da27a464f67d445",
    "support"
   ],
   "resources/chromium/device.mojom.js.headers": [
@@ -457966,7 +458625,7 @@
    "support"
   ],
   "resources/chromium/webusb-test.js": [
-   "18ee824aafaf45087f4b0aa2d6e90811cb39a751",
+   "c4d4e8f1ac47a2f8c5ea02fa737a01b36aca6329",
    "support"
   ],
   "resources/chromium/webusb-test.js.headers": [
@@ -458118,7 +458777,7 @@
    "testharness"
   ],
   "screen-orientation/META.yml": [
-   "dc3f290196fabe6e4594a498282fc0091134bdad",
+   "3ddb3b0507d54269c54a552227771a0bf9131a0e",
    "support"
   ],
   "screen-orientation/OWNERS": [
@@ -458153,6 +458812,14 @@
    "1041f91886a87083ed78227e15badb071395dfb4",
    "testharness"
   ],
+  "screen-orientation/lock-unlock-check-expected.txt": [
+   "b4d17d2d48a94dffc0320236cad946850ec094e2",
+   "support"
+  ],
+  "screen-orientation/lock-unlock-check.html": [
+   "129882d64f6d323d93a183d59f4744a8e888d3f1",
+   "testharness"
+  ],
   "screen-orientation/onchange-event-expected.txt": [
    "76af39c5c08a2a59d1699fe78e04253db0db86a3",
    "support"
@@ -458181,12 +458848,16 @@
    "4cfd37d02bc58f2bed39075357b393fea769a155",
    "support"
   ],
+  "screen-orientation/resources/orientation-utils.js": [
+   "8721818bec2fadcaa3010f3c48d9e38db854f669",
+   "support"
+  ],
   "screen-orientation/resources/sandboxed-iframe-locking.html": [
    "e1b50f670105f3a05dacd3518d62770685121c67",
    "support"
   ],
   "scroll-animations/META.yml": [
-   "20f3c7e6c930193207c6cbcd329e36f85a993dc9",
+   "c53f1f432fe1ec2887e30af396a1f1574b76b95d",
    "support"
   ],
   "scroll-animations/constructor-expected.txt": [
@@ -458341,8 +459012,12 @@
    "faed70a5c863fb31572f069d598caccab3a00a03",
    "support"
   ],
+  "selection/Document-open-expected.txt": [
+   "eaa85d4992385b5f5265eff529ceaedff9ed7c84",
+   "support"
+  ],
   "selection/Document-open.html": [
-   "9d170914e6516b2829f1872e001dd4cd08e30b4c",
+   "9e3cb28124c0d65f61d1e71672c2429a3b64a792",
    "testharness"
   ],
   "selection/META.yml": [
@@ -462642,7 +463317,7 @@
    "support"
   ],
   "shape-detection/idlharness.any-expected.txt": [
-   "a2c26dcade6fe6ec10970115f2ce39faf5a7afa2",
+   "da45152cbbb78189eb3a5c1d95f5020e0266f383",
    "support"
   ],
   "shape-detection/idlharness.any.js": [
@@ -462814,7 +463489,7 @@
    "support"
   ],
   "signed-exchange/resources/generate-test-sxgs.sh": [
-   "60746ff34caaec9e83942aeae6a6cc74aa8138e0",
+   "e76286be991ca3d3832f767a5ab7aab172157184",
    "support"
   ],
   "signed-exchange/resources/inner-url.html": [
@@ -462829,6 +463504,18 @@
    "d581d5987ea0f9d7c8164d680a4527f2ea519cd4",
    "support"
   ],
+  "signed-exchange/resources/register-sw-after-fallback.html": [
+   "2711fc241f3215ff7e6649daefde40e7b2e147da",
+   "support"
+  ],
+  "signed-exchange/resources/register-sw.html": [
+   "8a3873bfde88dd9bd0cc979f3db6a7d88b776d22",
+   "support"
+  ],
+  "signed-exchange/resources/service-worker.js": [
+   "2647f45a3ea3e7e406305f41a3b4677b26ecd8e7",
+   "support"
+  ],
   "signed-exchange/resources/sxg-location.html": [
    "b3ebd2bde7acd2d1885838a37ab9cfc91c250551",
    "support"
@@ -462838,7 +463525,7 @@
    "support"
   ],
   "signed-exchange/resources/sxg-util.js": [
-   "7abb3cf2079087092ac4a7f7332ecf72f9cabd75",
+   "78edf137408f93150209f76b6e492d13805ca95a",
    "support"
   ],
   "signed-exchange/resources/sxg-version1b2.sxg": [
@@ -462873,6 +463560,14 @@
    "6d8538882d27c40b0ffcf0845c090844aaec87b7",
    "support"
   ],
+  "signed-exchange/resources/sxg/register-sw-after-fallback.sxg": [
+   "20ae275818765133e5018e0db2263cf21269d756",
+   "support"
+  ],
+  "signed-exchange/resources/sxg/register-sw-from-sxg.sxg": [
+   "792222029f1730c20c6673a9b89771c70226faea",
+   "support"
+  ],
   "signed-exchange/resources/sxg/sxg-cert-not-found-on-alt-origin.sxg": [
    "2a7dbf6fa69ae29055e51f6c7d32d3ab4ceb6765",
    "support"
@@ -462969,6 +463664,22 @@
    "ae96b7213fa7f3d056964a2eeab1528ff840486a",
    "support"
   ],
+  "signed-exchange/service-workers/sxg-sw-register-after-fallback.tentative.https-expected.txt": [
+   "7a8dbb39f3ab20ec490af6a4a60b349d0f09cd25",
+   "support"
+  ],
+  "signed-exchange/service-workers/sxg-sw-register-after-fallback.tentative.https.html": [
+   "2b76a70dc9feb2fe446fa309202494b172dcb04e",
+   "testharness"
+  ],
+  "signed-exchange/service-workers/sxg-sw-register.tentative.https-expected.txt": [
+   "c50ff44a931570ed8899d48654ffbd5d66b98ad4",
+   "support"
+  ],
+  "signed-exchange/service-workers/sxg-sw-register.tentative.https.html": [
+   "ad21ebb20d44c846bd99cbffeb510c8af2bb81ea",
+   "testharness"
+  ],
   "signed-exchange/sxg-double-prefetch.tentative.html": [
    "d682741744fed929bee8e62fbae4857a4bfbf1d5",
    "testharness"
@@ -463062,7 +463773,7 @@
    "testharness"
   ],
   "speech-api/META.yml": [
-   "4d1b42a44d2a6a447f8a47bc079d7e28436843e0",
+   "9ce8830e78fc4be5b25e5382248810932abfd829",
    "support"
   ],
   "speech-api/OWNERS": [
@@ -463250,7 +463961,7 @@
    "testharness"
   ],
   "streams/META.yml": [
-   "108c774fae6f0f56b562bfcd0823fab4709f36c5",
+   "1259a55cb5a99e3ba3a13d81d02dd78d697ddabf",
    "support"
   ],
   "streams/OWNERS": [
@@ -463734,7 +464445,7 @@
    "testharness"
   ],
   "subresource-integrity/META.yml": [
-   "2b8891ec6b498cc6b24df46e21fffad437732b54",
+   "f6980682f11bc29b19789c91a93d9e0f58383306",
    "support"
   ],
   "subresource-integrity/OWNERS": [
@@ -463926,7 +464637,7 @@
    "support"
   ],
   "svg/META.yml": [
-   "09ef583b72d7a204612e8f124404895137d80205",
+   "2904d6f606bfd2092952dcb7883d66afc9e9be8b",
    "support"
   ],
   "svg/OWNERS": [
@@ -465706,7 +466417,7 @@
    "support"
   ],
   "tools/ci/azure/affected_tests.yml": [
-   "17fca51d50cbd4f1986c63f3383b18dbdbe9c6fe",
+   "8076bc386986ed48a7af50fd48a59a544bf8c3bc",
    "support"
   ],
   "tools/ci/azure/checkout.yml": [
@@ -465830,7 +466541,7 @@
    "support"
   ],
   "tools/ci/taskcluster-run.py": [
-   "78c50a6285e81c8fa5e69585a28f04e957a59869",
+   "fbd2f2ab4ea0b27ffd1690d10d64f88937228d20",
    "support"
   ],
   "tools/ci/tcdownload.py": [
@@ -465910,7 +466621,7 @@
    "support"
   ],
   "tools/manifest/manifest.py": [
-   "7640136b21317f9c990a3021337146f03a796993",
+   "dc57c24ddb084e2af0eb93e6470f7e5024d6e469",
    "support"
   ],
   "tools/manifest/sourcefile.py": [
@@ -470102,7 +470813,7 @@
    "support"
   ],
   "tools/wpt/run.py": [
-   "df34e591568617616211e0f549872fe94c7568d8",
+   "a19851d14c5cd2a64355a4e0389ace0b7cbd022f",
    "support"
   ],
   "tools/wpt/testfiles.py": [
@@ -470122,7 +470833,7 @@
    "support"
   ],
   "tools/wpt/virtualenv.py": [
-   "61de936b7679e0f143d43278ad2494b34140b004",
+   "357ddcbefce1f9ed81324bab0bf2467f572b0753",
    "support"
   ],
   "tools/wpt/wpt.py": [
@@ -470142,7 +470853,7 @@
    "support"
   ],
   "tools/wptrunner/requirements.txt": [
-   "6216fb6708da3c60d6e2b0a60d92a232dc383b0f",
+   "f17b12b3dddffd988bf05b1255761b713e28ca49",
    "support"
   ],
   "tools/wptrunner/requirements_chrome.txt": [
@@ -470162,7 +470873,7 @@
    "support"
   ],
   "tools/wptrunner/requirements_firefox.txt": [
-   "ee84d840f814088fdb4607ff355096772894a987",
+   "668cea391543074722e19ad802ea189df84890c0",
    "support"
   ],
   "tools/wptrunner/requirements_ie.txt": [
@@ -471534,7 +472245,7 @@
    "testharness"
   ],
   "url/META.yml": [
-   "3a789a0d513f0a78bf362dd73c8a807d0cd55a50",
+   "094b266b64b61b97966f2fa88d78dfdf5a00b573",
    "support"
   ],
   "url/OWNERS": [
@@ -471834,7 +472545,7 @@
    "testharness"
   ],
   "vibration/META.yml": [
-   "016588931f9d1221bd9730605bd3d7abaeb069d7",
+   "91cd8c9d8056e8512e049280b7c1a43a76b3074f",
    "support"
   ],
   "vibration/OWNERS": [
@@ -472002,7 +472713,7 @@
    "support"
   ],
   "wake-lock/META.yml": [
-   "a5ff85281f875366aa3f22262e1a58beb60fe8f3",
+   "7ca3da2d8d2e4c90c55074246589d5464aa7ae3e",
    "support"
   ],
   "wake-lock/OWNERS": [
@@ -474182,7 +474893,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html": [
-   "2c1162d47b973937c826caba0c740f58970defcc",
+   "3e364eb7b359948402ef8ecdb287a5f55bb80fc3",
    "testharness"
   ],
   "webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/no-cors.https.html": [
@@ -475390,7 +476101,7 @@
    "testharness"
   ],
   "webmessaging/META.yml": [
-   "e70b780b57a659a928ce7575f19224dcce8087f9",
+   "95d5071171b5a20cc14a414c97c9eae2f525f43f",
    "support"
   ],
   "webmessaging/MessageEvent-trusted-worker.js": [
@@ -475958,7 +476669,7 @@
    "testharness"
   ],
   "webrtc/META.yml": [
-   "2025a11f3810042bcef24acae751ce5ffd3a3ee8",
+   "eed4ac834313773528e5665d80505cb4b951a1c9",
    "support"
   ],
   "webrtc/OWNERS": [
@@ -476198,7 +476909,7 @@
    "support"
   ],
   "webrtc/RTCPeerConnection-getStats.https.html": [
-   "247402b83be0a2655fa8d4ad43fa166b6459c587",
+   "c2c4e8e37176ce13447c1c8238aa6243f9aea130",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-getTransceivers.html": [
@@ -476238,11 +476949,11 @@
    "testharness"
   ],
   "webrtc/RTCPeerConnection-onnegotiationneeded-expected.txt": [
-   "086110186f91ea9336e73f0cc0bc1217aafef88a",
+   "62c3abf9a08a1fcbc0c5454a5b417ea4c85623e3",
    "support"
   ],
   "webrtc/RTCPeerConnection-onnegotiationneeded.html": [
-   "ac9d70c43eff1ddd0995dcea741f3b6ea850464b",
+   "f7bf8bd3e3bdc24c63a92da22eaae77b95f0d4fd",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-onsignalingstatechanged.https.html": [
@@ -476302,7 +477013,7 @@
    "testharness"
   ],
   "webrtc/RTCPeerConnection-setLocalDescription.html": [
-   "5e9b54389bf8ca762eeb95be275991f1f9291fd2",
+   "2becbd3e23efee6ee14988b770c34e8fba9d3455",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-setRemoteDescription-answer.html": [
@@ -476358,7 +477069,7 @@
    "testharness"
   ],
   "webrtc/RTCPeerConnection-transceivers.https.html": [
-   "f56a170616cca25d2619158a2f3894aeee59b95a",
+   "9b3a9a85413e2dcfdbcbbefe2b8b05a0ffd05ca0",
    "testharness"
   ],
   "webrtc/RTCPeerConnectionIceEvent-constructor-expected.txt": [
@@ -477726,7 +478437,7 @@
    "support"
   ],
   "webstorage/META.yml": [
-   "0da67a586b84030b835ddbdaa0af20ddadb8f4b3",
+   "020075c3f2401ca4b8da73116a84582d46e265c0",
    "support"
   ],
   "webstorage/OWNERS": [
@@ -481198,7 +481909,7 @@
    "support"
   ],
   "webxr/META.yml": [
-   "b5e3e65a12cb4124e43c4f24b7fca84910fda119",
+   "520afec2000721d04aae9ed89bca49297fa31d4b",
    "support"
   ],
   "webxr/OWNERS": [
@@ -481206,7 +481917,7 @@
    "support"
   ],
   "webxr/idlharness.https.window-expected.txt": [
-   "c491e806fb5c5c9aed9f7cad7e6cc65e080b8350",
+   "979535e73edb7d4bb6aafa38d5e418f420c4ec14",
    "support"
   ],
   "webxr/idlharness.https.window.js": [
@@ -481221,6 +481932,10 @@
    "2d8e5b387dc88588921ccfa49dd14db58009900c",
    "support"
   ],
+  "webxr/resources/webxr_math_utils.js": [
+   "bb55fb72978690427aac38b84d1eac24e838d0eb",
+   "support"
+  ],
   "webxr/resources/webxr_test_asserts.js": [
    "2253ffc2d39d268142711fca7f81dda3fc6a318c",
    "support"
@@ -481290,13 +482005,17 @@
    "testharness"
   ],
   "webxr/xrRay_matrix.https.html": [
-   "3c9cea0849f77063d3c86eff7f2d85e4830c851c",
+   "85d7bffb87b731f6a863ec752ede5ceac3bfca16",
    "testharness"
   ],
   "webxr/xrRigidTransform_constructor.https.html": [
    "abaf8bf9ebe2fed3c99cef5bf52d697b9e8ed1c8",
    "testharness"
   ],
+  "webxr/xrRigidTransform_matrix.https.html": [
+   "21236c732461de4422dcab7a3709cdc7ffc0f3a6",
+   "testharness"
+  ],
   "webxr/xrSession_cancelAnimationFrame.https.html": [
    "cc7b8802cba01ac03adb53a06308acd5642dd0af",
    "testharness"
@@ -483262,7 +483981,7 @@
    "testharness"
   ],
   "xhr/META.yml": [
-   "4b2ecf39bf3a07188d587f0a7ac3d22cad55f923",
+   "c343ceac4375531d92d2ef1ec88de5c7a3897bbe",
    "support"
   ],
   "xhr/OWNERS": [
diff --git a/third_party/blink/web_tests/external/wpt/2dcontext/META.yml b/third_party/blink/web_tests/external/wpt/2dcontext/META.yml
index 53b11d2..0f79f259 100644
--- a/third_party/blink/web_tests/external/wpt/2dcontext/META.yml
+++ b/third_party/blink/web_tests/external/wpt/2dcontext/META.yml
@@ -3,5 +3,4 @@
   - AmeliaBR
   - annevk
   - kenrussell
-  - jdashg
   - fserb
diff --git a/third_party/blink/web_tests/external/wpt/WebIDL/META.yml b/third_party/blink/web_tests/external/wpt/WebIDL/META.yml
index 82ae523..a8dc9c44 100644
--- a/third_party/blink/web_tests/external/wpt/WebIDL/META.yml
+++ b/third_party/blink/web_tests/external/wpt/WebIDL/META.yml
@@ -1,6 +1,5 @@
 spec: https://heycam.github.io/webidl/
 suggested_reviewers:
   - domenic
-  - jensl
   - tobie
   - yuki3
diff --git a/third_party/blink/web_tests/external/wpt/accelerometer/META.yml b/third_party/blink/web_tests/external/wpt/accelerometer/META.yml
index 6554be8..7df27e1f 100644
--- a/third_party/blink/web_tests/external/wpt/accelerometer/META.yml
+++ b/third_party/blink/web_tests/external/wpt/accelerometer/META.yml
@@ -1,7 +1,6 @@
 spec: https://w3c.github.io/accelerometer/
 suggested_reviewers:
   - zqzhang
-  - dontcallmedom
   - riju
   - Honry
   - rakuco
diff --git a/third_party/blink/web_tests/external/wpt/ambient-light/META.yml b/third_party/blink/web_tests/external/wpt/ambient-light/META.yml
index 04fce804..c3f69ba 100644
--- a/third_party/blink/web_tests/external/wpt/ambient-light/META.yml
+++ b/third_party/blink/web_tests/external/wpt/ambient-light/META.yml
@@ -1,7 +1,6 @@
 spec: https://w3c.github.io/ambient-light/
 suggested_reviewers:
   - zqzhang
-  - dontcallmedom
   - riju
   - rakuco
   - Honry
diff --git a/third_party/blink/web_tests/external/wpt/battery-status/META.yml b/third_party/blink/web_tests/external/wpt/battery-status/META.yml
index eded36c5..12a2f12c 100644
--- a/third_party/blink/web_tests/external/wpt/battery-status/META.yml
+++ b/third_party/blink/web_tests/external/wpt/battery-status/META.yml
@@ -1,5 +1,4 @@
 spec: https://w3c.github.io/battery/
 suggested_reviewers:
   - anssiko
-  - dontcallmedom
   - zqzhang
diff --git a/third_party/blink/web_tests/external/wpt/bluetooth/META.yml b/third_party/blink/web_tests/external/wpt/bluetooth/META.yml
index 501396b..607edb6 100644
--- a/third_party/blink/web_tests/external/wpt/bluetooth/META.yml
+++ b/third_party/blink/web_tests/external/wpt/bluetooth/META.yml
@@ -1,6 +1,5 @@
 spec: https://webbluetoothcg.github.io/web-bluetooth/
 suggested_reviewers:
   - dougt
-  - g-ortuno
   - odejesush
   - reillyeon
diff --git a/third_party/blink/web_tests/external/wpt/common/META.yml b/third_party/blink/web_tests/external/wpt/common/META.yml
index 594c8b17..958883a 100644
--- a/third_party/blink/web_tests/external/wpt/common/META.yml
+++ b/third_party/blink/web_tests/external/wpt/common/META.yml
@@ -1,5 +1,4 @@
 suggested_reviewers:
   - zqzhang
-  - dontcallmedom
   - deniak
   - gsnedders
diff --git a/third_party/blink/web_tests/external/wpt/cookies/META.yml b/third_party/blink/web_tests/external/wpt/cookies/META.yml
index 946da88..d074394 100644
--- a/third_party/blink/web_tests/external/wpt/cookies/META.yml
+++ b/third_party/blink/web_tests/external/wpt/cookies/META.yml
@@ -1,3 +1,2 @@
 suggested_reviewers:
-  - inikulin
   - mikewest
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/META.yml b/third_party/blink/web_tests/external/wpt/css/CSS2/META.yml
index 4ac0804..e9bc44dc 100644
--- a/third_party/blink/web_tests/external/wpt/css/CSS2/META.yml
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/META.yml
@@ -5,4 +5,3 @@
   - svgeesus
   - kojiishi
   - frivoal
-  - bert-github
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/META.yml b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/META.yml
index d90a6e0..d673be5 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/META.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/META.yml
@@ -1,6 +1,4 @@
 spec: https://drafts.csswg.org/css-backgrounds/
 suggested_reviewers:
   - dbaron
-  - bert-github
   - fantasai
-  - bradkemper
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/META.yml b/third_party/blink/web_tests/external/wpt/css/css-color/META.yml
index a8d93c12..a0e70aa 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-color/META.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/META.yml
@@ -1,6 +1,5 @@
 spec: https://drafts.csswg.org/css-color/
 suggested_reviewers:
   - dbaron
-  - tantek
   - svgeesus
   - tabatkins
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/META.yml b/third_party/blink/web_tests/external/wpt/css/css-flexbox/META.yml
index 764d8cbd..0bcad0b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/META.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/META.yml
@@ -4,7 +4,6 @@
   - plinss
   - mrego
   - cbiesinger
-  - atanassov
   - fantasai
   - rachelandrew
   - tabatkins
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/META.yml b/third_party/blink/web_tests/external/wpt/css/css-grid/META.yml
index af20bb4..e49946f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/META.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/META.yml
@@ -2,10 +2,8 @@
 suggested_reviewers:
   - mrego
   - plinss
-  - jxs
   - tabatkins
   - fantasai
-  - atanassov
   - javifernandez
   - rachelandrew
   - svillar
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-overflow-auto-max-height-percentage-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-overflow-auto-max-height-percentage-ref.html
new file mode 100644
index 0000000..96a3ca1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-overflow-auto-max-height-percentage-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Reference: Testcase for bug 1526567</title>
+  <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+  <style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+
+.webconsole-app {
+  display: grid;
+}
+
+.sidebar {
+  display: flex;
+  flex: 1;
+  flex-direction: row;
+  background: blue;
+}
+
+.controlled {
+  display: flex;
+  overflow: auto;
+}
+
+.sidebar-wrapper {
+  display: grid;
+  grid-template-columns: 100px;
+  grid-template-rows: 50px 1fr;
+  overflow: hidden;
+}
+
+.sidebar-contents {
+  grid-row: 2 / 3;
+  overflow: auto;
+}
+
+  </style>
+</head>
+<body>
+
+<div class="webconsole-app">
+  <div class="sidebar">
+    <div class="controlled">
+      <div class="sidebar-wrapper">
+        <div></div>
+        <div class="sidebar-contents">
+          <div style="height:400px; background: grey"></div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-overflow-auto-max-height-percentage.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-overflow-auto-max-height-percentage.html
new file mode 100644
index 0000000..62273b87
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-overflow-auto-max-height-percentage.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Testcase for bug 1526567</title>
+  <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+  <link rel="help" href="https://drafts.csswg.org/css-sizing-3/#behave-auto">
+  <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1526567">
+  <link rel="match" href="grid-item-overflow-auto-max-height-percentage-ref.html">
+  <meta name="assert" content="Check that max-height:100% has no effect on a grid item's max-content contribution, since the percentage basis is indefinite in this case.">
+  <style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+
+.webconsole-app {
+  display: grid;
+  height: 200px;
+}
+
+.sidebar {
+  display: flex;
+  flex: 1;
+  flex-direction: row;
+  height: 100%;
+  background: blue;
+}
+
+.controlled {
+  display: flex;
+  overflow: auto;
+}
+
+.sidebar-wrapper {
+  display: grid;
+  grid-template-columns: 100px;
+  grid-template-rows: 50px 1fr;
+  overflow: hidden;
+}
+
+.sidebar-contents {
+  grid-row: 2 / 3;
+  overflow: auto;
+  max-height: 100%;
+}
+
+  </style>
+</head>
+<body>
+
+<div class="webconsole-app">
+  <div class="sidebar">
+    <div class="controlled">
+      <div class="sidebar-wrapper">
+        <div></div>
+        <div class="sidebar-contents">
+          <div style="height:400px; background: grey"></div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-001-ref.html
new file mode 100644
index 0000000..1090871
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-001-ref.html
@@ -0,0 +1,312 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Reference: item [min-|max-]*[width|height] percentages</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+
+.grid {
+  display: inline-grid;
+  height: 10px;
+  width: 10px;
+  grid: 1px auto 2px / 3px auto 4px;
+  border: solid 1px;
+  margin: 0 20px 20px 0;
+  place-items: start;
+}
+.item {
+  background: cyan;
+  grid-area: 2/2;
+  height: 30px;
+  width: 30px;
+}
+.content {
+  height: 30px;
+  width: 30px;
+}
+.min {
+  height: 7px;
+  width: 3px;
+}
+.min:not(.max):not(.size) {
+  height: 30px;
+  width: 30px;
+}
+
+.hl  .item { writing-mode: horizontal-tb; direction:ltr; }
+.hr  .item { writing-mode: horizontal-tb; direction:rtl; }
+.vrl .item { writing-mode: vertical-rl; direction:ltr; }
+.vrr .item { writing-mode: vertical-rl; direction:rtl; }
+.vll .item { writing-mode: vertical-lr; direction:ltr; }
+.vlr .item { writing-mode: vertical-lr; direction:rtl; }
+.sll .item { writing-mode: sideways-lr; direction:ltr; }
+.slr .item { writing-mode: sideways-lr; direction:rtl; }
+
+</style>
+<div class="hl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vrl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vrr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vll">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vlr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="slr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="srl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-001.html
new file mode 100644
index 0000000..97532e4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-001.html
@@ -0,0 +1,318 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: item [min-|max-]*[width|height] percentages</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="help" href="http://www.w3.org/TR/css-grid-1">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1526567">
+<link rel="match" href="grid-item-percentage-sizes-001-ref.html">
+<meta name="assert" content="Checks that item [min-|max-]*[width|height] percentages are resolved correctly in span=1 auto tracks.">
+<style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+
+.grid {
+  display: inline-grid;
+  height: 10px;
+  width: 10px;
+  grid: 1px auto 2px / 3px auto 4px;
+  border: solid 1px;
+  margin: 0 20px 20px 0;
+  place-items: start;
+}
+.item {
+  background: cyan;
+  grid-area: 2/2;
+}
+.content {
+  height: 30px;
+  width: 30px;
+}
+.min {
+  min-height: 100%;
+  min-width: 100%;
+}
+.max {
+  max-height: 100%;
+  max-width: 100%;
+}
+.size {
+  height: 100%;
+  width: 100%;
+}
+
+.hl  .item { writing-mode: horizontal-tb; direction:ltr; }
+.hr  .item { writing-mode: horizontal-tb; direction:rtl; }
+.vrl .item { writing-mode: vertical-rl; direction:ltr; }
+.vrr .item { writing-mode: vertical-rl; direction:rtl; }
+.vll .item { writing-mode: vertical-lr; direction:ltr; }
+.vlr .item { writing-mode: vertical-lr; direction:rtl; }
+.sll .item { writing-mode: sideways-lr; direction:ltr; }
+.slr .item { writing-mode: sideways-lr; direction:rtl; }
+
+</style>
+<div class="hl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vrl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vrr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vll">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vlr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="slr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="srl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-002-ref.html
new file mode 100644
index 0000000..5686426
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-002-ref.html
@@ -0,0 +1,312 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Reference: item [min-|max-]*[width|height] percentages</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+
+.grid {
+  display: inline-grid;
+  height: 10px;
+  width: 10px;
+  grid: 1px auto 2px 3px / 3px auto 4px 2px;
+  border: solid 1px;
+  margin: 0 20px 20px 0;
+  place-items: start;
+}
+.item {
+  background: cyan;
+  grid-area: 2/2/span 2/span 2;
+  height: 30px;
+  width: 30px;
+}
+.content {
+  height: 30px;
+  width: 30px;
+}
+.min {
+  height: 6px;
+  width: 5px;
+}
+.min:not(.max):not(.size) {
+  height: 30px;
+  width: 30px;
+}
+
+.hl  .item { writing-mode: horizontal-tb; direction:ltr; }
+.hr  .item { writing-mode: horizontal-tb; direction:rtl; }
+.vrl .item { writing-mode: vertical-rl; direction:ltr; }
+.vrr .item { writing-mode: vertical-rl; direction:rtl; }
+.vll .item { writing-mode: vertical-lr; direction:ltr; }
+.vlr .item { writing-mode: vertical-lr; direction:rtl; }
+.sll .item { writing-mode: sideways-lr; direction:ltr; }
+.slr .item { writing-mode: sideways-lr; direction:rtl; }
+
+</style>
+<div class="hl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vrl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vrr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vll">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vlr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="slr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="srl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-002.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-002.html
new file mode 100644
index 0000000..2ceba537
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-002.html
@@ -0,0 +1,318 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: item [min-|max-]*[width|height] percentages</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="help" href="http://www.w3.org/TR/css-grid-1">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1526567">
+<link rel="match" href="grid-item-percentage-sizes-002-ref.html">
+<meta name="assert" content="Checks that item [min-|max-]*[width|height] percentages are resolved correctly in span=2 auto tracks.">
+<style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+
+.grid {
+  display: inline-grid;
+  height: 10px;
+  width: 10px;
+  grid: 1px auto 2px 3px / 3px auto 4px 2px;
+  border: solid 1px;
+  margin: 0 20px 20px 0;
+  place-items: start;
+}
+.item {
+  background: cyan;
+  grid-area: 2/2/span 2/span 2;
+}
+.content {
+  height: 30px;
+  width: 30px;
+}
+.min {
+  min-height: 100%;
+  min-width: 100%;
+}
+.max {
+  max-height: 100%;
+  max-width: 100%;
+}
+.size {
+  height: 100%;
+  width: 100%;
+}
+
+.hl  .item { writing-mode: horizontal-tb; direction:ltr; }
+.hr  .item { writing-mode: horizontal-tb; direction:rtl; }
+.vrl .item { writing-mode: vertical-rl; direction:ltr; }
+.vrr .item { writing-mode: vertical-rl; direction:rtl; }
+.vll .item { writing-mode: vertical-lr; direction:ltr; }
+.vlr .item { writing-mode: vertical-lr; direction:rtl; }
+.sll .item { writing-mode: sideways-lr; direction:ltr; }
+.slr .item { writing-mode: sideways-lr; direction:rtl; }
+
+</style>
+<div class="hl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vrl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vrr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vll">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vlr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="slr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="srl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-003-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-003-ref.html
new file mode 100644
index 0000000..41070a8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-003-ref.html
@@ -0,0 +1,316 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Reference: item [min-|max-]*[width|height] calc() percentages</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+
+.grid {
+  display: inline-grid;
+  height: 10px;
+  width: 10px;
+  grid: 1px auto 2px / 3px auto 4px;
+  border: solid 1px;
+  margin: 0 20px 20px 0;
+  place-items: start;
+}
+.item {
+  background: cyan;
+  grid-area: 2/2;
+  height: 30px;
+  width: 30px;
+}
+.content {
+  height: 30px;
+  width: 30px;
+}
+.min {
+  height: 9px;
+  width: 5px;
+}
+.min:not(.max):not(.size) {
+  height: 30px;
+  width: 30px;
+}
+.size:not(.min) {
+  height: 32px;
+  width: 32px;
+}
+
+.hl  .item { writing-mode: horizontal-tb; direction:ltr; }
+.hr  .item { writing-mode: horizontal-tb; direction:rtl; }
+.vrl .item { writing-mode: vertical-rl; direction:ltr; }
+.vrr .item { writing-mode: vertical-rl; direction:rtl; }
+.vll .item { writing-mode: vertical-lr; direction:ltr; }
+.vlr .item { writing-mode: vertical-lr; direction:rtl; }
+.sll .item { writing-mode: sideways-lr; direction:ltr; }
+.slr .item { writing-mode: sideways-lr; direction:rtl; }
+
+</style>
+<div class="hl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vrl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vrr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vll">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vlr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="slr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="srl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-003.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-003.html
new file mode 100644
index 0000000..fccf4fe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-003.html
@@ -0,0 +1,318 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: item [min-|max-]*[width|height] calc() percentages</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="help" href="http://www.w3.org/TR/css-grid-1">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1526567">
+<link rel="match" href="grid-item-percentage-sizes-003-ref.html">
+<meta name="assert" content="Checks that item [min-|max-]*[width|height] percentages are resolved correctly in span=1 auto tracks.">
+<style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+
+.grid {
+  display: inline-grid;
+  height: 10px;
+  width: 10px;
+  grid: 1px auto 2px / 3px auto 4px;
+  border: solid 1px;
+  margin: 0 20px 20px 0;
+  place-items: start;
+}
+.item {
+  background: cyan;
+  grid-area: 2/2;
+}
+.content {
+  height: 30px;
+  width: 30px;
+}
+.min {
+  min-height: calc(2px + 100%);
+  min-width: calc(2px + 100%);
+}
+.max {
+  max-height: calc(2px + 100%);
+  max-width: calc(2px + 100%);
+}
+.size {
+  height: calc(2px + 100%);
+  width: calc(2px + 100%);
+}
+
+.hl  .item { writing-mode: horizontal-tb; direction:ltr; }
+.hr  .item { writing-mode: horizontal-tb; direction:rtl; }
+.vrl .item { writing-mode: vertical-rl; direction:ltr; }
+.vrr .item { writing-mode: vertical-rl; direction:rtl; }
+.vll .item { writing-mode: vertical-lr; direction:ltr; }
+.vlr .item { writing-mode: vertical-lr; direction:rtl; }
+.sll .item { writing-mode: sideways-lr; direction:ltr; }
+.slr .item { writing-mode: sideways-lr; direction:rtl; }
+
+</style>
+<div class="hl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vrl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vrr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vll">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="vlr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="slr">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
+
+<div class="srl">
+<div class="grid">
+  <div class="item max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item max size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min size">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max">
+    <div class="content"></div>
+  </div>
+</div>
+<div class="grid">
+  <div class="item min max size">
+    <div class="content"></div>
+  </div>
+</div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-logical/META.yml b/third_party/blink/web_tests/external/wpt/css/css-logical/META.yml
index 98d838c..cf789d63 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-logical/META.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-logical/META.yml
@@ -1,4 +1,3 @@
 spec: https://drafts.csswg.org/css-logical/
 suggested_reviewers:
-  - atanassov
   - fantasai
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/META.yml b/third_party/blink/web_tests/external/wpt/css/css-position/META.yml
index 00eb3b1..c1ce1ff 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-position/META.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/META.yml
@@ -1,3 +1,3 @@
 spec: https://drafts.csswg.org/css-position/
 suggested_reviewers:
-  - atanassov
+  - astearns
diff --git a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt
index c657b7c..3823a752 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 55 tests; 54 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 60 tests; 59 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS <length> values computed are correctly via var()-reference
 PASS <length> values computed are correctly via var()-reference when font-size is inherited
 PASS <length> values are computed correctly when font-size is inherited [14em]
@@ -9,6 +9,11 @@
 PASS <length> values are computed correctly [14em]
 PASS <length> values are computed correctly [15vmin]
 PASS <length> values are computed correctly [calc(16px - 7em + 10vh)]
+PASS <length> values are computed correctly [1in]
+PASS <length> values are computed correctly [2.54cm]
+PASS <length> values are computed correctly [25.4mm]
+PASS <length> values are computed correctly [6pc]
+PASS <length> values are computed correctly [72pt]
 PASS <length-percentage> values are computed correctly [17em]
 PASS <length-percentage> values are computed correctly [18%]
 PASS <length-percentage> values are computed correctly [calc(19em - 2%)]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation.html b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation.html
index b1e5d237..f03b257 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation.html
@@ -101,6 +101,12 @@
 test_computed_value('<length>', '15vmin', length_ref('15vmin'));
 test_computed_value('<length>', 'calc(16px - 7em + 10vh)', length_ref('calc(10vh - 54px)'));
 
+test_computed_value('<length>', '1in', '96px');
+test_computed_value('<length>', '2.54cm', '96px');
+test_computed_value('<length>', '25.4mm', '96px');
+test_computed_value('<length>', '6pc', '96px');
+test_computed_value('<length>', '72pt', '96px');
+
 test_computed_value('<length-percentage>', '17em', '170px');
 test_computed_value('<length-percentage>', '18%', '18%');
 test_computed_value('<length-percentage>', 'calc(19em - 2%)', 'calc(-2% + 190px)');
diff --git a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-initial.html b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-initial.html
index d35b14b..17c883a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-initial.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-initial.html
@@ -18,6 +18,12 @@
 }
 
 test_initial_value({ syntax: '<length>', initialValue: 'calc(10px + 15px)' }, '25px');
+test_initial_value({ syntax: '<length>', initialValue: '1in' }, '96px');
+test_initial_value({ syntax: '<length>', initialValue: '2.54cm' }, '96px');
+test_initial_value({ syntax: '<length>', initialValue: '25.4mm' }, '96px');
+test_initial_value({ syntax: '<length>', initialValue: '6pc' }, '96px');
+test_initial_value({ syntax: '<length>', initialValue: '72pt' }, '96px');
+test_initial_value({ syntax: '<percentage>', initialValue: 'calc(10% + 20%)' }, '30%');
 test_initial_value({ syntax: '<length-percentage>', initialValue: 'calc(1in + 10% + 4px)' }, 'calc(10% + 100px)');
 test_initial_value({ syntax: '<color>', initialValue: 'pink', inherits: true }, 'rgb(255, 192, 203)');
 test_initial_value({ syntax: '<color>', initialValue: 'purple' }, 'rgb(128, 0, 128)');
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scrollbars/META.yml b/third_party/blink/web_tests/external/wpt/css/css-scrollbars/META.yml
index 9209d5d..f7c0439 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-scrollbars/META.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-scrollbars/META.yml
@@ -1,3 +1,3 @@
 spec: https://drafts.csswg.org/css-scrollbars/
 suggested_reviewers:
-  - tantek
+  - upsuper
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/META.yml b/third_party/blink/web_tests/external/wpt/css/css-shapes/META.yml
index 9913681..2e433aa 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/META.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/META.yml
@@ -1,7 +1,5 @@
 spec: https://drafts.csswg.org/css-shapes/
 suggested_reviewers:
-  - bemjb
   - kojiishi
   - plinss
-  - atanassov
   - astearns
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-2-ref.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-2-ref.html
index 83eff4b4..207b60d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-2-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-2-ref.html
@@ -97,12 +97,14 @@
   <input type="range" class="mb" orient="vertical">
 </div></div>
 
-<div class="grid" style="grid: 4px / auto">
-  <input type="range" class="mb" orient="vertical" style="height:2px">
+<div class="grid" style="grid: min-content / auto">
+  <input type="range" class="b" orient="vertical" style="height:50%; grid-area:1/1">
+  <input type="range" class="b" orient="vertical" style="visibility:hidden; grid-area:1/1">
 </div>
 
-<div class="grid" style="grid: 30px / auto">
-  <input type="range" class="b" orient="vertical" style="height:15px">
+<div class="grid" style="grid: min-content / auto">
+  <input type="range" class="b" orient="vertical" style="height:50%; grid-area:1/1">
+  <input type="range" class="b" orient="vertical" style="visibility:hidden; grid-area:1/1">
 </div>
 
 <div class="grid" style="grid: 30px / auto">
@@ -117,12 +119,14 @@
   <input type="range" class="mb n" orient="vertical">
 </div></div>
 
-<div class="grid" style="grid: 4px / auto">
-  <input type="range" class="mb n" orient="vertical" style="height:2px">
+<div class="grid" style="grid: min-content / auto">
+  <input type="range" class="b" orient="vertical" style="height:50%; grid-area:1/1">
+  <input type="range" class="b" orient="vertical" style="visibility:hidden; grid-area:1/1">
 </div>
 
-<div class="grid" style="grid: 30px / auto">
-  <input type="range" class="b" orient="vertical" style="height:15px">
+<div class="grid" style="grid: min-content / auto">
+  <input type="range" class="b" orient="vertical" style="height:50%; grid-area:1/1">
+  <input type="range" class="b" orient="vertical" style="visibility:hidden; grid-area:1/1">
 </div>
 
 <div class="grid" style="grid: 30px / auto">
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-2a-ref.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-2a-ref.html
index 815b0a1..861d34c6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-2a-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/range-percent-intrinsic-size-2a-ref.html
@@ -71,8 +71,9 @@
   <input type="range" class="mb" orient="vertical">
 </div></div>
 
-<div class="grid" style="grid: 30px / auto">
-  <input type="range" class="b" orient="vertical" style="height:15px">
+<div class="grid" style="grid: min-content / auto">
+  <input type="range" class="b" orient="vertical" style="height:50%; grid-area:1/1">
+  <input type="range" class="b" orient="vertical" style="visibility:hidden; grid-area:1/1">
 </div>
 
 <div class="grid" style="grid: 30px / auto">
diff --git a/third_party/blink/web_tests/external/wpt/css/css-style-attr/META.yml b/third_party/blink/web_tests/external/wpt/css/css-style-attr/META.yml
index 7243873..067e03cf 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-style-attr/META.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-style-attr/META.yml
@@ -1,4 +1,3 @@
 spec: https://drafts.csswg.org/css-style-attr/
 suggested_reviewers:
-  - tantek
   - fantasai
diff --git a/third_party/blink/web_tests/external/wpt/css/css-syntax/META.yml b/third_party/blink/web_tests/external/wpt/css/css-syntax/META.yml
index 17489e1..359219c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-syntax/META.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-syntax/META.yml
@@ -2,4 +2,3 @@
 suggested_reviewers:
   - gregwhitworth
   - tabatkins
-  - simonsapin
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/META.yml b/third_party/blink/web_tests/external/wpt/css/css-text/META.yml
index 042b8585..e7914c0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/META.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/META.yml
@@ -5,5 +5,4 @@
   - frivoal
   - r12a
   - nox
-  - hakatashi
   - fantasai
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/META.yml b/third_party/blink/web_tests/external/wpt/css/css-transforms/META.yml
index 33c1fce3..b948e3a3 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transforms/META.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/META.yml
@@ -3,5 +3,4 @@
   - dbaron
   - plinss
   - dirkschulze
-  - hober
   - grorg
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/transform-flattening-001.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/transform-flattening-001.html
new file mode 100644
index 0000000..85d2977
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/transform-flattening-001.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<title>CSS Transforms: Transforms are flattened if transform-style is flat.</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#3d-rendering-context">
+<link rel="mismatch" href="about:blank">
+<!-- Should see a green rectangle, not white -->
+<div style="transform: rotateX(45deg)">
+  <div style="transform: rotateX(45deg); background: green; width: 100px; height: 100px"></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/META.yml b/third_party/blink/web_tests/external/wpt/css/css-ui/META.yml
index e78564bc..7ce4b54 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/META.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/META.yml
@@ -4,4 +4,3 @@
   - mrego
   - plinss
   - svgeesus
-  - tantek
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/META.yml b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/META.yml
index c74fff07..c11da73b 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/META.yml
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/META.yml
@@ -2,7 +2,6 @@
 suggested_reviewers:
   - kojiishi
   - fantasai
-  - myakura
   - r12a
   - plinss
   - upsuper
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/META.yml b/third_party/blink/web_tests/external/wpt/css/selectors/META.yml
index 3f86842..8e506d6 100644
--- a/third_party/blink/web_tests/external/wpt/css/selectors/META.yml
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/META.yml
@@ -1,6 +1,5 @@
 spec: https://drafts.csswg.org/selectors/
 suggested_reviewers:
-  - tantek
   - fantasai
   - frivoal
   - plinss
diff --git a/third_party/blink/web_tests/external/wpt/device-memory/META.yml b/third_party/blink/web_tests/external/wpt/device-memory/META.yml
index b393c6b..b8dd476 100644
--- a/third_party/blink/web_tests/external/wpt/device-memory/META.yml
+++ b/third_party/blink/web_tests/external/wpt/device-memory/META.yml
@@ -1,4 +1,3 @@
 spec: https://w3c.github.io/device-memory/
 suggested_reviewers:
-  - tdresser
   - npm1
diff --git a/third_party/blink/web_tests/external/wpt/encrypted-media/META.yml b/third_party/blink/web_tests/external/wpt/encrypted-media/META.yml
index 3168f7d..b09e3b3 100644
--- a/third_party/blink/web_tests/external/wpt/encrypted-media/META.yml
+++ b/third_party/blink/web_tests/external/wpt/encrypted-media/META.yml
@@ -1,3 +1,6 @@
 spec: https://w3c.github.io/encrypted-media/
 suggested_reviewers:
-  - ddorwin
+  - cpearce
+  - joeyparrish
+  - jrummell-chromium
+  - jyavenard
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/META.yml b/third_party/blink/web_tests/external/wpt/event-timing/META.yml
index feede41d..aa27fb6 100644
--- a/third_party/blink/web_tests/external/wpt/event-timing/META.yml
+++ b/third_party/blink/web_tests/external/wpt/event-timing/META.yml
@@ -1,4 +1,3 @@
 spec: https://github.com/WICG/event-timing
 suggested_reviewers:
   - npm1
-  - tdresser
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/META.yml b/third_party/blink/web_tests/external/wpt/feature-policy/META.yml
index 44ab62c..a4136f7 100644
--- a/third_party/blink/web_tests/external/wpt/feature-policy/META.yml
+++ b/third_party/blink/web_tests/external/wpt/feature-policy/META.yml
@@ -1,3 +1,3 @@
 spec: https://wicg.github.io/feature-policy/
 suggested_reviewers:
-  - clelland
+  - bakulf
diff --git a/third_party/blink/web_tests/external/wpt/gamepad/META.yml b/third_party/blink/web_tests/external/wpt/gamepad/META.yml
index 5f99b9d..b008a9e 100644
--- a/third_party/blink/web_tests/external/wpt/gamepad/META.yml
+++ b/third_party/blink/web_tests/external/wpt/gamepad/META.yml
@@ -1,3 +1,3 @@
 spec: https://w3c.github.io/gamepad/
 suggested_reviewers:
-  - luser
+  - marcoscaceres
diff --git a/third_party/blink/web_tests/external/wpt/generic-sensor/META.yml b/third_party/blink/web_tests/external/wpt/generic-sensor/META.yml
index 1cfe809..bf48f80 100644
--- a/third_party/blink/web_tests/external/wpt/generic-sensor/META.yml
+++ b/third_party/blink/web_tests/external/wpt/generic-sensor/META.yml
@@ -1,7 +1,6 @@
 spec: https://w3c.github.io/sensors/
 suggested_reviewers:
   - zqzhang
-  - dontcallmedom
   - riju
   - rakuco
   - Honry
diff --git a/third_party/blink/web_tests/external/wpt/gyroscope/META.yml b/third_party/blink/web_tests/external/wpt/gyroscope/META.yml
index 67f22d53..6a48535 100644
--- a/third_party/blink/web_tests/external/wpt/gyroscope/META.yml
+++ b/third_party/blink/web_tests/external/wpt/gyroscope/META.yml
@@ -1,7 +1,6 @@
 spec: https://w3c.github.io/gyroscope/
 suggested_reviewers:
   - zqzhang
-  - dontcallmedom
   - riju
   - Honry
   - rakuco
diff --git a/third_party/blink/web_tests/external/wpt/html-media-capture/META.yml b/third_party/blink/web_tests/external/wpt/html-media-capture/META.yml
index 706dbdf8..3dd015f 100644
--- a/third_party/blink/web_tests/external/wpt/html-media-capture/META.yml
+++ b/third_party/blink/web_tests/external/wpt/html-media-capture/META.yml
@@ -1,4 +1,3 @@
 spec: https://w3c.github.io/html-media-capture/
 suggested_reviewers:
-  - haoxli
   - zqzhang
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/document-attribute.window.js b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/document-attribute.window.js
new file mode 100644
index 0000000..f13acdb8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/document-attribute.window.js
@@ -0,0 +1,15 @@
+async_test(t => {
+  const frame = document.createElement("iframe");
+  frame.onload = t.step_func(() => {
+    const frameW = frame.contentWindow,
+          frameD = frame.contentDocument;
+    assert_equals(frameW.document, frameD);
+    frame.remove();
+    assert_equals(frameW.document, frameD);
+    t.step_timeout(() => {
+      assert_equals(frameW.document, frameD);
+      t.done();
+    }, 100);
+  });
+  document.body.append(frame);
+}, "Window object's document IDL attribute and discarding the browsing context");
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/self-et-al.window.js b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/self-et-al.window.js
new file mode 100644
index 0000000..1b0fa121
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/self-et-al.window.js
@@ -0,0 +1,43 @@
+function delayed_assert_done(t, w, windowProxySelfReference) {
+  // Let's make sure nobody is being sneaky
+  t.step_timeout(() => {
+    t.step_timeout(() => {
+      assert_equals(w[windowProxySelfReference], w, `${windowProxySelfReference} got cleared after some time`);
+      t.done();
+    }, 0);
+  }, 0);
+}
+
+[
+  "frames",
+  "globalThis",
+  "self",
+  "window"
+].forEach(windowProxySelfReference => {
+  async_test(t => {
+    const frame = document.body.appendChild(document.createElement("iframe")),
+          otherW = frame.contentWindow;
+    assert_equals(otherW[windowProxySelfReference], otherW, `${windowProxySelfReference} is broken`);
+    frame.remove();
+    assert_equals(otherW[windowProxySelfReference], otherW, `${windowProxySelfReference} got cleared after browsing context removal`);
+    assert_true(otherW.closed);
+
+    delayed_assert_done(t, otherW, windowProxySelfReference);
+  }, `iframeWindow.${windowProxySelfReference} before and after removal`);
+
+  async_test(t => {
+    const otherW = window.open();
+    assert_equals(otherW[windowProxySelfReference], otherW, `${windowProxySelfReference} is broken`);
+    otherW.onunload = t.step_func(() => {
+      assert_equals(otherW[windowProxySelfReference], otherW, `${windowProxySelfReference} got cleared after browsing context unload`);
+      t.step_timeout(() => {
+        assert_equals(otherW.opener, null); // Ensure browsing context is discarded
+        assert_equals(otherW[windowProxySelfReference], otherW, `${windowProxySelfReference} got cleared after browsing context removal`);
+        delayed_assert_done(t, otherW, windowProxySelfReference);
+      }, 0);
+    });
+    otherW.close();
+    assert_equals(otherW[windowProxySelfReference], otherW, `${windowProxySelfReference} got cleared after browsing context closure`);
+    assert_true(otherW.closed);
+  }, `popupWindow.${windowProxySelfReference} before, after closing, and after discarding`)
+});
diff --git a/third_party/blink/web_tests/external/wpt/imagebitmap-renderingcontext/META.yml b/third_party/blink/web_tests/external/wpt/imagebitmap-renderingcontext/META.yml
index f6a06f4..4239a85 100644
--- a/third_party/blink/web_tests/external/wpt/imagebitmap-renderingcontext/META.yml
+++ b/third_party/blink/web_tests/external/wpt/imagebitmap-renderingcontext/META.yml
@@ -3,5 +3,4 @@
   - AmeliaBR
   - annevk
   - kenrussell
-  - jdashg
   - fserb
diff --git a/third_party/blink/web_tests/external/wpt/lint.whitelist b/third_party/blink/web_tests/external/wpt/lint.whitelist
index 11b75562..12b3212 100644
--- a/third_party/blink/web_tests/external/wpt/lint.whitelist
+++ b/third_party/blink/web_tests/external/wpt/lint.whitelist
@@ -187,6 +187,8 @@
 SET TIMEOUT: payment-request/allowpaymentrequest/setting-allowpaymentrequest-timing.https.sub.html
 SET TIMEOUT: preload/single-download-preload.html
 SET TIMEOUT: resize-observer/resources/iframe.html
+SET TIMEOUT: resource-timing/resources/iframe-TAO*
+SET TIMEOUT: resource-timing/resources/nested-contexts.js
 SET TIMEOUT: screen-orientation/onchange-event.html
 SET TIMEOUT: secure-contexts/basic-popup-and-iframe-tests.https.js
 SET TIMEOUT: service-workers/cache-storage/script-tests/cache-abort.js
diff --git a/third_party/blink/web_tests/external/wpt/magnetometer/META.yml b/third_party/blink/web_tests/external/wpt/magnetometer/META.yml
index 88b900c..d7d395e 100644
--- a/third_party/blink/web_tests/external/wpt/magnetometer/META.yml
+++ b/third_party/blink/web_tests/external/wpt/magnetometer/META.yml
@@ -1,7 +1,6 @@
 spec: https://w3c.github.io/magnetometer/
 suggested_reviewers:
   - zqzhang
-  - dontcallmedom
   - riju
   - Honry
   - rakuco
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-linethickness-001-ref.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-linethickness-001-ref.html
index c703edb..d4be8ea 100644
--- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-linethickness-001-ref.html
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-linethickness-001-ref.html
@@ -16,23 +16,26 @@
     </style>
   </head>
   <body>
-    <p>This test passes if you see fractions with line thickness equal to the height of their blue numerator and cyan denominator.</p>
+    <p>This test passes if you see the same fraction four times.</p>
     <math>
-      <mfrac linethickness="5px">
-        <mspace width="20px" height="5px" style="background: blue"></mspace>
-        <mspace width="20px" height="5px" style="background: cyan"></mspace>
-      </mfrac>
-      <mfrac linethickness="10px">
+      <mfrac>
         <mspace width="20px" height="10px" style="background: blue"></mspace>
         <mspace width="20px" height="10px" style="background: cyan"></mspace>
       </mfrac>
-      <mfrac linethickness="20px">
-        <mspace width="20px" height="20px" style="background: blue"></mspace>
-        <mspace width="20px" height="20px" style="background: cyan"></mspace>
+      <mspace width="20px"/>
+      <mfrac>
+        <mspace width="20px" height="10px" style="background: blue"></mspace>
+        <mspace width="20px" height="10px" style="background: cyan"></mspace>
       </mfrac>
-      <mfrac linethickness="50px">
-        <mspace width="20px" height="50px" style="background: blue"></mspace>
-        <mspace width="20px" height="50px" style="background: cyan"></mspace>
+      <mspace width="20px"/>
+      <mfrac>
+        <mspace width="20px" height="10px" style="background: blue"></mspace>
+        <mspace width="20px" height="10px" style="background: cyan"></mspace>
+      </mfrac>
+      <mspace width="20px"/>
+      <mfrac>
+        <mspace width="20px" height="10px" style="background: blue"></mspace>
+        <mspace width="20px" height="10px" style="background: cyan"></mspace>
       </mfrac>
     </math>
   </body>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-linethickness-001.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-linethickness-001.html
index 83e15c8..eca8287 100644
--- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-linethickness-001.html
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-linethickness-001.html
@@ -4,7 +4,7 @@
     <meta charset="utf-8">
     <title>fractions linethickness</title>
     <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#mfrac">
-    <meta name="assert" content="Verifies 'thin', 'medium', 'thick' and unitless values for the linethickness attribute of the mfrac element">
+    <meta name="assert" content="Verifies deprecated 'thin', 'medium', 'thick' and unitless values have no effect on the linethickness of the mfrac element">
     <link rel="match" href="frac-linethickness-001-ref.html">
     <style type="text/css">
       @font-face {
@@ -19,23 +19,26 @@
     </style>
   </head>
   <body>
-    <p>This test passes if you see fractions with line thickness equal to the height of their blue numerator and cyan denominator.</p>
+    <p>This test passes if you see the same fraction four times.</p>
     <math>
       <mfrac linethickness="thin">
-        <mspace width="20px" height="5px" style="background: blue"></mspace>
-        <mspace width="20px" height="5px" style="background: cyan"></mspace>
+        <mspace width="20px" height="10px" style="background: blue"></mspace>
+        <mspace width="20px" height="10px" style="background: cyan"></mspace>
       </mfrac>
+      <mspace width="20px"/>
       <mfrac linethickness="medium">
         <mspace width="20px" height="10px" style="background: blue"></mspace>
         <mspace width="20px" height="10px" style="background: cyan"></mspace>
       </mfrac>
+      <mspace width="20px"/>
       <mfrac linethickness="thick">
-        <mspace width="20px" height="20px" style="background: blue"></mspace>
-        <mspace width="20px" height="20px" style="background: cyan"></mspace>
+        <mspace width="20px" height="10px" style="background: blue"></mspace>
+        <mspace width="20px" height="10px" style="background: cyan"></mspace>
       </mfrac>
+      <mspace width="20px"/>
       <mfrac linethickness="5">
-        <mspace width="20px" height="50px" style="background: blue"></mspace>
-        <mspace width="20px" height="50px" style="background: cyan"></mspace>
+        <mspace width="20px" height="10px" style="background: blue"></mspace>
+        <mspace width="20px" height="10px" style="background: cyan"></mspace>
       </mfrac>
     </math>
   </body>
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-depth/META.yml b/third_party/blink/web_tests/external/wpt/mediacapture-depth/META.yml
index e083c9b..4346120 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-depth/META.yml
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-depth/META.yml
@@ -3,4 +3,3 @@
   - anssiko
   - Honry
   - robman
-  - astojilj
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/META.yml b/third_party/blink/web_tests/external/wpt/mediacapture-streams/META.yml
index 1ed650e..960dc3a5 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/META.yml
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/META.yml
@@ -2,7 +2,5 @@
 suggested_reviewers:
   - agouaillard
   - alvestrand
-  - dontcallmedom
-  - eric-carlson
   - youennf
   - jan-ivar
diff --git a/third_party/blink/web_tests/external/wpt/navigation-timing/nav2_test_redirect_chain_xserver_partial_opt_in.html b/third_party/blink/web_tests/external/wpt/navigation-timing/nav2_test_redirect_chain_xserver_partial_opt_in.html
new file mode 100644
index 0000000..c0dd249
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/navigation-timing/nav2_test_redirect_chain_xserver_partial_opt_in.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="utf-8" />
+        <title>Navigation Timing 2 WPT</title>
+        <link rel="author" title="Google" href="http://www.google.com/" />
+        <link rel="help" href="http://www.w3.org/TR/navigation-timing-2/#sec-PerformanceNavigationTiming"/>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="/common/utils.js"></script>
+        <script>
+
+            function verifyTimingEventOrder(eventOrder, timingEntry) {
+                for (let i = 0; i < eventOrder.length - 1; i++) {
+                    assert_true(timingEntry[eventOrder[i]] < timingEntry[eventOrder[i + 1]],
+                        "Expected " + eventOrder[i] + " to be no greater than " + eventOrder[i + 1] + ".");
+                }
+            }
+
+            function onload_test()
+            {
+                const frame_performance = document.getElementById("frameContext").contentWindow.performance;
+                assert_equals(frame_performance.getEntriesByType("navigation")[0].type,
+                    "navigate",
+                    "Expected navigation type to be navigate.");
+                assert_equals(frame_performance.getEntriesByType("navigation")[0].redirectCount, 0,
+                    "Expected redirectCount to be 0.");
+                assert_equals(frame_performance.getEntriesByType("navigation")[0].redirectStart, 0,
+                    "Expected redirectStart to be 0.");
+                assert_equals(frame_performance.getEntriesByType("navigation")[0].redirectEnd, 0,
+                    "Expected redirectEnd to be 0.");
+                done();
+            }
+        </script>
+
+    </head>
+    <body>
+        <h1>Description</h1>
+        <p>This test validates the values of the window.performance.getEntriesByType("navigation")[0].redirectCount and the
+           window.performance.getEntriesByType("navigation")[0].redirectStart/End times for a cross-origin server side redirect navigation when the redirect chooses to opt-in.</p>
+
+        <iframe id="frameContext" src="" style="width: 250px; height: 250px;"></iframe>
+        <script>
+            // combine the page origin and redirect origin into the IFRAME's src URL
+            const destUrl_first = make_absolute_url({subdomain: "www",
+                                             path: "/common/redirect-opt-in.py",
+                                             query: "location=" + make_absolute_url(
+                                                         {path: "/navigation-timing/resources/blank_page_green.html"})
+                                             });
+            const destUrl = make_absolute_url({subdomain: "www",
+                                             path: "/common/redirect.py",
+                                             query: "location=" + destUrl_first});
+            let frameContext = document.getElementById("frameContext");
+            frameContext.onload = onload_test;
+            frameContext.src = destUrl;
+        </script>
+    </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/navigation-timing/nav2_test_unloadEvents_with_cross_origin_redirect_chain_partial_opt_in.html b/third_party/blink/web_tests/external/wpt/navigation-timing/nav2_test_unloadEvents_with_cross_origin_redirect_chain_partial_opt_in.html
new file mode 100644
index 0000000..0b39786
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/navigation-timing/nav2_test_unloadEvents_with_cross_origin_redirect_chain_partial_opt_in.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="utf-8" />
+        <title>Navigation Timing 2 WPT</title>
+        <link rel="author" title="Google" href="http://www.google.com/" />
+        <link rel="help" href="http://www.w3.org/TR/navigation-timing-2/#sec-PerformanceNavigationTiming"/>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="/common/utils.js"></script>
+        <script>
+
+            let reload_frame;
+
+            function onload_test()
+            {
+                reload_frame = document.getElementById("frameContext");
+                reload_frame.onload = do_test;
+                setTimeout("reload_the_frame();", 100);
+            }
+
+            function reload_the_frame()
+            {
+                const destUrl_first = make_absolute_url({subdomain: "www",
+                                                 path: "/common/redirect-opt-in.py",
+                                                 query: "location=" + make_absolute_url(
+                                                             {path: "/navigation-timing/resources/blank_page_yellow.html"})
+                                                 });
+                const destUrl = make_absolute_url({subdomain: "www",
+                                                 path: "/common/redirect.py",
+                                                 query: "location=" + destUrl_first
+                                                 });
+                reload_frame.contentWindow.location.href = destUrl;
+            }
+
+            function do_test()
+            {
+                const newNavTiming = document.getElementById("frameContext").contentWindow.performance.getEntriesByType("navigation")[0];
+                assert_equals(newNavTiming.type, "navigate", "Expected navigation type to be navigate.");
+                assert_equals(newNavTiming.unloadEventStart, 0, "Expected unloadEventStart to be 0.");
+                assert_equals(newNavTiming.unloadEventEnd, 0, "Expected unloadEventEnd to be 0.");
+                done();
+            }
+        </script>
+    </head>
+    <body>
+        <h1>Description</h1>
+        <p>This test validates the value of window.performance.getEntriesByType("navigation")[0].(type/unloadEventEnd/unloadEventStart) with a reloaded navigation.</p>
+
+        <p>This page should be loaded with a green background frame below.  The frame will be automatically reloaded
+        and then verified that
+        <ul>
+            <li>The window.performance.getEntriesByType("navigation").type = "navigate"</li>
+            <li>The window.performance.getEntriesByType("navigation").unloadEventStart == 0</li>
+            <li>The window.performance.getEntriesByType("navigation").unloadEventEnd == 0</li>
+        </ul>
+        </p>
+
+        <iframe id="frameContext" onload="onload_test();" src="resources/blank_page_green.html" style="width: 250px; height: 250px;"></iframe>
+    </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/navigation-timing/nav2_test_unloadEvents_with_cross_origin_redirect_opt_in.html b/third_party/blink/web_tests/external/wpt/navigation-timing/nav2_test_unloadEvents_with_cross_origin_redirect_opt_in.html
new file mode 100644
index 0000000..d3ff5508
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/navigation-timing/nav2_test_unloadEvents_with_cross_origin_redirect_opt_in.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="utf-8" />
+        <title>Navigation Timing 2 WPT</title>
+        <link rel="author" title="Google" href="http://www.google.com/" />
+        <link rel="help" href="http://www.w3.org/TR/navigation-timing-2/#sec-PerformanceNavigationTiming"/>
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script src="/common/utils.js"></script>
+        <script>
+
+            let reload_frame;
+
+            function onload_test()
+            {
+                reload_frame = document.getElementById("frameContext");
+                reload_frame.onload = do_test;
+                setTimeout("reload_the_frame();", 100);
+            }
+
+            function reload_the_frame()
+            {
+                const destUrl = make_absolute_url({subdomain: "www",
+                                                 path: "/common/redirect-opt-in.py",
+                                                 query: "location=" + make_absolute_url(
+                                                             {path: "/navigation-timing/resources/blank_page_yellow.html"})
+                                                 });
+                reload_frame.contentWindow.location.href = destUrl;
+            }
+
+            function do_test()
+            {
+                const newNavTiming = document.getElementById("frameContext").contentWindow.performance.getEntriesByType("navigation")[0];
+                assert_equals(newNavTiming.type, "navigate", "Expected navigation type to be navigate.");
+                assert_not_equals(newNavTiming.unloadEventStart, 0, "Expected unloadEventStart to not be 0.");
+                assert_not_equals(newNavTiming.unloadEventEnd, 0, "Expected unloadEventEnd to not be 0.");
+                done();
+            }
+        </script>
+    </head>
+    <body>
+        <h1>Description</h1>
+        <p>This test validates the value of window.performance.getEntriesByType("navigation")[0].(type/unloadEventEnd/unloadEventStart) with a reloaded navigation.</p>
+
+        <p>This page should be loaded with a green background frame below.  The frame will be automatically reloaded
+        and then verified that
+        <ul>
+            <li>The window.performance.getEntriesByType("navigation").type = "navigate"</li>
+            <li>The window.performance.getEntriesByType("navigation").unloadEventStart == 0</li>
+            <li>The window.performance.getEntriesByType("navigation").unloadEventEnd == 0</li>
+        </ul>
+        </p>
+
+        <iframe id="frameContext" onload="onload_test();" src="resources/blank_page_green.html" style="width: 250px; height: 250px;"></iframe>
+    </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/notifications/META.yml b/third_party/blink/web_tests/external/wpt/notifications/META.yml
index 2cb7972..0daa86e 100644
--- a/third_party/blink/web_tests/external/wpt/notifications/META.yml
+++ b/third_party/blink/web_tests/external/wpt/notifications/META.yml
@@ -1,4 +1,3 @@
 spec: https://notifications.spec.whatwg.org/
 suggested_reviewers:
   - sideshowbarker
-  - ibelem
diff --git a/third_party/blink/web_tests/external/wpt/offscreen-canvas/META.yml b/third_party/blink/web_tests/external/wpt/offscreen-canvas/META.yml
index bcb30ed..d3e4c38 100644
--- a/third_party/blink/web_tests/external/wpt/offscreen-canvas/META.yml
+++ b/third_party/blink/web_tests/external/wpt/offscreen-canvas/META.yml
@@ -3,5 +3,4 @@
   - AmeliaBR
   - annevk
   - kenrussell
-  - jdashg
   - fserb
diff --git a/third_party/blink/web_tests/external/wpt/orientation-sensor/META.yml b/third_party/blink/web_tests/external/wpt/orientation-sensor/META.yml
index 99d61666..4273858 100644
--- a/third_party/blink/web_tests/external/wpt/orientation-sensor/META.yml
+++ b/third_party/blink/web_tests/external/wpt/orientation-sensor/META.yml
@@ -1,7 +1,6 @@
 spec: https://w3c.github.io/orientation-sensor/
 suggested_reviewers:
   - zqzhang
-  - dontcallmedom
   - riju
   - Honry
   - rakuco
diff --git a/third_party/blink/web_tests/external/wpt/paint-timing/META.yml b/third_party/blink/web_tests/external/wpt/paint-timing/META.yml
index 24acb25..1892a41e 100644
--- a/third_party/blink/web_tests/external/wpt/paint-timing/META.yml
+++ b/third_party/blink/web_tests/external/wpt/paint-timing/META.yml
@@ -1,4 +1,3 @@
 spec: https://w3c.github.io/paint-timing/
 suggested_reviewers:
   - spanicker
-  - tdresser
diff --git a/third_party/blink/web_tests/external/wpt/payment-method-id/META.yml b/third_party/blink/web_tests/external/wpt/payment-method-id/META.yml
index e0931f4..5e9fe05a 100644
--- a/third_party/blink/web_tests/external/wpt/payment-method-id/META.yml
+++ b/third_party/blink/web_tests/external/wpt/payment-method-id/META.yml
@@ -1,4 +1,3 @@
 spec: https://w3c.github.io/payment-method-id/
 suggested_reviewers:
-  - alphan102
   - marcoscaceres
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/PaymentAddress/attributes-and-toJSON-method-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/PaymentAddress/attributes-and-toJSON-method-manual.https.html
index 45f3f0a5..226fd88 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/PaymentAddress/attributes-and-toJSON-method-manual.https.html
+++ b/third_party/blink/web_tests/external/wpt/payment-request/PaymentAddress/attributes-and-toJSON-method-manual.https.html
@@ -72,6 +72,7 @@
       city: 'Chapel Hill',
       dependentLocality: '',
       postalCode: '6095',
+      region: 'QLD',
       sortingCode: '',
       organization: 'w3c',
       recipient: 'web platform test',
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/payment-response/onpayerdetailchange-attribute-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/payment-response/onpayerdetailchange-attribute-manual.https.html
index c8dd926..f3f3f76 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/payment-response/onpayerdetailchange-attribute-manual.https.html
+++ b/third_party/blink/web_tests/external/wpt/payment-request/payment-response/onpayerdetailchange-attribute-manual.https.html
@@ -16,7 +16,14 @@
     await response.retry({ error });
     const event = await eventPromise;
     assert_true(event instanceof PaymentRequestUpdateEvent);
-    for(const [prop, value] of Object.entries(expected)){
+    for([prop, value] of Object.entries(expected)){
+      if (prop === 'payerPhone') {
+        // |payerPhone| may optionally adhere to E164 structure, which does not
+        // contain formatting, e.g. +180000000 instead of +1-800-000-0000.
+        // Strip out the formatting in case the user agent implements E164.
+        // https://w3c.github.io/payment-request/#addressinit-dictionary
+        value = value.replace(/[-\(\) ]/g, '');
+      }
       assert_equals(response[prop], value);
     }
     await response.complete("success");
@@ -52,7 +59,7 @@
     <p>
       Change payer's phone to "+1-800-000-0000".
     </p>
-    <button onclick="runTest(this, {requestPayerPhone: true}, { payerPhone: '+1-800-000-0000' })">
+    <button onclick="runTest(this, {requestPayerPhone: true}, { payerPhone: '+18000000000' })">
       PaymentRequestUpdateEvent is dispatched when payer phone changes.
     </button>
   </li>
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/show-method-postmessage-manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/show-method-postmessage-manual.https.html
index 05fce4f..920e0a99 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/show-method-postmessage-manual.https.html
+++ b/third_party/blink/web_tests/external/wpt/payment-request/show-method-postmessage-manual.https.html
@@ -12,43 +12,6 @@
   allow_uncaught_exception: true,
 });
 
-const defaultMethods = Object.freeze([
-  { supportedMethods: "basic-card" },
-  {
-    supportedMethods: "https://apple.com/apple-pay",
-    data: {
-      version: 3,
-      merchantIdentifier: "merchant.com.example",
-      countryCode: "US",
-      merchantCapabilities: ["supports3DS"],
-      supportedNetworks: ["visa"],
-    }
-  },
-]);
-
-const defaultDetails = Object.freeze({
-  id: "fail",
-  total: {
-    label: "Total",
-    amount: {
-      currency: "USD",
-      value: "1.00",
-    },
-  },
-});
-
-test(() => {
-  assert_throws(
-    "SecurityError",
-    () => {
-      const request = new PaymentRequest(defaultMethods, defaultDetails);
-      request.show(); // <--- should throw here
-      request.abort();
-    },
-    "throws a SecurityError if not triggered by user activation"
-  );
-});
-
 async function runUserActivation(button) {
   button.disabled = true;
   const { contentWindow: iframeWindow } = document.getElementById("iframe");
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/META.yml b/third_party/blink/web_tests/external/wpt/pointerevents/META.yml
index be61ddd..1962feaf 100644
--- a/third_party/blink/web_tests/external/wpt/pointerevents/META.yml
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/META.yml
@@ -1,8 +1,6 @@
 spec: https://w3c.github.io/pointerevents/
 suggested_reviewers:
   - Steditor
-  - jacobrossi
   - plehegar
-  - scottgonzalez
   - RByers
   - NavidZ
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/META.yml b/third_party/blink/web_tests/external/wpt/referrer-policy/META.yml
index a622289..8ead043 100644
--- a/third_party/blink/web_tests/external/wpt/referrer-policy/META.yml
+++ b/third_party/blink/web_tests/external/wpt/referrer-policy/META.yml
@@ -1,5 +1,3 @@
 spec: https://w3c.github.io/webappsec-referrer-policy/
 suggested_reviewers:
-  - estark37
-  - jeisinger
   - domfarolino
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/META.yml b/third_party/blink/web_tests/external/wpt/resource-timing/META.yml
index a2ce7c48..76176970 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/META.yml
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/META.yml
@@ -1,6 +1,5 @@
 spec: https://w3c.github.io/resource-timing/
 suggested_reviewers:
-  - haoxli
   - plehegar
   - zqzhang
   - igrigorik
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/TAO-crossorigin-port.sub.html b/third_party/blink/web_tests/external/wpt/resource-timing/TAO-crossorigin-port.sub.html
new file mode 100644
index 0000000..0601217
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/TAO-crossorigin-port.sub.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Resource Timing TAO - "null" and opaque origin</title>
+<link rel="author" title="Google" href="http://www.google.com/" />
+<link rel="help" href="https://www.w3.org/TR/resource-timing-2/#timing-allow-origin"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+const t = async_test("Makes sure that the iframe passed the test and had an entry which passed the timing allow check");
+window.addEventListener("message", t.step_func_done(e=>{
+    assert_equals(e.data, "PASS");
+}));
+</script>
+</head>
+<body>
+<h1>Description</h1>
+<p>This test validates that for a cross origin resource with different ports, the timing allow check algorithm will fail when the value of Timing-Allow-Origin value has the right host but the wrong port in it.</p>
+<div id="log"></div>
+<!-- The frame is being requested on the default port ([0]), while the subresource in it will be requested on a separate port ([1]) -->
+<iframe id="frameContext" src="{{location[scheme]}}://{{host}}:{{ports[http][0]}}/resource-timing/resources/iframe-TAO-crossorigin-port.sub.html"></iframe>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/nested-context-navigations.html b/third_party/blink/web_tests/external/wpt/resource-timing/nested-context-navigations.html
new file mode 100644
index 0000000..483cc5b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/nested-context-navigations.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<meta name=timeout content=long>
+<title>Resource Timing embed navigate - back button navigation</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="resources/nested-contexts.js"></script>
+<script>
+    open_test_window("resources/embed-navigate-back.html",  "Test that embed navigations are not observable by the parent, even after history navigations by the parent");
+    open_test_window("resources/embed-navigate-back.html?crossorigin",  "Test that crossorigin embed navigations are not observable by the parent, even after history navigations by the parent");
+    open_test_window("resources/embed-navigate.html",  "Test that embed navigations are not observable by the parent");
+    open_test_window("resources/embed-navigate.html?crossorigin",  "Test that crossorigin embed navigations are not observable by the parent");
+    open_test_window("resources/embed-refresh.html",  "Test that embed refreshes are not observable by the parent");
+    open_test_window("resources/embed-refresh.html?crossorigin",  "Test that crossorigin embed refreshes are not observable by the parent");
+    open_test_window("resources/iframe-navigate-back.html",  "Test that iframe navigations are not observable by the parent, even after history navigations by the parent");
+    open_test_window("resources/iframe-navigate-back.html?crossorigin",  "Test that crossorigin iframe navigations are not observable by the parent, even after history navigations by the parent");
+    open_test_window("resources/iframe-navigate.html",  "Test that iframe navigations are not observable by the parent");
+    open_test_window("resources/iframe-navigate.html?crossorigin",  "Test that crossorigin iframe navigations are not observable by the parent");
+    open_test_window("resources/iframe-refresh.html",  "Test that iframe refreshes are not observable by the parent");
+    open_test_window("resources/iframe-refresh.html?crossorigin",  "Test that crossorigin iframe refreshes are not observable by the parent");
+    open_test_window("resources/object-navigate-back.html",  "Test that object navigations are not observable by the parent, even after history navigations by the parent");
+    open_test_window("resources/object-navigate-back.html?crossorigin",  "Test that crossorigin object navigations are not observable by the parent, even after history navigations by the parent");
+    open_test_window("resources/object-navigate.html",  "Test that object navigations are not observable by the parent");
+    open_test_window("resources/object-navigate.html?crossorigin",  "Test that crossorigin object navigations are not observable by the parent");
+    open_test_window("resources/object-refresh.html",  "Test that object refreshes are not observable by the parent");
+    open_test_window("resources/object-refresh.html?crossorigin",  "Test that crossorigin object refreshes are not observable by the parent");
+</script>
+
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/TAOResponse.py b/third_party/blink/web_tests/external/wpt/resource-timing/resources/TAOResponse.py
index fefc75b7..d98098c 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/resources/TAOResponse.py
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/TAOResponse.py
@@ -16,6 +16,12 @@
     elif tao == 'origin':
     # case-sensitive match for origin, pass
         response.headers.set('Timing-Allow-Origin', origin)
+    elif tao.startswith('origin_port'):
+    # case-sensitive match for origin and port, pass
+        origin_parts = origin.split(':')
+        host = origin_parts[0] + ':' + origin_parts[1]
+        port = tao.split('origin_port_')[1]
+        response.headers.set('Timing-Allow-Origin', host + ':' + port)
     elif tao == 'space':
     # space separated list of origin and wildcard, fail
         response.headers.set('Timing-Allow-Origin', (origin + ' *'))
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/document-navigated.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/document-navigated.html
new file mode 100644
index 0000000..fa87355
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/document-navigated.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+</head>
+<body>
+    navigated document!
+<script>
+    top.postMessage("navigated", "*");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/document-refreshed.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/document-refreshed.html
new file mode 100644
index 0000000..7e4ca09
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/document-refreshed.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+</head>
+<body>
+    Refreshed document!
+<script>
+    top.postMessage("refreshed", "*");
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/document-that-navigates.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/document-that-navigates.html
new file mode 100644
index 0000000..cb567bf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/document-that-navigates.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+</head>
+<body>
+<script>
+    location.href="document-navigated.html";
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/document-that-refreshes.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/document-that-refreshes.html
new file mode 100644
index 0000000..7552278
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/document-that-refreshes.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<meta http-equiv="refresh" content="0;document-refreshed.html">
+</head>
+<body></body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/embed-navigate-back.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/embed-navigate-back.html
new file mode 100644
index 0000000..3c3def1d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/embed-navigate-back.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Resource Timing embed navigate - back button navigation</title>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="nested-contexts.js"></script>
+<script>
+setup_back_navigation("embed-navigate-back.html");
+</script>
+<embed type="text/html">
+<script>
+    document.getElementsByTagName("embed")[0].src = pre_navigate_url;
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/embed-navigate.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/embed-navigate.html
new file mode 100644
index 0000000..20a73c6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/embed-navigate.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Resource Timing embed navigate</title>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="nested-contexts.js"></script>
+<script>
+    setup_navigate_test();
+</script>
+<div id=log></div>
+<embed type="text/html">
+<script>
+    document.getElementsByTagName("embed")[0].src = pre_navigate_url;
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/embed-refresh.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/embed-refresh.html
new file mode 100644
index 0000000..4a49fd0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/embed-refresh.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Resource Timing embed refresh</title>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="nested-contexts.js"></script>
+<script>
+    setup_refresh_test();
+</script>
+<div id=log></div>
+<embed type="text/html">
+<script>
+    document.getElementsByTagName("embed")[0].src = pre_refresh_url;
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/iframe-TAO-crossorigin-port.sub.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/iframe-TAO-crossorigin-port.sub.html
new file mode 100644
index 0000000..39f5d13
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/iframe-TAO-crossorigin-port.sub.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script>
+    const url = '{{location[scheme]}}://{{host}}:{{ports[http][1]}}/resource-timing/resources/TAOResponse.py?tao=origin_port_{{ports[http][1]}}';
+    const observe = (list, observer) => {
+        const entry = list.getEntries()[0];
+        const sum = entry.redirectStart +
+                  entry.redirectEnd +
+                  entry.domainLookupStart +
+                  entry.domainLookupEnd +
+                  entry.connectStart +
+                  entry.connectEnd +
+                  entry.secureConnectionStart +
+                  entry.requestStart +
+                  entry.responseStart +
+                  entry.transferSize +
+                  entry.encodedBodySize +
+                  entry.decodedBodySize;
+
+        const result = sum == 0 ? 'PASS' : 'FAIL';
+        window.top.postMessage(result, '*');
+    }
+    let observer = new PerformanceObserver(observe);
+    observer.observe({ entryTypes: ["resource"] });
+    fetch(url);
+</script>
+</body>
+</html>
+
+
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/iframe-navigate-back.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/iframe-navigate-back.html
new file mode 100644
index 0000000..c5c1fc1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/iframe-navigate-back.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Resource Timing iframe navigate - back button navigation</title>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="nested-contexts.js"></script>
+<script>
+setup_back_navigation("iframe-navigate-back.html");
+</script>
+<iframe></iframe>
+<script>
+    document.getElementsByTagName("iframe")[0].src = pre_navigate_url;
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/iframe-navigate.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/iframe-navigate.html
new file mode 100644
index 0000000..2a1a7e0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/iframe-navigate.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Resource Timing iframe navigate</title>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="nested-contexts.js"></script>
+<script>
+    setup_navigate_test();
+</script>
+<div id=log></div>
+<iframe></iframe>
+<script>
+    document.getElementsByTagName("iframe")[0].src = pre_navigate_url;
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/iframe-refresh.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/iframe-refresh.html
new file mode 100644
index 0000000..4ce3ea0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/iframe-refresh.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Resource Timing iframe refresh</title>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="nested-contexts.js"></script>
+<script>
+    setup_refresh_test();
+</script>
+<div id=log></div>
+<iframe></iframe>
+<script>
+    document.getElementsByTagName("iframe")[0].src = pre_refresh_url;
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/navigate_back.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/navigate_back.html
new file mode 100644
index 0000000..345eee1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/navigate_back.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<script>
+window.onload = function() {history.back();}
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/nested-contexts.js b/third_party/blink/web_tests/external/wpt/resource-timing/resources/nested-contexts.js
new file mode 100644
index 0000000..0c20224
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/nested-contexts.js
@@ -0,0 +1,95 @@
+let destination = location;
+if (location.search == "?crossorigin") {
+    const host_info = get_host_info()
+    destination = location.protocol + "//" + host_info["REMOTE_HOST"] + ":" + location.port;
+}
+
+const pre_navigate_url = new URL("/resource-timing/resources/document-that-navigates.html", destination).href;
+const post_navigate_url = new URL("/resource-timing/resources/document-navigated.html", destination).href;
+const pre_refresh_url = new URL("/resource-timing/resources/document-that-refreshes.html", destination).href;
+const post_refresh_url = new URL("/resource-timing/resources/document-refreshed.html", destination).href;
+
+function setup_navigate_or_refresh(type, pre, post) {
+    function verify_document_navigate_not_observable() {
+        let entries = performance.getEntriesByType("resource");
+        let found_first_document = false;
+        for (entry of entries) {
+            if (entry.name == pre) {
+                found_first_document = true;
+            }
+            if (entry.name == post) {
+                opener.postMessage("FAIL - " + type + " document should not be observable", "*");
+                return;
+            }
+        }
+        if (!found_first_document) {
+            opener.postMessage("FAIL - initial document should be observable", "*");
+            return;
+        }
+        opener.postMessage("PASS", "*");
+    }
+    window.addEventListener("message", e=>{
+        if (e.data == type) {
+            verify_document_navigate_not_observable();
+        }
+    });
+}
+
+function setup_navigate_test() {
+    setup_navigate_or_refresh("navigated", pre_navigate_url, post_navigate_url);
+}
+
+function setup_refresh_test() {
+    setup_navigate_or_refresh("refreshed", pre_refresh_url, post_refresh_url);
+}
+
+function setup_back_navigation(pushed_url) {
+    function verify_document_navigate_not_observable() {
+        let entries = performance.getEntriesByType("resource");
+        let found_first_document = false;
+        for (entry of entries) {
+            if (entry.name == pre_navigate_url) {
+                found_first_document = true;
+            }
+            if (entry.name == post_navigate_url) {
+                opener.postMessage("FAIL - navigated document exposed", "*");
+                return;
+            }
+        }
+        if (!found_first_document) {
+            opener.postMessage("FAIL - first document not exposed", "*");
+            return;
+        }
+        opener.postMessage("PASS", "*");
+    }
+    window.addEventListener("message", e=>{
+        if (e.data == "navigated") {
+            if (sessionStorage.navigated) {
+                delete sessionStorage.navigated;
+                verify_document_navigate_not_observable();
+            } else {
+                sessionStorage.navigated = true;
+                setTimeout(() => {
+                    history.pushState({}, "", pushed_url);
+                    location.href="navigate_back.html";
+                }, 0);
+            }
+        }
+    });
+}
+
+function open_test_window(url, message) {
+    promise_test(() => {
+        return new Promise((resolve, reject) => {
+            let openee = window.open(url);
+            addEventListener("message", e => {
+                openee.close();
+                if (e.data == "PASS") {
+                    resolve();
+                } else {
+                    reject(e.data);
+                }
+            });
+        });
+    }, message);
+}
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/object-navigate-back.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/object-navigate-back.html
new file mode 100644
index 0000000..64e5f58
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/object-navigate-back.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Resource Timing object navigate - back button navigation</title>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="nested-contexts.js"></script>
+<script>
+setup_back_navigation("object-navigate-back.html");
+</script>
+<object></object>
+<script>
+    document.getElementsByTagName("object")[0].data = pre_navigate_url;
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/object-navigate.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/object-navigate.html
new file mode 100644
index 0000000..cbb862e7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/object-navigate.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Resource Timing object navigate</title>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="nested-contexts.js"></script>
+<script>
+    setup_navigate_test();
+</script>
+<div id=log></div>
+<object></object>
+<script>
+    document.getElementsByTagName("object")[0].data = pre_navigate_url;
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/object-refresh.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/object-refresh.html
new file mode 100644
index 0000000..b14cf7f1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/object-refresh.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<title>Resource Timing object refresh</title>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="nested-contexts.js"></script>
+<script>
+    setup_refresh_test();
+</script>
+<div id=log></div>
+<object></object>
+<script>
+    document.getElementsByTagName("object")[0].data = pre_refresh_url;
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/META.yml b/third_party/blink/web_tests/external/wpt/screen-orientation/META.yml
index dc3f290..3ddb3b0 100644
--- a/third_party/blink/web_tests/external/wpt/screen-orientation/META.yml
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/META.yml
@@ -1,4 +1,3 @@
 spec: https://w3c.github.io/screen-orientation/
 suggested_reviewers:
-  - haoxli
   - marcoscaceres
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/lock-unlock-check-expected.txt b/third_party/blink/web_tests/external/wpt/screen-orientation/lock-unlock-check-expected.txt
new file mode 100644
index 0000000..b4d17d2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/lock-unlock-check-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL lock-unlock-check Uncaught SyntaxError: Unexpected token {
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/lock-unlock-check.html b/third_party/blink/web_tests/external/wpt/screen-orientation/lock-unlock-check.html
new file mode 100644
index 0000000..129882d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/lock-unlock-check.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script>
+  import { getOppositeOrientation } from "/screen-orientation/resources/orientation-utils.js";
+  promise_test(async t => {
+    await test_driver.bless("request full screen", () => {
+      return document.documentElement.requestFullscreen();
+    });
+    const newOrientation = getOppositeOrientation();
+    // This will reject, because the event will call lock() again.
+    const pMustReject = screen.orientation.lock(newOrientation);
+    // This one resolves, because we are re-locking.
+    const pMustResolve = new Promise(r => {
+      screen.orientation.onchange = () => {
+        r(orientation.lock("any"));
+      };
+    });
+    await promise_rejects(t, new TypeError(), pMustReject);
+    await pMustResolve;
+    screen.orientation.unlock();
+    return document.exitFullscreen();
+  }, "Re-locking orientation during event dispatch must reject existing orientationPendingPromise");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/screen-orientation/resources/orientation-utils.js b/third_party/blink/web_tests/external/wpt/screen-orientation/resources/orientation-utils.js
new file mode 100644
index 0000000..8721818b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/screen-orientation/resources/orientation-utils.js
@@ -0,0 +1,17 @@
+export async function loadIframe(src = "/screen-orientation/resources/blank.html") {
+  const iframe = document.createElement("iframe");
+  iframe.src = src;
+  document.body.appendChild(iframe);
+  return new Promise(r => {
+    if (iframe.contentDocument.readyState === "complete") {
+      return r(iframe);
+    }
+    iframe.onload = () => r(iframe);
+  });
+}
+
+export function getOppositeOrientation() {
+  const { type: currentOrientation } = screen.orientation;
+  const isPortrait = currentOrientation.includes("portrait");
+  return (newOrientation = `${isPortrait ? "landscape" : "portrait"}`);
+}
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/META.yml b/third_party/blink/web_tests/external/wpt/scroll-animations/META.yml
index 20f3c7e6..c53f1f432 100644
--- a/third_party/blink/web_tests/external/wpt/scroll-animations/META.yml
+++ b/third_party/blink/web_tests/external/wpt/scroll-animations/META.yml
@@ -1,6 +1,5 @@
 spec: https://wicg.github.io/scroll-animations/
 suggested_reviewers:
   - birtles
-  - theres-waldo
   - graouts
   - stephenmcgruer
diff --git a/third_party/blink/web_tests/external/wpt/selection/Document-open-expected.txt b/third_party/blink/web_tests/external/wpt/selection/Document-open-expected.txt
new file mode 100644
index 0000000..eaa85d4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/selection/Document-open-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Selection must not be replaced with a new object after document.open() assert_equals: After document.open(), the Selection object must be the same expected object "" but got object ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/selection/Document-open.html b/third_party/blink/web_tests/external/wpt/selection/Document-open.html
index 9d17091..9e3cb28 100644
--- a/third_party/blink/web_tests/external/wpt/selection/Document-open.html
+++ b/third_party/blink/web_tests/external/wpt/selection/Document-open.html
@@ -6,39 +6,23 @@
 <script>
 "use strict";
 
-// This tests the HTML spec requirement "Replace the Document's singleton
-// objects with new instances of those objects. (This includes in particular
-// the Window, Location, History, ApplicationCache, and Navigator, objects, the
-// various BarProp objects, the two Storage objects, the various HTMLCollection
-// objects, and objects defined by other specifications, like Selection and the
-// document's UndoManager. It also includes all the Web IDL prototypes in the
-// JavaScript binding, including the Document object's prototype.)" in the
-// document.open() algorithm.
+const iframe = document.createElement("iframe");
+async_test(t => {
+  iframe.onload = t.step_func_done(() => {
+    const originalSelection = iframe.contentWindow.getSelection();
+    assert_equals(originalSelection.rangeCount, 0, "rangeCount must initially be 0");
+    iframe.contentDocument.body.appendChild(iframe.contentDocument.createTextNode("foo"));
+    const range = iframe.contentDocument.createRange();
+    range.selectNodeContents(iframe.contentDocument.body);
+    iframe.contentWindow.getSelection().addRange(range);
+    assert_equals(originalSelection.rangeCount, 1, "rangeCount must be 1 after adding a range");
 
-var iframe = document.createElement("iframe");
-var t = async_test("Selection must be replaced with a new object after document.open()");
-iframe.onload = function() {
-    t.step(function() {
-        var originalSelection = iframe.contentWindow.getSelection();
-        assert_equals(originalSelection.rangeCount, 0,
-            "Sanity check: rangeCount must be initially 0");
-        iframe.contentDocument.body.appendChild(
-            iframe.contentDocument.createTextNode("foo"));
-        var range = iframe.contentDocument.createRange();
-        range.selectNodeContents(iframe.contentDocument.body);
-        iframe.contentWindow.getSelection().addRange(range);
-        assert_equals(originalSelection.rangeCount, 1,
-            "Sanity check: rangeCount must be 1 after adding a range");
+    iframe.contentDocument.open();
 
-        iframe.contentDocument.open();
-
-        assert_not_equals(iframe.contentWindow.getSelection(), originalSelection,
-            "After document.open(), the Selection object must no longer be the same");
-        assert_equals(iframe.contentWindow.getSelection().rangeCount, 0,
-            "After document.open(), rangeCount must be 0 again");
-    });
-    t.done();
+    assert_equals(iframe.contentWindow.getSelection(), originalSelection, "After document.open(), the Selection object must be the same");
+    assert_equals(iframe.contentWindow.getSelection().rangeCount, 1, "After document.open(), rangeCount must still be 1");
     document.body.removeChild(iframe);
-};
-document.body.appendChild(iframe);
+  });
+  document.body.appendChild(iframe);
+}, "Selection must not be replaced with a new object after document.open()");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/speech-api/META.yml b/third_party/blink/web_tests/external/wpt/speech-api/META.yml
index 4d1b42a..9ce8830 100644
--- a/third_party/blink/web_tests/external/wpt/speech-api/META.yml
+++ b/third_party/blink/web_tests/external/wpt/speech-api/META.yml
@@ -1,4 +1,3 @@
 spec: https://w3c.github.io/speech-api/
 suggested_reviewers:
   - foolip
-  - gshires
diff --git a/third_party/blink/web_tests/external/wpt/streams/META.yml b/third_party/blink/web_tests/external/wpt/streams/META.yml
index 108c774..1259a55 100644
--- a/third_party/blink/web_tests/external/wpt/streams/META.yml
+++ b/third_party/blink/web_tests/external/wpt/streams/META.yml
@@ -3,6 +3,5 @@
   - domenic
   - yutakahirano
   - youennf
-  - calvaris
   - wanderview
   - ricea
diff --git a/third_party/blink/web_tests/external/wpt/subresource-integrity/META.yml b/third_party/blink/web_tests/external/wpt/subresource-integrity/META.yml
index 2b8891ec..f6980682f 100644
--- a/third_party/blink/web_tests/external/wpt/subresource-integrity/META.yml
+++ b/third_party/blink/web_tests/external/wpt/subresource-integrity/META.yml
@@ -1,6 +1,5 @@
 spec: https://w3c.github.io/webappsec-subresource-integrity/
 suggested_reviewers:
   - metromoxie
-  - jonathanKingston
   - mikewest
   - hillbrad
diff --git a/third_party/blink/web_tests/external/wpt/svg/META.yml b/third_party/blink/web_tests/external/wpt/svg/META.yml
index 09ef583b..2904d6f60 100644
--- a/third_party/blink/web_tests/external/wpt/svg/META.yml
+++ b/third_party/blink/web_tests/external/wpt/svg/META.yml
@@ -1,6 +1,5 @@
 spec: https://svgwg.org/svg2-draft/
 suggested_reviewers:
-  - heycam
   - nikosandronikos
   - boggydigital
   - ewilligers
diff --git a/third_party/blink/web_tests/external/wpt/tools/ci/azure/affected_tests.yml b/third_party/blink/web_tests/external/wpt/tools/ci/azure/affected_tests.yml
index 17fca51..8076bc3 100644
--- a/third_party/blink/web_tests/external/wpt/tools/ci/azure/affected_tests.yml
+++ b/third_party/blink/web_tests/external/wpt/tools/ci/azure/affected_tests.yml
@@ -16,7 +16,7 @@
 - template: install_safari.yml
 - template: update_hosts.yml
 - template: update_manifest.yml
-- script: no_proxy='*' ./wpt run --yes --no-pause --no-fail-on-unexpected --no-restart-on-unexpected --affected ${{ parameters.affectedRange }} --log-wptreport $(Build.ArtifactStagingDirectory)/wpt_report.json --channel preview safari
+- script: no_proxy='*' ./wpt run --yes --no-pause --no-fail-on-unexpected --no-restart-on-unexpected --affected ${{ parameters.affectedRange }} --log-wptreport $(Build.ArtifactStagingDirectory)/wpt_report.json --log-wptscreenshot $(Build.ArtifactStagingDirectory)/wpt_screenshot.txt --channel preview safari
   displayName: 'Run tests'
 - task: PublishBuildArtifacts@1
   displayName: 'Publish results'
diff --git a/third_party/blink/web_tests/external/wpt/tools/ci/taskcluster-run.py b/third_party/blink/web_tests/external/wpt/tools/ci/taskcluster-run.py
index 78c50a6..fbd2f2ab 100755
--- a/third_party/blink/web_tests/external/wpt/tools/ci/taskcluster-run.py
+++ b/third_party/blink/web_tests/external/wpt/tools/ci/taskcluster-run.py
@@ -19,6 +19,12 @@
     return parser.parse_known_args(args)[0].log_wptreport
 
 
+def find_wptscreenshot(args):
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--log-wptscreenshot', action='store')
+    return parser.parse_known_args(args)[0].log_wptscreenshot
+
+
 def gzip_file(filename, delete_original=True):
     with open(filename, 'rb') as f_in:
         with gzip.open('%s.gz' % filename, 'wb') as f_out:
@@ -72,6 +78,9 @@
     wptreport = find_wptreport(wpt_args)
     if wptreport:
         gzip_file(wptreport)
+    wptscreenshot = find_wptscreenshot(wpt_args)
+    if wptscreenshot:
+        gzip_file(wptscreenshot)
 
 
 if __name__ == "__main__":
diff --git a/third_party/blink/web_tests/external/wpt/tools/manifest/manifest.py b/third_party/blink/web_tests/external/wpt/tools/manifest/manifest.py
index 7640136..dc57c24d 100644
--- a/third_party/blink/web_tests/external/wpt/tools/manifest/manifest.py
+++ b/third_party/blink/web_tests/external/wpt/tools/manifest/manifest.py
@@ -302,9 +302,8 @@
                 elif is_new or hash_changed:
                     self._data[new_type][rel_path] = set(manifest_items)
 
-                self._path_hash[rel_path] = (file_hash, new_type)
-
                 if is_new or hash_changed:
+                    self._path_hash[rel_path] = (file_hash, new_type)
                     changed = True
 
         deleted = prev_files - seen_files
diff --git a/third_party/blink/web_tests/external/wpt/tools/wpt/run.py b/third_party/blink/web_tests/external/wpt/tools/wpt/run.py
index df34e59..a19851d1 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wpt/run.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wpt/run.py
@@ -277,8 +277,6 @@
         if kwargs["browser_channel"] == "dev":
             logger.info("Automatically turning on experimental features for Chrome Dev")
             kwargs["binary_args"].append("--enable-experimental-web-platform-features")
-            # TODO(foolip): remove after unified plan is enabled on Chrome stable
-            kwargs["binary_args"].append("--enable-features=RTCUnifiedPlanByDefault")
 
         # Allow audio autoplay without a user gesture.
         kwargs["binary_args"].append("--autoplay-policy=no-user-gesture-required")
diff --git a/third_party/blink/web_tests/external/wpt/tools/wpt/virtualenv.py b/third_party/blink/web_tests/external/wpt/tools/wpt/virtualenv.py
index 61de936..357ddcbe 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wpt/virtualenv.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wpt/virtualenv.py
@@ -4,6 +4,8 @@
 import logging
 from distutils.spawn import find_executable
 
+import pkg_resources
+
 from tools.wpt.utils import call
 
 logger = logging.getLogger(__name__)
@@ -16,6 +18,7 @@
             self.virtualenv = find_executable("virtualenv")
             if not self.virtualenv:
                 raise ValueError("virtualenv must be installed and on the PATH")
+            self._working_set = None
 
     @property
     def exists(self):
@@ -24,6 +27,7 @@
     def create(self):
         if os.path.exists(self.path):
             shutil.rmtree(self.path)
+            self._working_set = None
         call(self.virtualenv, self.path, "-p", sys.executable)
 
     @property
@@ -39,6 +43,22 @@
             raise ValueError("pip not found")
         return path
 
+    @property
+    def lib_path(self):
+        if sys.platform == 'win32':
+            return os.path.join(self.path, 'Lib', 'site-packages')
+        return os.path.join(self.path, 'lib', 'python%s' % sys.version[:3], 'site-packages')
+
+    @property
+    def working_set(self):
+        if not self.exists:
+            raise ValueError("trying to read working_set when venv doesn't exist")
+
+        if self._working_set is None:
+            self._working_set = pkg_resources.WorkingSet((self.lib_path,))
+
+        return self._working_set
+
     def activate(self):
         path = os.path.join(self.bin_path, "activate_this.py")
         execfile(path, {"__file__": path})  # noqa: F821
@@ -49,11 +69,26 @@
         self.activate()
 
     def install(self, *requirements):
+        try:
+            self.working_set.require(*requirements)
+        except pkg_resources.ResolutionError:
+            pass
+        else:
+            return
+
         # `--prefer-binary` guards against race conditions when installation
         # occurs while packages are in the process of being published.
         call(self.pip_path, "install", "--prefer-binary", *requirements)
 
     def install_requirements(self, requirements_path):
+        with open(requirements_path) as f:
+            try:
+                self.working_set.require(f.read())
+            except pkg_resources.ResolutionError:
+                pass
+            else:
+                return
+
         # `--prefer-binary` guards against race conditions when installation
         # occurs while packages are in the process of being published.
         call(
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements.txt b/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements.txt
index 6216fb6..f17b12b 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements.txt
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements.txt
@@ -2,6 +2,6 @@
 mozinfo==0.10
 mozlog==4.0
 mozdebug==0.1.1
-pillow==5.2.0
+pillow==5.4.1
 urllib3[secure]==1.24.1
 requests==2.21.0
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements_firefox.txt b/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements_firefox.txt
index ee84d840f..668cea3 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements_firefox.txt
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements_firefox.txt
@@ -1,4 +1,4 @@
-marionette_driver==2.7.0
+marionette_driver==2.8.0
 mozprofile==2.2.0
 mozprocess==1.0.0
 mozcrash==1.1.0
diff --git a/third_party/blink/web_tests/external/wpt/url/META.yml b/third_party/blink/web_tests/external/wpt/url/META.yml
index 3a789a0..094b266 100644
--- a/third_party/blink/web_tests/external/wpt/url/META.yml
+++ b/third_party/blink/web_tests/external/wpt/url/META.yml
@@ -2,7 +2,6 @@
 suggested_reviewers:
   - mikewest
   - domenic
-  - Sebmaster
   - annevk
   - GPHemsley
   - TimothyGu
diff --git a/third_party/blink/web_tests/external/wpt/vibration/META.yml b/third_party/blink/web_tests/external/wpt/vibration/META.yml
index 0165889..91cd8c9d 100644
--- a/third_party/blink/web_tests/external/wpt/vibration/META.yml
+++ b/third_party/blink/web_tests/external/wpt/vibration/META.yml
@@ -1,4 +1,3 @@
 spec: https://w3c.github.io/vibration/
 suggested_reviewers:
-  - dontcallmedom
   - zqzhang
diff --git a/third_party/blink/web_tests/external/wpt/wake-lock/META.yml b/third_party/blink/web_tests/external/wpt/wake-lock/META.yml
index a5ff852..7ca3da2 100644
--- a/third_party/blink/web_tests/external/wpt/wake-lock/META.yml
+++ b/third_party/blink/web_tests/external/wpt/wake-lock/META.yml
@@ -1,5 +1,4 @@
 spec: https://w3c.github.io/wake-lock/
 suggested_reviewers:
-  - andrey-logvinov
   - marcoscaceres
   - Honry
diff --git a/third_party/blink/web_tests/external/wpt/webmessaging/META.yml b/third_party/blink/web_tests/external/wpt/webmessaging/META.yml
index e70b780b..95d5071 100644
--- a/third_party/blink/web_tests/external/wpt/webmessaging/META.yml
+++ b/third_party/blink/web_tests/external/wpt/webmessaging/META.yml
@@ -1,7 +1,6 @@
 spec: https://html.spec.whatwg.org/multipage/web-messaging.html
 suggested_reviewers:
   - zqzhang
-  - aogilvie
   - jdm
   - mkruisselbrink
   - annevk
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/META.yml b/third_party/blink/web_tests/external/wpt/webrtc/META.yml
index 2025a11..eed4ac834 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/META.yml
+++ b/third_party/blink/web_tests/external/wpt/webrtc/META.yml
@@ -3,10 +3,8 @@
   - snuggs
   - agouaillard
   - alvestrand
-  - dontcallmedom
   - guidou
   - henbos
-  - phoglund
   - youennf
   - rwaldron
   - jan-ivar
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-getStats.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-getStats.https.html
index 247402b8..c2c4e8e 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-getStats.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-getStats.https.html
@@ -173,19 +173,18 @@
         - All stats objects referenced directly or indirectly by the RTCOutboundRTPStreamStats
           objects added.
    */
-  promise_test(t => {
-    const pc = new RTCPeerConnection();
-    t.add_cleanup(() => pc.close());
-    return getTrackFromUserMedia('audio')
-    .then(([track, mediaStream]) => {
-      pc.addTrack(track, mediaStream);
+  promise_test(async t => {
+    const pc = createPeerConnectionWithCleanup(t);
+    const pc2 = createPeerConnectionWithCleanup(t);
 
-      return pc.getStats(track)
-      .then(statsReport => {
-        validateStatsReport(statsReport);
-        assert_stats_report_has_stats(statsReport, ['outbound-rtp']);
-      });
-    });
+    let [track, mediaStream] = await getTrackFromUserMedia('audio');
+    pc.addTrack(track, mediaStream);
+    exchangeIceCandidates(pc, pc2);
+    await doSignalingHandshake(pc, pc2);
+    await listenToIceConnected(pc);
+    const stats = await pc.getStats(track);
+    validateStatsReport(stats);
+    assert_stats_report_has_stats(stats, ['outbound-rtp']);
   }, `getStats() on track associated with RtpSender should return stats report containing outbound-rtp stats`);
 
 
@@ -197,16 +196,20 @@
         - All stats objects referenced directly or indirectly by the RTCInboundRTPStreamStats
           added.
    */
-  promise_test(t => {
-    const pc = new RTCPeerConnection();
-    t.add_cleanup(() => pc.close());
-    const transceiver = pc.addTransceiver('audio');
+  promise_test(async t => {
+    const pc = createPeerConnectionWithCleanup(t);
+    const pc2 = createPeerConnectionWithCleanup(t);
 
-    return pc.getStats(transceiver.receiver.track)
-    .then(statsReport => {
-      validateStatsReport(statsReport);
-      assert_stats_report_has_stats(statsReport, ['inbound-rtp']);
+    let [track, mediaStream] = await getTrackFromUserMedia('audio');
+    pc.addTrack(track, mediaStream);
+    exchangeIceCandidates(pc, pc2);
+    await doSignalingHandshake(pc, pc2);
+    await new Promise(resolve => {
+      pc2.getReceivers()[0].track.addEventListener('unmute', resolve);
     });
+    const stats = await pc2.getStats(track);
+    validateStatsReport(stats);
+    assert_stats_report_has_stats(stats, ['inbound-rtp']);
   }, `getStats() on track associated with RtpReceiver should return stats report containing inbound-rtp stats`);
 
   /*
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded-expected.txt
index 0861101..62c3abf 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded-expected.txt
@@ -5,6 +5,6 @@
 FAIL Calling addTransceiver() twice should fire negotiationneeded event once assert_unreached: Pending promise should never be resolved. Instead it is fulfilled with: [object Object] Reached unreachable code
 FAIL Calling both addTransceiver() and createDataChannel() should fire negotiationneeded event once assert_unreached: Pending promise should never be resolved. Instead it is fulfilled with: [object Object] Reached unreachable code
 PASS negotiationneeded event should not fire if signaling state is not stable
-FAIL negotiationneeded event should fire only after signaling state go back to stable assert_unreached: Expect negotiationneeded promise to resolve after pc has set remote answer and go back to stable state Reached unreachable code
+FAIL negotiationneeded event should fire only after signaling state go back to stable assert_false: negotiationneeded should not fire until the next iteration of the event loop after returning to stable expected false got true
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded.html
index ac9d70c..f7bf8bd3 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded.html
@@ -187,22 +187,21 @@
         2.  If connection's [[NegotiationNeeded]] slot is false, abort these steps.
         3.  Fire a simple event named negotiationneeded at connection.
    */
-  promise_test(t => {
+  promise_test(async t => {
     const pc = new RTCPeerConnection();
 
     t.add_cleanup(() => pc.close());
 
-    return assert_first_promise_fulfill_after_second(
-      awaitNegotiation(pc),
-      generateAudioReceiveOnlyOffer(pc)
-      .then(offer =>
-        pc.setLocalDescription(offer)
-        .then(() => {
-          pc.createDataChannel('test');
-          return generateAnswer(offer);
-        }))
-      .then(answer => pc.setRemoteDescription(answer)),
-      'Expect negotiationneeded promise to resolve after pc has set remote answer and go back to stable state');
+    pc.addTransceiver('audio');
+    const offer = await pc.createOffer();
+    await pc.setLocalDescription(offer);
+    let fired = false;
+    pc.onnegotiationneeded = e => fired = true;
+    pc.createDataChannel('test');
+    const answer = await generateAnswer(offer);
+    await pc.setRemoteDescription(answer);
+    assert_false(fired, "negotiationneeded should not fire until the next iteration of the event loop after returning to stable");
+    await new Promise(resolve => pc.onnegotiationneeded = resolve);
   }, 'negotiationneeded event should fire only after signaling state go back to stable');
 
   /*
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription.html
index 5e9b543..2becbd3 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription.html
@@ -72,29 +72,55 @@
         })));
   }, 'Calling createOffer() and setLocalDescription() again after one round of local-offer/remote-answer should succeed');
 
-  promise_test(t => {
-    const pc = new RTCPeerConnection();
-    t.add_cleanup(() => pc.close());
+  promise_test(async t => {
+    const pc1 = new RTCPeerConnection();
+    t.add_cleanup(() => pc1.close());
+
+    const pc2 = new RTCPeerConnection();
+    t.add_cleanup(() => pc2.close());
 
     const states = [];
-    pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
+    pc1.addEventListener('signalingstatechange', () => states.push(pc1.signalingState));
 
-    return generateDataChannelOffer(pc)
-    .then(offer => pc.setRemoteDescription(offer))
-    .then(() => pc.createAnswer())
-    .then(answer =>
-      pc.setLocalDescription(answer)
-      .then(() => generateVideoReceiveOnlyOffer(pc))
-      .then(offer =>
-        pc.setLocalDescription(offer)
-        .then(() => {
-          assert_equals(pc.signalingState, 'have-local-offer');
-          assert_session_desc_similar(pc.localDescription, offer);
-          assert_session_desc_similar(pc.currentLocalDescription, answer);
-          assert_session_desc_similar(pc.pendingLocalDescription, offer);
+    assert_equals(pc1.localDescription, null);
+    assert_equals(pc1.currentLocalDescription, null);
+    assert_equals(pc1.pendingLocalDescription, null);
 
-          assert_array_equals(states, ['have-remote-offer', 'stable', 'have-local-offer']);
-        })));
+    pc1.createDataChannel('test');
+    const offer = await pc1.createOffer();
+
+    assert_equals(pc1.localDescription, null);
+    assert_equals(pc1.currentLocalDescription, null);
+    assert_equals(pc1.pendingLocalDescription, null);
+
+    await pc1.setLocalDescription(offer);
+
+    assert_session_desc_similar(pc1.localDescription, offer);
+    assert_equals(pc1.currentLocalDescription, null);
+    assert_session_desc_similar(pc1.pendingLocalDescription, offer);
+
+    await pc2.setRemoteDescription(offer);
+    const answer = await pc2.createAnswer();
+    await pc2.setLocalDescription(answer);
+    await pc1.setRemoteDescription(answer);
+
+    assert_equals(pc1.signalingState, 'stable');
+    assert_session_desc_similar(pc1.localDescription, offer);
+    assert_session_desc_similar(pc1.currentLocalDescription, offer);
+    assert_equals(pc1.pendingLocalDescription, null);
+
+    const stream = await getNoiseStream({audio:true});
+    pc2.addTrack(stream.getTracks()[0], stream);
+
+    const reoffer = await pc2.createOffer();
+    await pc2.setLocalDescription(reoffer);
+    await pc1.setRemoteDescription(reoffer);
+    const reanswer = await pc1.createAnswer();
+    await pc1.setLocalDescription(reanswer);
+
+    assert_session_desc_similar(pc1.localDescription, reanswer);
+    assert_session_desc_similar(pc1.currentLocalDescription, reanswer);
+    assert_equals(pc1.pendingLocalDescription, null);
   }, 'Switching role from answerer to offerer after going back to stable state should succeed');
 
   promise_test(async t => {
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-transceivers.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-transceivers.https.html
index f56a170..9b3a9a8 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-transceivers.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-transceivers.https.html
@@ -139,9 +139,13 @@
   const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
   assert_true(trackEvent.track instanceof MediaStreamTrack,
               'trackEvent.track instanceof MediaStreamTrack');
-  assert_equals(trackEvent.track.id, track.id,
-                'trackEvent.track.id == track.id');
-}, 'setRemoteDescription(offer): ontrack\'s track.id is the same as track.id');
+  assert_equals(trackEvent.streams.length, 1,
+                'trackEvent contains a single stream');
+  assert_true(trackEvent.streams[0] instanceof MediaStream,
+              'trackEvent has a MediaStream');
+  assert_equals(trackEvent.streams[0].id, stream.id,
+                'trackEvent.streams[0].id == stream.id');
+}, 'setRemoteDescription(offer): ontrack\'s stream.id is the same as stream.id');
 
 promise_test(async t => {
   const pc1 = createPeerConnectionWithCleanup(t);
diff --git a/third_party/blink/web_tests/external/wpt/webstorage/META.yml b/third_party/blink/web_tests/external/wpt/webstorage/META.yml
index 0da67a58..020075c3 100644
--- a/third_party/blink/web_tests/external/wpt/webstorage/META.yml
+++ b/third_party/blink/web_tests/external/wpt/webstorage/META.yml
@@ -3,5 +3,4 @@
   - siusin
   - inexorabletash
   - zqzhang
-  - ibelem
   - jdm
diff --git a/third_party/blink/web_tests/external/wpt/webxr/META.yml b/third_party/blink/web_tests/external/wpt/webxr/META.yml
index b5e3e65a..520afec 100644
--- a/third_party/blink/web_tests/external/wpt/webxr/META.yml
+++ b/third_party/blink/web_tests/external/wpt/webxr/META.yml
@@ -1,5 +1,3 @@
 spec: https://immersive-web.github.io/webxr/spec/latest/
 suggested_reviewers:
-  - toji
-  - paezagon
   - klausw
diff --git a/third_party/blink/web_tests/external/wpt/xhr/META.yml b/third_party/blink/web_tests/external/wpt/xhr/META.yml
index 4b2ecf3..c343ceac 100644
--- a/third_party/blink/web_tests/external/wpt/xhr/META.yml
+++ b/third_party/blink/web_tests/external/wpt/xhr/META.yml
@@ -2,9 +2,6 @@
 suggested_reviewers:
   - caitp
   - Manishearth
-  - jungkees
-  - ibelem
-  - mathiasbynens
   - jdm
   - annevk
   - wisniewskit
diff --git a/third_party/blink/web_tests/fast/spatial-navigation/snav-focusless-focused-editable-blocks-movement.html b/third_party/blink/web_tests/fast/spatial-navigation/snav-focusless-focused-editable-blocks-movement.html
new file mode 100644
index 0000000..dca44e9
--- /dev/null
+++ b/third_party/blink/web_tests/fast/spatial-navigation/snav-focusless-focused-editable-blocks-movement.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/snav-testharness.js"></script>
+
+<style>
+  .box {
+    width: 100px;
+    height: 30px;
+    margin: 5px;
+    border: 1px solid black;
+    display: inline-block;
+  }
+</style>
+
+<div class="box" tabindex="0">Top-Left</div>
+<div class="box" tabindex="0">Top</div>
+
+<div class="container">
+  <div class="box" tabindex="0">Left</div>
+  <input class="box" id="input" type="text" value="center">
+  <div class="box" tabindex="0">Right</div>
+</div>
+
+<div class="box" tabindex="0">Bottom-Left</div>
+<div class="box" tabindex="0">Bottom</div>
+
+<script>
+  // This test ensures that when an editable has focus, arrow keys don't cause
+  // spatial-navigation movement.
+  let first = document.getElementById("first");
+  let second = document.getElementById("second");
+  let third = document.getElementById("third");
+
+  let input = document.getElementById("input");
+
+  snav.assertSnavEnabledAndTestable(true /* focuslessSpatNav */ );
+
+  function testDirection(direction, expectMove) {
+    // We move twice because the first move will be interpreted as an editor
+    // command while the second will be ignored by the editor. We shouldn't
+    // move interest in either case.
+    snav.triggerMove(direction);
+    snav.triggerMove(direction);
+
+    if (expectMove) {
+      assert_not_equals(
+          window.internals.interestedElement,
+          input,
+          direction + " key expected to move interest but didn't,");
+    } else {
+      assert_equals(
+          window.internals.interestedElement,
+          input,
+          direction + " key did not expect to move interest but did,");
+    }
+
+    // Reset focus so the focused input box starts in a consistent state (fully
+    // selected) for the next test.
+    eventSender.keyDown('Escape');
+    eventSender.keyDown('Enter');
+  }
+
+  test(() => {
+    // Move interest to editable 'input' box and focus it.
+    snav.triggerMove('Down');
+    snav.triggerMove('Down');
+    snav.triggerMove('Right');
+    eventSender.keyDown('Enter');
+    assert_equals(document.activeElement, input);
+    assert_equals(window.internals.interestedElement, input);
+
+    // Ensure directional keys don't cause spatial navigation to move interest.
+    // We move twice because the first move will be interpreted as an editor
+    // command while the second will be ignored by the editor. We shouldn't
+    // move interest in either case.
+    let expectMove = false;
+    testDirection('Down', expectMove);
+    testDirection('Left', expectMove);
+    testDirection('Right', expectMove);
+    testDirection('Up', expectMove);
+
+    // Ensure removing focus allows movement again.
+    eventSender.keyDown('Escape');
+
+    expectMove = true;
+    testDirection('Down', expectMove);
+  }, "Enter key moves focus into interested element");
+</script>
diff --git a/third_party/blink/web_tests/http/tests/devtools/profiler/agents-disabled-check-expected.txt b/third_party/blink/web_tests/http/tests/devtools/profiler/agents-disabled-check-expected.txt
index 1042f9a..615bad0 100644
--- a/third_party/blink/web_tests/http/tests/devtools/profiler/agents-disabled-check-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/profiler/agents-disabled-check-expected.txt
@@ -3,10 +3,9 @@
 --> SDK.targetManager.suspendAllTargets();
 frontend: {"id":<number>,"method":"Debugger.disable"}
 frontend: {"id":<number>,"method":"Debugger.setAsyncCallStackDepth","params":{"maxDepth":0}}
-frontend: {"id":<number>,"method":"Overlay.setPausedInDebuggerMessage"}
 frontend: {"id":<number>,"method":"DOM.disable"}
 frontend: {"id":<number>,"method":"CSS.disable"}
-frontend: {"id":<number>,"method":"Overlay.setSuspended","params":{"suspended":true}}
+frontend: {"id":<number>,"method":"Overlay.disable"}
 frontend: {"id":<number>,"method":"Target.setAutoAttach","params":{"autoAttach":true,"waitForDebuggerOnStart":false,"flatten":true}}
 
 --> SDK.targetManager.resumeAllTargets();
@@ -15,7 +14,8 @@
 frontend: {"id":<number>,"method":"Debugger.setAsyncCallStackDepth","params":{"maxDepth":32}}
 frontend: {"id":<number>,"method":"DOM.enable"}
 frontend: {"id":<number>,"method":"CSS.enable"}
-frontend: {"id":<number>,"method":"Overlay.setSuspended","params":{"suspended":false}}
+frontend: {"id":<number>,"method":"Overlay.enable"}
+frontend: {"id":<number>,"method":"Overlay.setShowViewportSizeOnResize","params":{"show":true}}
 frontend: {"id":<number>,"method":"Target.setAutoAttach","params":{"autoAttach":true,"waitForDebuggerOnStart":true,"flatten":true}}
 
 --> done
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations-expected.txt
new file mode 100644
index 0000000..39e546e
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations-expected.txt
@@ -0,0 +1,21 @@
+This is a testharness.js-based test.
+PASS Test that embed navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that crossorigin embed navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that embed navigations are not observable by the parent
+PASS Test that crossorigin embed navigations are not observable by the parent
+PASS Test that embed refreshes are not observable by the parent
+PASS Test that crossorigin embed refreshes are not observable by the parent
+PASS Test that iframe navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that crossorigin iframe navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that iframe navigations are not observable by the parent
+PASS Test that crossorigin iframe navigations are not observable by the parent
+PASS Test that iframe refreshes are not observable by the parent
+PASS Test that crossorigin iframe refreshes are not observable by the parent
+FAIL Test that object navigations are not observable by the parent, even after history navigations by the parent promise_test: Unhandled rejection with value: "FAIL - first document not exposed"
+FAIL Test that crossorigin object navigations are not observable by the parent, even after history navigations by the parent promise_test: Unhandled rejection with value: "FAIL - first document not exposed"
+PASS Test that object navigations are not observable by the parent
+PASS Test that crossorigin object navigations are not observable by the parent
+PASS Test that object refreshes are not observable by the parent
+PASS Test that crossorigin object refreshes are not observable by the parent
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations-expected.txt
new file mode 100644
index 0000000..b88a5245
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations-expected.txt
@@ -0,0 +1,21 @@
+This is a testharness.js-based test.
+PASS Test that embed navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that crossorigin embed navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that embed navigations are not observable by the parent
+PASS Test that crossorigin embed navigations are not observable by the parent
+PASS Test that embed refreshes are not observable by the parent
+PASS Test that crossorigin embed refreshes are not observable by the parent
+PASS Test that iframe navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that crossorigin iframe navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that iframe navigations are not observable by the parent
+PASS Test that crossorigin iframe navigations are not observable by the parent
+PASS Test that iframe refreshes are not observable by the parent
+PASS Test that crossorigin iframe refreshes are not observable by the parent
+FAIL Test that object navigations are not observable by the parent, even after history navigations by the parent promise_test: Unhandled rejection with value: "FAIL - first document not exposed"
+PASS Test that crossorigin object navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that object navigations are not observable by the parent
+PASS Test that crossorigin object navigations are not observable by the parent
+PASS Test that object refreshes are not observable by the parent
+PASS Test that crossorigin object refreshes are not observable by the parent
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/mac/virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations-expected.txt
new file mode 100644
index 0000000..39e546e
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations-expected.txt
@@ -0,0 +1,21 @@
+This is a testharness.js-based test.
+PASS Test that embed navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that crossorigin embed navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that embed navigations are not observable by the parent
+PASS Test that crossorigin embed navigations are not observable by the parent
+PASS Test that embed refreshes are not observable by the parent
+PASS Test that crossorigin embed refreshes are not observable by the parent
+PASS Test that iframe navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that crossorigin iframe navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that iframe navigations are not observable by the parent
+PASS Test that crossorigin iframe navigations are not observable by the parent
+PASS Test that iframe refreshes are not observable by the parent
+PASS Test that crossorigin iframe refreshes are not observable by the parent
+FAIL Test that object navigations are not observable by the parent, even after history navigations by the parent promise_test: Unhandled rejection with value: "FAIL - first document not exposed"
+FAIL Test that crossorigin object navigations are not observable by the parent, even after history navigations by the parent promise_test: Unhandled rejection with value: "FAIL - first document not exposed"
+PASS Test that object navigations are not observable by the parent
+PASS Test that crossorigin object navigations are not observable by the parent
+PASS Test that object refreshes are not observable by the parent
+PASS Test that crossorigin object refreshes are not observable by the parent
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win/virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations-expected.txt b/third_party/blink/web_tests/platform/win/virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations-expected.txt
new file mode 100644
index 0000000..b88a5245
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations-expected.txt
@@ -0,0 +1,21 @@
+This is a testharness.js-based test.
+PASS Test that embed navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that crossorigin embed navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that embed navigations are not observable by the parent
+PASS Test that crossorigin embed navigations are not observable by the parent
+PASS Test that embed refreshes are not observable by the parent
+PASS Test that crossorigin embed refreshes are not observable by the parent
+PASS Test that iframe navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that crossorigin iframe navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that iframe navigations are not observable by the parent
+PASS Test that crossorigin iframe navigations are not observable by the parent
+PASS Test that iframe refreshes are not observable by the parent
+PASS Test that crossorigin iframe refreshes are not observable by the parent
+FAIL Test that object navigations are not observable by the parent, even after history navigations by the parent promise_test: Unhandled rejection with value: "FAIL - first document not exposed"
+PASS Test that crossorigin object navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that object navigations are not observable by the parent
+PASS Test that crossorigin object navigations are not observable by the parent
+PASS Test that object refreshes are not observable by the parent
+PASS Test that crossorigin object refreshes are not observable by the parent
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win7/virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations-expected.txt b/third_party/blink/web_tests/platform/win7/virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations-expected.txt
new file mode 100644
index 0000000..39e546e
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/virtual/omt-worker-fetch/external/wpt/resource-timing/nested-context-navigations-expected.txt
@@ -0,0 +1,21 @@
+This is a testharness.js-based test.
+PASS Test that embed navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that crossorigin embed navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that embed navigations are not observable by the parent
+PASS Test that crossorigin embed navigations are not observable by the parent
+PASS Test that embed refreshes are not observable by the parent
+PASS Test that crossorigin embed refreshes are not observable by the parent
+PASS Test that iframe navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that crossorigin iframe navigations are not observable by the parent, even after history navigations by the parent
+PASS Test that iframe navigations are not observable by the parent
+PASS Test that crossorigin iframe navigations are not observable by the parent
+PASS Test that iframe refreshes are not observable by the parent
+PASS Test that crossorigin iframe refreshes are not observable by the parent
+FAIL Test that object navigations are not observable by the parent, even after history navigations by the parent promise_test: Unhandled rejection with value: "FAIL - first document not exposed"
+FAIL Test that crossorigin object navigations are not observable by the parent, even after history navigations by the parent promise_test: Unhandled rejection with value: "FAIL - first document not exposed"
+PASS Test that object navigations are not observable by the parent
+PASS Test that crossorigin object navigations are not observable by the parent
+PASS Test that object refreshes are not observable by the parent
+PASS Test that crossorigin object refreshes are not observable by the parent
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/binary-for-devtools/http/tests/devtools/README.txt b/third_party/blink/web_tests/virtual/binary-for-devtools/http/tests/devtools/README.txt
new file mode 100644
index 0000000..0ac69026
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/binary-for-devtools/http/tests/devtools/README.txt
@@ -0,0 +1,2 @@
+# This suite runs the tests in http/tests/devtools with
+# the additional flag --enable-internal-devtools-binary-protocol.
diff --git a/third_party/blink/web_tests/virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/README.txt b/third_party/blink/web_tests/virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/README.txt
new file mode 100644
index 0000000..36800ce
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/binary-for-inspector-protocol/http/tests/inspector-protocol/README.txt
@@ -0,0 +1,2 @@
+# This suite runs the tests in http/tests/inspector-protocol with
+# the additional flag --enable-internal-devtools-binary-protocol.
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded-expected.txt
index 64d94456..2da577f 100644
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded-expected.txt
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-onnegotiationneeded-expected.txt
@@ -5,6 +5,6 @@
 FAIL Calling addTransceiver() twice should fire negotiationneeded event once Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument.
 FAIL Calling both addTransceiver() and createDataChannel() should fire negotiationneeded event once assert_unreached: Pending promise should never be resolved. Instead it is rejected with: InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument. Reached unreachable code
 PASS negotiationneeded event should not fire if signaling state is not stable
-FAIL negotiationneeded event should fire only after signaling state go back to stable assert_unreached: Expect negotiationneeded promise to resolve after pc has set remote answer and go back to stable state Reached unreachable code
+FAIL negotiationneeded event should fire only after signaling state go back to stable promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt
index f265ed42..f6cc537 100644
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt
@@ -11,7 +11,7 @@
 FAIL setLocalDescription(offer): transceiver gets associated with an m-section promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'mid' of null"
 FAIL setLocalDescription(offer): transceiver.mid matches the offer SDP promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'mid' of null"
 PASS setRemoteDescription(offer): ontrack fires with a track
-PASS setRemoteDescription(offer): ontrack's track.id is the same as track.id
+PASS setRemoteDescription(offer): ontrack's stream.id is the same as stream.id
 FAIL setRemoteDescription(offer): ontrack fires with a transceiver. assert_true: trackEvent.transceiver instanceof RTCRtpTransceiver expected true got false
 FAIL setRemoteDescription(offer): transceiver.mid is the same on both ends promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'mid' of null"
 FAIL setRemoteDescription(offer): "transceiver == {sender,receiver}" assert_array_equals: pc2.getTransceivers() equals [transceiver] lengths differ, expected 1 got 0
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index a7681dd4..a5901da0 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: unknown
-Revision: 99bf283e54d049b6f5d2ad5522c6e3094b7156b4
+Revision: 1bb8ca4059d8bcc933478e02d7869dda7daa0263
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/BUILD.gn b/third_party/crashpad/crashpad/BUILD.gn
index ce9edf7..10850c6 100644
--- a/third_party/crashpad/crashpad/BUILD.gn
+++ b/third_party/crashpad/crashpad/BUILD.gn
@@ -37,7 +37,6 @@
     import("//build/package.gni")
     package("crashpad_test") {
       testonly = true
-      deprecated_system_image = true
 
       deps = [
         ":crashpad_tests",
@@ -55,19 +54,21 @@
         },
       ]
 
-      # Note that the infix of "crashpad_tests" below in
-      # binary/resource entries should be removed once
-      # crashpad_tests is moved out of the system image;
-      # until then, it is used to disambiguate the crashpad
-      # binaries and data from others within /system/(bin|data).
+      meta = [
+        {
+          path = "test/fuchsia_crashpad_tests.cmx"
+          dest = "crashpad_tests.cmx"
+        },
+      ]
+
       binaries = [
         {
           name = "crashpad_test_test_multiprocess_exec_test_child"
-          dest = "crashpad_tests/crashpad_test_test_multiprocess_exec_test_child"
+          dest = "crashpad_test_test_multiprocess_exec_test_child"
         },
         {
           name = "http_transport_test_server"
-          dest = "crashpad_tests/http_transport_test_server"
+          dest = "http_transport_test_server"
         },
       ]
 
@@ -89,52 +90,34 @@
       resources = [
         {
           path = "util/net/testdata/ascii_http_body.txt"
-          dest = "crashpad_tests/util/net/testdata/ascii_http_body.txt"
+          dest = "util/net/testdata/ascii_http_body.txt"
         },
         {
           path = "util/net/testdata/binary_http_body.dat"
-          dest = "crashpad_tests/util/net/testdata/binary_http_body.dat"
+          dest = "util/net/testdata/binary_http_body.dat"
         },
         {
           path = "test/test_paths_test_data_root.txt"
-          dest = "crashpad_tests/test/test_paths_test_data_root.txt"
+          dest = "test/test_paths_test_data_root.txt"
         },
       ]
 
       if (crashpad_use_boringssl_for_http_transport_socket) {
-        deps += [
-          "util:generate_test_server_key",
-        ]
+        deps += [ "util:generate_test_server_key" ]
         resources += [
           {
             path = "$root_out_dir/crashpad_util_test_cert.pem"
-            dest = "crashpad_tests/crashpad_util_test_cert.pem"
+            dest = "crashpad_util_test_cert.pem"
           },
           {
             path = "$root_out_dir/crashpad_util_test_key.pem"
-            dest = "crashpad_tests/crashpad_util_test_key.pem"
+            dest = "crashpad_util_test_key.pem"
           },
         ]
       }
     }
 
-    package("crashpad_handler") {
-      deprecated_system_image = true
-
-      deps = [
-        "handler:crashpad_handler",
-      ]
-
-      binaries = [
-        {
-          name = "crashpad_handler"
-        },
-      ]
-    }
-
     package("crashpad_database_util") {
-      deprecated_system_image = true
-
       deps = [
         "tools:crashpad_database_util",
       ]
@@ -142,6 +125,7 @@
       binaries = [
         {
           name = "crashpad_database_util"
+          shell = true
         },
       ]
     }
diff --git a/third_party/crashpad/crashpad/DEPS b/third_party/crashpad/crashpad/DEPS
index 0c8edf20..4bb7d65e 100644
--- a/third_party/crashpad/crashpad/DEPS
+++ b/third_party/crashpad/crashpad/DEPS
@@ -20,17 +20,17 @@
 
 deps = {
   'buildtools':
-      Var('chromium_git') + '/chromium/buildtools.git@' +
-      '6fe4a3251488f7af86d64fc25cf442e817cf6133',
+      Var('chromium_git') + '/chromium/src/buildtools.git@' +
+      '3e50219fc4503f461b2176a9976891b28d80f9ab',
   'crashpad/third_party/gtest/gtest':
       Var('chromium_git') + '/external/github.com/google/googletest@' +
-      '9518a57428ae0a7ed450c1361768e84a2a38af5a',
+      '8b6d3f9c4a774bef3081195d422993323b6bb2e0',
   'crashpad/third_party/gyp/gyp':
       Var('chromium_git') + '/external/gyp@' +
-      '5e2b3ddde7cda5eb6bc09a5546a76b00e49d888f',
+      '8bee09f4a57807136593ddc906b0b213c21f9014',
   'crashpad/third_party/mini_chromium/mini_chromium':
       Var('chromium_git') + '/chromium/mini_chromium@' +
-      '737433ebade4d446643c6c07daae02a67e8decca',
+      'df0c375531b7cd554e10ad757c5d2372780a1138',
   'crashpad/third_party/libfuzzer/src':
       Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' +
       'fda403cf93ecb8792cb1d061564d89a6553ca020',
@@ -89,22 +89,24 @@
     'condition': 'checkout_fuchsia and host_os == "linux"',
     'dep_type': 'cipd'
   },
-  'crashpad/third_party/fuchsia/sdk/linux-amd64': {
-    # The SDK is keyed to the host system because it contains build tools.
-    # Currently, linux-amd64 is the only SDK published (see
-    # https://chrome-infra-packages.appspot.com/#/?path=fuchsia/sdk).
-    # As long as this is the case, use that SDK package
-    # even on other build hosts.
-    # The sysroot (containing headers and libraries) and other components are
-    # related to the target and should be functional with an appropriate
-    # toolchain that runs on the build host (fuchsia_clang, above).
+  'crashpad/third_party/fuchsia/sdk/mac-amd64': {
     'packages': [
       {
-        'package': 'fuchsia/sdk/linux-amd64',
+        'package': 'fuchsia/sdk/core/mac-amd64',
         'version': 'latest'
       },
     ],
-    'condition': 'checkout_fuchsia',
+    'condition': 'checkout_fuchsia and host_os == "mac"',
+    'dep_type': 'cipd'
+  },
+  'crashpad/third_party/fuchsia/sdk/linux-amd64': {
+    'packages': [
+      {
+        'package': 'fuchsia/sdk/core/linux-amd64',
+        'version': 'latest'
+      },
+    ],
+    'condition': 'checkout_fuchsia and host_os == "linux"',
     'dep_type': 'cipd'
   },
   'crashpad/third_party/win/toolchain': {
diff --git a/third_party/crashpad/crashpad/compat/BUILD.gn b/third_party/crashpad/crashpad/compat/BUILD.gn
index 9f247a45..7a33d7ca 100644
--- a/third_party/crashpad/crashpad/compat/BUILD.gn
+++ b/third_party/crashpad/crashpad/compat/BUILD.gn
@@ -19,6 +19,8 @@
 
   if (crashpad_is_mac) {
     include_dirs += [ "mac" ]
+  } else {
+    include_dirs += [ "non_mac" ]
   }
 
   if (crashpad_is_linux || crashpad_is_android) {
@@ -34,6 +36,10 @@
   } else {
     include_dirs += [ "non_win" ]
   }
+
+  if (!crashpad_is_linux && !crashpad_is_android && !crashpad_is_fuchsia) {
+    include_dirs += [ "non_elf" ]
+  }
 }
 
 template("compat_target") {
@@ -62,7 +68,12 @@
       "mac/sys/resource.h",
     ]
   } else {
-    sources += [ "non_mac/mach/mach.h" ]
+    sources += [
+      "non_mac/mach-o/loader.h",
+      "non_mac/mach/mach.h",
+      "non_mac/mach/machine.h",
+      "non_mac/mach/vm_prot.h",
+    ]
   }
 
   if (crashpad_is_linux || crashpad_is_android) {
@@ -116,6 +127,10 @@
     ]
   }
 
+  if (!crashpad_is_linux && !crashpad_is_android && !crashpad_is_fuchsia) {
+    sources += [ "non_elf/elf.h" ]
+  }
+
   public_configs = [
     ":compat_config",
     "..:crashpad_config",
@@ -123,7 +138,15 @@
 
   deps = []
 
+  if (!crashpad_is_mac) {
+    deps += [ "../third_party/xnu" ]
+  }
+
   if (crashpad_is_win) {
     deps += [ "../third_party/getopt" ]
   }
+
+  if (!crashpad_is_linux && !crashpad_is_android && !crashpad_is_fuchsia) {
+    deps += [ "../third_party/glibc" ]
+  }
 }
diff --git a/third_party/crashpad/crashpad/compat/non_elf/elf.h b/third_party/crashpad/crashpad/compat/non_elf/elf.h
new file mode 100644
index 0000000..1245f16
--- /dev/null
+++ b/third_party/crashpad/crashpad/compat/non_elf/elf.h
@@ -0,0 +1,20 @@
+// Copyright 2019 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_COMPAT_NON_ELF_ELF_H_
+#define CRASHPAD_COMPAT_NON_ELF_ELF_H_
+
+#include "third_party/glibc/elf/elf.h"
+
+#endif  // CRASHPAD_COMPAT_NON_ELF_ELF_H_
diff --git a/third_party/crashpad/crashpad/compat/non_mac/mach-o/loader.h b/third_party/crashpad/crashpad/compat/non_mac/mach-o/loader.h
new file mode 100644
index 0000000..98a8b5f
--- /dev/null
+++ b/third_party/crashpad/crashpad/compat/non_mac/mach-o/loader.h
@@ -0,0 +1,20 @@
+// Copyright 2019 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_COMPAT_NON_MAC_MACH_O_LOADER_H_
+#define CRASHPAD_COMPAT_NON_MAC_MACH_O_LOADER_H_
+
+#include "third_party/xnu/EXTERNAL_HEADERS/mach-o/loader.h"
+
+#endif  // CRASHPAD_COMPAT_NON_MAC_MACH_O_LOADER_H_
diff --git a/third_party/crashpad/crashpad/compat/non_mac/mach/machine.h b/third_party/crashpad/crashpad/compat/non_mac/mach/machine.h
new file mode 100644
index 0000000..54d4742
--- /dev/null
+++ b/third_party/crashpad/crashpad/compat/non_mac/mach/machine.h
@@ -0,0 +1,21 @@
+// Copyright 2019 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_COMPAT_NON_MAC_MACH_MACHINE_H_
+#define CRASHPAD_COMPAT_NON_MAC_MACH_MACHINE_H_
+
+typedef int cpu_type_t;
+typedef int cpu_subtype_t;
+
+#endif  // CRASHPAD_COMPAT_NON_MAC_MACH_MACHINE_H_
diff --git a/third_party/crashpad/crashpad/compat/non_mac/mach/vm_prot.h b/third_party/crashpad/crashpad/compat/non_mac/mach/vm_prot.h
new file mode 100644
index 0000000..1200179
--- /dev/null
+++ b/third_party/crashpad/crashpad/compat/non_mac/mach/vm_prot.h
@@ -0,0 +1,20 @@
+// Copyright 2019 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_COMPAT_NON_MAC_MACH_VM_PROT_H_
+#define CRASHPAD_COMPAT_NON_MAC_MACH_VM_PROT_H_
+
+typedef int vm_prot_t;
+
+#endif  // CRASHPAD_COMPAT_NON_MAC_MACH_VM_PROT_H_
diff --git a/third_party/crashpad/crashpad/snapshot/minidump/thread_snapshot_minidump.cc b/third_party/crashpad/crashpad/snapshot/minidump/thread_snapshot_minidump.cc
index e77bab8..30b2d71 100644
--- a/third_party/crashpad/crashpad/snapshot/minidump/thread_snapshot_minidump.cc
+++ b/third_party/crashpad/crashpad/snapshot/minidump/thread_snapshot_minidump.cc
@@ -86,7 +86,6 @@
   }
 
   if (context_.architecture == CPUArchitecture::kCPUArchitectureX86) {
-    LOG(WARNING) << "Snapshot X86 context support has no unit tests.";
     context_memory_.resize(sizeof(CPUContextX86));
     context_.x86 = reinterpret_cast<CPUContextX86*>(context_memory_.data());
     const MinidumpContextX86* src =
@@ -180,7 +179,6 @@
     context_.x86_64->dr4 = src->dr6;
     context_.x86_64->dr5 = src->dr7;
   } else if (context_.architecture == CPUArchitecture::kCPUArchitectureARM) {
-    LOG(WARNING) << "Snapshot ARM32 context support has no unit tests.";
     context_memory_.resize(sizeof(CPUContextARM));
     context_.arm = reinterpret_cast<CPUContextARM*>(context_memory_.data());
     const MinidumpContextARM* src =
@@ -242,7 +240,6 @@
     context_.arm64->fpsr = src->fpsr;
     context_.arm64->spsr = src->cpsr;
   } else if (context_.architecture == CPUArchitecture::kCPUArchitectureMIPSEL) {
-    LOG(WARNING) << "Snapshot MIPS context support has no unit tests.";
     context_memory_.resize(sizeof(CPUContextMIPS));
     context_.mipsel = reinterpret_cast<CPUContextMIPS*>(context_memory_.data());
     const MinidumpContextMIPS* src =
@@ -278,7 +275,6 @@
     memcpy(&context_.mipsel->fpregs, &src->fpregs, sizeof(src->fpregs));
   } else if (context_.architecture ==
              CPUArchitecture::kCPUArchitectureMIPS64EL) {
-    LOG(WARNING) << "Snapshot MIPS64 context support has no unit tests.";
     context_memory_.resize(sizeof(CPUContextMIPS64));
     context_.mips64 =
       reinterpret_cast<CPUContextMIPS64*>(context_memory_.data());
diff --git a/third_party/crashpad/crashpad/test/fuchsia_crashpad_tests.cmx b/third_party/crashpad/crashpad/test/fuchsia_crashpad_tests.cmx
new file mode 100644
index 0000000..6b666379
--- /dev/null
+++ b/third_party/crashpad/crashpad/test/fuchsia_crashpad_tests.cmx
@@ -0,0 +1,21 @@
+{
+  "facets": {
+    "fuchsia.test": {
+      "system-services": [
+        "fuchsia.net.SocketProvider"
+      ]
+    }
+  },
+  "program": {
+    "binary": "test/crashpad_tests"
+  },
+  "sandbox": {
+    "features": [
+      "system-temp"
+    ],
+    "services": [
+      "fuchsia.net.SocketProvider",
+      "fuchsia.process.Launcher"
+    ]
+  }
+}
diff --git a/third_party/crashpad/crashpad/test/test_paths.cc b/third_party/crashpad/crashpad/test/test_paths.cc
index 3b611b1..10bae7a2 100644
--- a/third_party/crashpad/crashpad/test/test_paths.cc
+++ b/third_party/crashpad/crashpad/test/test_paths.cc
@@ -44,14 +44,7 @@
 
 base::FilePath TestDataRootInternal() {
 #if defined(OS_FUCHSIA)
-  base::FilePath asset_path("/pkg/assets");
-#if defined(CRASHPAD_IS_IN_FUCHSIA)
-  // Tests are not yet packaged when running in the Fuchsia tree, so assets do
-  // not appear as expected at /pkg/assets. Override the default so that tests
-  // can find their data for now.
-  // https://crashpad.chromium.org/bug/196.
-  asset_path = base::FilePath("/system/data/crashpad_tests");
-#endif
+  base::FilePath asset_path("/pkg/data");
   if (!IsTestDataRoot(asset_path)) {
     LOG(WARNING) << "Test data root seems invalid, continuing anyway";
   }
@@ -129,11 +122,7 @@
   base::FilePath executable_path;
   CHECK(Paths::Executable(&executable_path));
 #if defined(CRASHPAD_IS_IN_FUCHSIA)
-  // Tests are not yet packaged when running in the Fuchsia tree, so binaries do
-  // not appear as expected at /pkg/bin. Override the default of /pkg/bin/app
-  // so that tests can find the correct location for now.
-  // https://crashpad.chromium.org/bug/196.
-  executable_path = base::FilePath("/system/bin/crashpad_tests/app");
+  executable_path = base::FilePath("/pkg/bin/app");
 #endif
   return executable_path;
 }
@@ -202,16 +191,7 @@
 #if defined(OS_WIN)
       extension = FILE_PATH_LITERAL(".exe");
 #elif defined(OS_FUCHSIA)
-#if defined(CRASHPAD_IS_IN_FUCHSIA)
-      // Tests are not yet packaged when running in the Fuchsia tree, so
-      // binaries do not appear as expected at /pkg/bin. Override the default of
-      // /pkg/bin/app so that tests can find the correct location for now.
-      // https://crashpad.chromium.org/bug/196.
-      directory =
-          base::FilePath(FILE_PATH_LITERAL("/system/bin/crashpad_tests"));
-#else
       directory = base::FilePath(FILE_PATH_LITERAL("/pkg/bin"));
-#endif
 #endif  // OS_WIN
       break;
 
@@ -233,12 +213,7 @@
 
     case FileType::kCertificate:
 #if defined(CRASHPAD_IS_IN_FUCHSIA)
-      // When running in the Fuchsia tree, the .pem files are packaged as assets
-      // into the test data folder. This will need to be rationalized when
-      // things are actually run from a package.
-      // https://crashpad.chromium.org/bug/196.
-      directory =
-          base::FilePath(FILE_PATH_LITERAL("/system/data/crashpad_tests"));
+      directory = base::FilePath(FILE_PATH_LITERAL("/pkg/data"));
 #endif
       extension = FILE_PATH_LITERAL(".pem");
       break;
diff --git a/third_party/crashpad/crashpad/third_party/apple_cf/BUILD.gn b/third_party/crashpad/crashpad/third_party/apple_cf/BUILD.gn
new file mode 100644
index 0000000..43c62eb
--- /dev/null
+++ b/third_party/crashpad/crashpad/third_party/apple_cf/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2019 The Crashpad Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+source_set("apple_cf") {
+  sources = [
+    "CFStreamAbstract.h",
+  ]
+}
diff --git a/third_party/crashpad/crashpad/third_party/apple_cf/CFStreamAbstract.h b/third_party/crashpad/crashpad/third_party/apple_cf/CFStreamAbstract.h
index bf12c92..ac26664 100644
--- a/third_party/crashpad/crashpad/third_party/apple_cf/CFStreamAbstract.h
+++ b/third_party/crashpad/crashpad/third_party/apple_cf/CFStreamAbstract.h
@@ -1,15 +1,15 @@
 /*
- * Copyright (c) 2010 Apple Inc. All rights reserved.
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -17,12 +17,12 @@
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
 /*	CFStreamAbstract.h
-	Copyright (c) 2000-2009, Apple Inc. All rights reserved.
+	Copyright (c) 2000-2014, Apple Inc. All rights reserved.
 */
 
 #if !defined(__COREFOUNDATION_CFSTREAMABSTRACT__)
@@ -134,11 +134,18 @@
 void *_CFWriteStreamGetClient(CFWriteStreamRef writeStream);
 
 // Returns an array of the runloops and modes on which the stream is currently scheduled
+// Note that these are unretained mutable arrays - use the copy variant instead.
 CF_EXPORT
 CFArrayRef _CFReadStreamGetRunLoopsAndModes(CFReadStreamRef readStream);
 CF_EXPORT
 CFArrayRef _CFWriteStreamGetRunLoopsAndModes(CFWriteStreamRef writeStream);
 
+// Returns an array of the runloops and modes on which the stream is currently scheduled
+CF_EXPORT
+CFArrayRef _CFReadStreamCopyRunLoopsAndModes(CFReadStreamRef readStream);
+CF_EXPORT
+CFArrayRef _CFWriteStreamCopyRunLoopsAndModes(CFWriteStreamRef writeStream);
+
 /* Deprecated versions; here for backwards compatibility. */
 typedef struct {
     CFIndex version; /* == 1 */
diff --git a/third_party/crashpad/crashpad/third_party/apple_cf/README.crashpad b/third_party/crashpad/crashpad/third_party/apple_cf/README.crashpad
index b6c6cfa..20066484 100644
--- a/third_party/crashpad/crashpad/third_party/apple_cf/README.crashpad
+++ b/third_party/crashpad/crashpad/third_party/apple_cf/README.crashpad
@@ -2,7 +2,7 @@
 Short Name: CF
 URL: https://opensource.apple.com/source/CF/
 URL: https://opensource.apple.com/tarballs/CF/
-Version: 550.43 (from Mac OS X 10.6.8)
+Version: 1153.18 (from OS X 10.10.3)
 License: APSL 2.0
 License File: APPLE_LICENSE
 Security Critical: no
diff --git a/third_party/crashpad/crashpad/third_party/fuchsia/BUILD.gn b/third_party/crashpad/crashpad/third_party/fuchsia/BUILD.gn
index 1e6d94d..6965dfe 100644
--- a/third_party/crashpad/crashpad/third_party/fuchsia/BUILD.gn
+++ b/third_party/crashpad/crashpad/third_party/fuchsia/BUILD.gn
@@ -26,12 +26,12 @@
   group("zx") {
     public_deps = [
       "//third_party/fuchsia-sdk/sdk:fdio",
-      "//third_party/fuchsia-sdk/sdk:zx",
       "//third_party/fuchsia-sdk/sdk:sysinfo",
+      "//third_party/fuchsia-sdk/sdk:zx",
     ]
   }
 } else {
-  sdk_path = "sdk/linux-amd64"
+  sdk_path = "sdk/$host_os-amd64"
   sdk_pkg_path = "$sdk_path/pkg"
   sdk_fidl_path = "$sdk_path/fidl"
 
@@ -40,6 +40,7 @@
     include_dirs = [
       "$root_gen_dir/fidl/include",
       "$sdk_pkg_path/fidl/include",
+      "$sdk_pkg_path/fidl_base/include",
       "$sdk_pkg_path/zx/include",
     ]
   }
@@ -70,17 +71,20 @@
       script = "runner.py"
 
       args = [
-        rebase_path("$sdk_path/tools/fidlc", root_build_dir),
-        "--c-header",
-        rebase_path(c_header, root_build_dir),
-        "--c-client",
-        rebase_path(c_client, root_build_dir),
-        "--tables",
-        rebase_path(coding_tables, root_build_dir),
-        "--files",
-      ] + [ rebase_path(fidl_source.fidl, root_build_dir) ]
+               rebase_path("$sdk_path/tools/fidlc", root_build_dir),
+               "--c-header",
+               rebase_path(c_header, root_build_dir),
+               "--c-client",
+               rebase_path(c_client, root_build_dir),
+               "--tables",
+               rebase_path(coding_tables, root_build_dir),
+               "--files",
+             ] + [ rebase_path(fidl_source.fidl, root_build_dir) ]
 
-      inputs = [ fidl_source.fidl, "$sdk_path/tools/fidlc" ]
+      inputs = [
+        fidl_source.fidl,
+        "$sdk_path/tools/fidlc",
+      ]
 
       outputs = [
         c_client,
@@ -91,47 +95,76 @@
   }
 
   static_library("zx") {
-    sources = [
-      "$sdk_pkg_path/zx/channel.cpp",
-      "$sdk_pkg_path/zx/event.cpp",
-      "$sdk_pkg_path/zx/eventpair.cpp",
-      "$sdk_pkg_path/zx/fifo.cpp",
-      "$sdk_pkg_path/zx/guest.cpp",
-      "$sdk_pkg_path/zx/include/lib/zx/bti.h",
-      "$sdk_pkg_path/zx/include/lib/zx/channel.h",
-      "$sdk_pkg_path/zx/include/lib/zx/event.h",
-      "$sdk_pkg_path/zx/include/lib/zx/eventpair.h",
-      "$sdk_pkg_path/zx/include/lib/zx/fifo.h",
-      "$sdk_pkg_path/zx/include/lib/zx/guest.h",
-      "$sdk_pkg_path/zx/include/lib/zx/handle.h",
-      "$sdk_pkg_path/zx/include/lib/zx/interrupt.h",
-      "$sdk_pkg_path/zx/include/lib/zx/job.h",
-      "$sdk_pkg_path/zx/include/lib/zx/object.h",
-      "$sdk_pkg_path/zx/include/lib/zx/object_traits.h",
-      "$sdk_pkg_path/zx/include/lib/zx/pmt.h",
-      "$sdk_pkg_path/zx/include/lib/zx/port.h",
-      "$sdk_pkg_path/zx/include/lib/zx/process.h",
-      "$sdk_pkg_path/zx/include/lib/zx/resource.h",
-      "$sdk_pkg_path/zx/include/lib/zx/socket.h",
-      "$sdk_pkg_path/zx/include/lib/zx/task.h",
-      "$sdk_pkg_path/zx/include/lib/zx/thread.h",
-      "$sdk_pkg_path/zx/include/lib/zx/time.h",
-      "$sdk_pkg_path/zx/include/lib/zx/timer.h",
-      "$sdk_pkg_path/zx/include/lib/zx/vmar.h",
-      "$sdk_pkg_path/zx/include/lib/zx/vmo.h",
-      "$sdk_pkg_path/zx/interrupt.cpp",
-      "$sdk_pkg_path/zx/job.cpp",
-      "$sdk_pkg_path/zx/port.cpp",
-      "$sdk_pkg_path/zx/process.cpp",
-      "$sdk_pkg_path/zx/resource.cpp",
-      "$sdk_pkg_path/zx/socket.cpp",
-      "$sdk_pkg_path/zx/thread.cpp",
-      "$sdk_pkg_path/zx/timer.cpp",
-      "$sdk_pkg_path/zx/vmar.cpp",
-      "$sdk_pkg_path/zx/vmo.cpp",
-    ] + fidl_gen_sources
+    sources =
+        [
+          # This is the zx library.
+          "$sdk_pkg_path/zx/channel.cpp",
+          "$sdk_pkg_path/zx/event.cpp",
+          "$sdk_pkg_path/zx/eventpair.cpp",
+          "$sdk_pkg_path/zx/fifo.cpp",
+          "$sdk_pkg_path/zx/guest.cpp",
+          "$sdk_pkg_path/zx/include/lib/zx/bti.h",
+          "$sdk_pkg_path/zx/include/lib/zx/channel.h",
+          "$sdk_pkg_path/zx/include/lib/zx/event.h",
+          "$sdk_pkg_path/zx/include/lib/zx/eventpair.h",
+          "$sdk_pkg_path/zx/include/lib/zx/fifo.h",
+          "$sdk_pkg_path/zx/include/lib/zx/guest.h",
+          "$sdk_pkg_path/zx/include/lib/zx/handle.h",
+          "$sdk_pkg_path/zx/include/lib/zx/interrupt.h",
+          "$sdk_pkg_path/zx/include/lib/zx/job.h",
+          "$sdk_pkg_path/zx/include/lib/zx/object.h",
+          "$sdk_pkg_path/zx/include/lib/zx/object_traits.h",
+          "$sdk_pkg_path/zx/include/lib/zx/pmt.h",
+          "$sdk_pkg_path/zx/include/lib/zx/port.h",
+          "$sdk_pkg_path/zx/include/lib/zx/process.h",
+          "$sdk_pkg_path/zx/include/lib/zx/resource.h",
+          "$sdk_pkg_path/zx/include/lib/zx/socket.h",
+          "$sdk_pkg_path/zx/include/lib/zx/task.h",
+          "$sdk_pkg_path/zx/include/lib/zx/thread.h",
+          "$sdk_pkg_path/zx/include/lib/zx/time.h",
+          "$sdk_pkg_path/zx/include/lib/zx/timer.h",
+          "$sdk_pkg_path/zx/include/lib/zx/vmar.h",
+          "$sdk_pkg_path/zx/include/lib/zx/vmo.h",
+          "$sdk_pkg_path/zx/interrupt.cpp",
+          "$sdk_pkg_path/zx/job.cpp",
+          "$sdk_pkg_path/zx/port.cpp",
+          "$sdk_pkg_path/zx/process.cpp",
+          "$sdk_pkg_path/zx/resource.cpp",
+          "$sdk_pkg_path/zx/socket.cpp",
+          "$sdk_pkg_path/zx/thread.cpp",
+          "$sdk_pkg_path/zx/timer.cpp",
+          "$sdk_pkg_path/zx/vmar.cpp",
+          "$sdk_pkg_path/zx/vmo.cpp",
 
-    deps = [ ":fuchsia.sysinfo" ]
+          # This is the fidl_base library.
+          "$sdk_pkg_path/fidl_base/builder.cpp",
+          "$sdk_pkg_path/fidl_base/decoding.cpp",
+          "$sdk_pkg_path/fidl_base/encoding.cpp",
+          "$sdk_pkg_path/fidl_base/envelope_frames.h",
+          "$sdk_pkg_path/fidl_base/formatting.cpp",
+          "$sdk_pkg_path/fidl_base/include/lib/fidl/coding.h",
+          "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/builder.h",
+          "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message.h",
+          "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message_buffer.h",
+          "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message_builder.h",
+          "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/message_part.h",
+          "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/string_view.h",
+          "$sdk_pkg_path/fidl_base/include/lib/fidl/cpp/vector_view.h",
+          "$sdk_pkg_path/fidl_base/include/lib/fidl/internal.h",
+          "$sdk_pkg_path/fidl_base/include/lib/fidl/internal_callable_traits.h",
+          "$sdk_pkg_path/fidl_base/linearizing.cpp",
+          "$sdk_pkg_path/fidl_base/message.cpp",
+          "$sdk_pkg_path/fidl_base/message_buffer.cpp",
+          "$sdk_pkg_path/fidl_base/message_builder.cpp",
+          "$sdk_pkg_path/fidl_base/validating.cpp",
+          "$sdk_pkg_path/fidl_base/visitor.h",
+          "$sdk_pkg_path/fidl_base/walker.cpp",
+          "$sdk_pkg_path/fidl_base/walker.h",
+        ] + fidl_gen_sources
+
+    deps = [
+      ":fuchsia.sysinfo",
+    ]
 
     public_configs = [ ":zx_config" ]
   }
diff --git a/third_party/crashpad/crashpad/third_party/glibc/BUILD.gn b/third_party/crashpad/crashpad/third_party/glibc/BUILD.gn
new file mode 100644
index 0000000..e12febf
--- /dev/null
+++ b/third_party/crashpad/crashpad/third_party/glibc/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2019 The Crashpad Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+source_set("glibc") {
+  sources = [
+    "elf/elf.h",
+  ]
+}
diff --git a/third_party/crashpad/crashpad/third_party/glibc/COPYING.LIB b/third_party/crashpad/crashpad/third_party/glibc/COPYING.LIB
new file mode 100644
index 0000000..4362b49
--- /dev/null
+++ b/third_party/crashpad/crashpad/third_party/glibc/COPYING.LIB
@@ -0,0 +1,502 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/third_party/crashpad/crashpad/third_party/glibc/README.crashpad b/third_party/crashpad/crashpad/third_party/glibc/README.crashpad
new file mode 100644
index 0000000..b550ad9
--- /dev/null
+++ b/third_party/crashpad/crashpad/third_party/glibc/README.crashpad
@@ -0,0 +1,16 @@
+Name: GNU C Library
+Short Name: glibc
+URL: https://www.gnu.org/software/libc/
+URL: https://sourceware.org/git/?p=glibc.git
+Version: 2.29
+License: GNU LGPL 2.1
+License File: COPYING.LIB
+Security Critical: no
+
+Description:
+glibc is the GNU Project’s implementation of the C standard library.
+
+Local Modifications:
+ - Only elf/elf.h is included. Its #include of <features.h> has been removed,
+   and it uses of __BEGIN_DECLS and __END_DECLS have been replaced with inline
+   versions in the manner that misc/sys/cdefs.h defines those macros.
diff --git a/third_party/crashpad/crashpad/third_party/glibc/elf/elf.h b/third_party/crashpad/crashpad/third_party/glibc/elf/elf.h
new file mode 100644
index 0000000..331536b49
--- /dev/null
+++ b/third_party/crashpad/crashpad/third_party/glibc/elf/elf.h
@@ -0,0 +1,4003 @@
+/* This file defines standard ELF types, structures, and macros.
+   Copyright (C) 1995-2019 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _ELF_H
+#define	_ELF_H 1
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Standard ELF types.  */
+
+#include <stdint.h>
+
+/* Type for a 16-bit quantity.  */
+typedef uint16_t Elf32_Half;
+typedef uint16_t Elf64_Half;
+
+/* Types for signed and unsigned 32-bit quantities.  */
+typedef uint32_t Elf32_Word;
+typedef	int32_t  Elf32_Sword;
+typedef uint32_t Elf64_Word;
+typedef	int32_t  Elf64_Sword;
+
+/* Types for signed and unsigned 64-bit quantities.  */
+typedef uint64_t Elf32_Xword;
+typedef	int64_t  Elf32_Sxword;
+typedef uint64_t Elf64_Xword;
+typedef	int64_t  Elf64_Sxword;
+
+/* Type of addresses.  */
+typedef uint32_t Elf32_Addr;
+typedef uint64_t Elf64_Addr;
+
+/* Type of file offsets.  */
+typedef uint32_t Elf32_Off;
+typedef uint64_t Elf64_Off;
+
+/* Type for section indices, which are 16-bit quantities.  */
+typedef uint16_t Elf32_Section;
+typedef uint16_t Elf64_Section;
+
+/* Type for version symbol information.  */
+typedef Elf32_Half Elf32_Versym;
+typedef Elf64_Half Elf64_Versym;
+
+
+/* The ELF file header.  This appears at the start of every ELF file.  */
+
+#define EI_NIDENT (16)
+
+typedef struct
+{
+  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
+  Elf32_Half	e_type;			/* Object file type */
+  Elf32_Half	e_machine;		/* Architecture */
+  Elf32_Word	e_version;		/* Object file version */
+  Elf32_Addr	e_entry;		/* Entry point virtual address */
+  Elf32_Off	e_phoff;		/* Program header table file offset */
+  Elf32_Off	e_shoff;		/* Section header table file offset */
+  Elf32_Word	e_flags;		/* Processor-specific flags */
+  Elf32_Half	e_ehsize;		/* ELF header size in bytes */
+  Elf32_Half	e_phentsize;		/* Program header table entry size */
+  Elf32_Half	e_phnum;		/* Program header table entry count */
+  Elf32_Half	e_shentsize;		/* Section header table entry size */
+  Elf32_Half	e_shnum;		/* Section header table entry count */
+  Elf32_Half	e_shstrndx;		/* Section header string table index */
+} Elf32_Ehdr;
+
+typedef struct
+{
+  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
+  Elf64_Half	e_type;			/* Object file type */
+  Elf64_Half	e_machine;		/* Architecture */
+  Elf64_Word	e_version;		/* Object file version */
+  Elf64_Addr	e_entry;		/* Entry point virtual address */
+  Elf64_Off	e_phoff;		/* Program header table file offset */
+  Elf64_Off	e_shoff;		/* Section header table file offset */
+  Elf64_Word	e_flags;		/* Processor-specific flags */
+  Elf64_Half	e_ehsize;		/* ELF header size in bytes */
+  Elf64_Half	e_phentsize;		/* Program header table entry size */
+  Elf64_Half	e_phnum;		/* Program header table entry count */
+  Elf64_Half	e_shentsize;		/* Section header table entry size */
+  Elf64_Half	e_shnum;		/* Section header table entry count */
+  Elf64_Half	e_shstrndx;		/* Section header string table index */
+} Elf64_Ehdr;
+
+/* Fields in the e_ident array.  The EI_* macros are indices into the
+   array.  The macros under each EI_* macro are the values the byte
+   may have.  */
+
+#define EI_MAG0		0		/* File identification byte 0 index */
+#define ELFMAG0		0x7f		/* Magic number byte 0 */
+
+#define EI_MAG1		1		/* File identification byte 1 index */
+#define ELFMAG1		'E'		/* Magic number byte 1 */
+
+#define EI_MAG2		2		/* File identification byte 2 index */
+#define ELFMAG2		'L'		/* Magic number byte 2 */
+
+#define EI_MAG3		3		/* File identification byte 3 index */
+#define ELFMAG3		'F'		/* Magic number byte 3 */
+
+/* Conglomeration of the identification bytes, for easy testing as a word.  */
+#define	ELFMAG		"\177ELF"
+#define	SELFMAG		4
+
+#define EI_CLASS	4		/* File class byte index */
+#define ELFCLASSNONE	0		/* Invalid class */
+#define ELFCLASS32	1		/* 32-bit objects */
+#define ELFCLASS64	2		/* 64-bit objects */
+#define ELFCLASSNUM	3
+
+#define EI_DATA		5		/* Data encoding byte index */
+#define ELFDATANONE	0		/* Invalid data encoding */
+#define ELFDATA2LSB	1		/* 2's complement, little endian */
+#define ELFDATA2MSB	2		/* 2's complement, big endian */
+#define ELFDATANUM	3
+
+#define EI_VERSION	6		/* File version byte index */
+					/* Value must be EV_CURRENT */
+
+#define EI_OSABI	7		/* OS ABI identification */
+#define ELFOSABI_NONE		0	/* UNIX System V ABI */
+#define ELFOSABI_SYSV		0	/* Alias.  */
+#define ELFOSABI_HPUX		1	/* HP-UX */
+#define ELFOSABI_NETBSD		2	/* NetBSD.  */
+#define ELFOSABI_GNU		3	/* Object uses GNU ELF extensions.  */
+#define ELFOSABI_LINUX		ELFOSABI_GNU /* Compatibility alias.  */
+#define ELFOSABI_SOLARIS	6	/* Sun Solaris.  */
+#define ELFOSABI_AIX		7	/* IBM AIX.  */
+#define ELFOSABI_IRIX		8	/* SGI Irix.  */
+#define ELFOSABI_FREEBSD	9	/* FreeBSD.  */
+#define ELFOSABI_TRU64		10	/* Compaq TRU64 UNIX.  */
+#define ELFOSABI_MODESTO	11	/* Novell Modesto.  */
+#define ELFOSABI_OPENBSD	12	/* OpenBSD.  */
+#define ELFOSABI_ARM_AEABI	64	/* ARM EABI */
+#define ELFOSABI_ARM		97	/* ARM */
+#define ELFOSABI_STANDALONE	255	/* Standalone (embedded) application */
+
+#define EI_ABIVERSION	8		/* ABI version */
+
+#define EI_PAD		9		/* Byte index of padding bytes */
+
+/* Legal values for e_type (object file type).  */
+
+#define ET_NONE		0		/* No file type */
+#define ET_REL		1		/* Relocatable file */
+#define ET_EXEC		2		/* Executable file */
+#define ET_DYN		3		/* Shared object file */
+#define ET_CORE		4		/* Core file */
+#define	ET_NUM		5		/* Number of defined types */
+#define ET_LOOS		0xfe00		/* OS-specific range start */
+#define ET_HIOS		0xfeff		/* OS-specific range end */
+#define ET_LOPROC	0xff00		/* Processor-specific range start */
+#define ET_HIPROC	0xffff		/* Processor-specific range end */
+
+/* Legal values for e_machine (architecture).  */
+
+#define EM_NONE		 0	/* No machine */
+#define EM_M32		 1	/* AT&T WE 32100 */
+#define EM_SPARC	 2	/* SUN SPARC */
+#define EM_386		 3	/* Intel 80386 */
+#define EM_68K		 4	/* Motorola m68k family */
+#define EM_88K		 5	/* Motorola m88k family */
+#define EM_IAMCU	 6	/* Intel MCU */
+#define EM_860		 7	/* Intel 80860 */
+#define EM_MIPS		 8	/* MIPS R3000 big-endian */
+#define EM_S370		 9	/* IBM System/370 */
+#define EM_MIPS_RS3_LE	10	/* MIPS R3000 little-endian */
+				/* reserved 11-14 */
+#define EM_PARISC	15	/* HPPA */
+				/* reserved 16 */
+#define EM_VPP500	17	/* Fujitsu VPP500 */
+#define EM_SPARC32PLUS	18	/* Sun's "v8plus" */
+#define EM_960		19	/* Intel 80960 */
+#define EM_PPC		20	/* PowerPC */
+#define EM_PPC64	21	/* PowerPC 64-bit */
+#define EM_S390		22	/* IBM S390 */
+#define EM_SPU		23	/* IBM SPU/SPC */
+				/* reserved 24-35 */
+#define EM_V800		36	/* NEC V800 series */
+#define EM_FR20		37	/* Fujitsu FR20 */
+#define EM_RH32		38	/* TRW RH-32 */
+#define EM_RCE		39	/* Motorola RCE */
+#define EM_ARM		40	/* ARM */
+#define EM_FAKE_ALPHA	41	/* Digital Alpha */
+#define EM_SH		42	/* Hitachi SH */
+#define EM_SPARCV9	43	/* SPARC v9 64-bit */
+#define EM_TRICORE	44	/* Siemens Tricore */
+#define EM_ARC		45	/* Argonaut RISC Core */
+#define EM_H8_300	46	/* Hitachi H8/300 */
+#define EM_H8_300H	47	/* Hitachi H8/300H */
+#define EM_H8S		48	/* Hitachi H8S */
+#define EM_H8_500	49	/* Hitachi H8/500 */
+#define EM_IA_64	50	/* Intel Merced */
+#define EM_MIPS_X	51	/* Stanford MIPS-X */
+#define EM_COLDFIRE	52	/* Motorola Coldfire */
+#define EM_68HC12	53	/* Motorola M68HC12 */
+#define EM_MMA		54	/* Fujitsu MMA Multimedia Accelerator */
+#define EM_PCP		55	/* Siemens PCP */
+#define EM_NCPU		56	/* Sony nCPU embeeded RISC */
+#define EM_NDR1		57	/* Denso NDR1 microprocessor */
+#define EM_STARCORE	58	/* Motorola Start*Core processor */
+#define EM_ME16		59	/* Toyota ME16 processor */
+#define EM_ST100	60	/* STMicroelectronic ST100 processor */
+#define EM_TINYJ	61	/* Advanced Logic Corp. Tinyj emb.fam */
+#define EM_X86_64	62	/* AMD x86-64 architecture */
+#define EM_PDSP		63	/* Sony DSP Processor */
+#define EM_PDP10	64	/* Digital PDP-10 */
+#define EM_PDP11	65	/* Digital PDP-11 */
+#define EM_FX66		66	/* Siemens FX66 microcontroller */
+#define EM_ST9PLUS	67	/* STMicroelectronics ST9+ 8/16 mc */
+#define EM_ST7		68	/* STmicroelectronics ST7 8 bit mc */
+#define EM_68HC16	69	/* Motorola MC68HC16 microcontroller */
+#define EM_68HC11	70	/* Motorola MC68HC11 microcontroller */
+#define EM_68HC08	71	/* Motorola MC68HC08 microcontroller */
+#define EM_68HC05	72	/* Motorola MC68HC05 microcontroller */
+#define EM_SVX		73	/* Silicon Graphics SVx */
+#define EM_ST19		74	/* STMicroelectronics ST19 8 bit mc */
+#define EM_VAX		75	/* Digital VAX */
+#define EM_CRIS		76	/* Axis Communications 32-bit emb.proc */
+#define EM_JAVELIN	77	/* Infineon Technologies 32-bit emb.proc */
+#define EM_FIREPATH	78	/* Element 14 64-bit DSP Processor */
+#define EM_ZSP		79	/* LSI Logic 16-bit DSP Processor */
+#define EM_MMIX		80	/* Donald Knuth's educational 64-bit proc */
+#define EM_HUANY	81	/* Harvard University machine-independent object files */
+#define EM_PRISM	82	/* SiTera Prism */
+#define EM_AVR		83	/* Atmel AVR 8-bit microcontroller */
+#define EM_FR30		84	/* Fujitsu FR30 */
+#define EM_D10V		85	/* Mitsubishi D10V */
+#define EM_D30V		86	/* Mitsubishi D30V */
+#define EM_V850		87	/* NEC v850 */
+#define EM_M32R		88	/* Mitsubishi M32R */
+#define EM_MN10300	89	/* Matsushita MN10300 */
+#define EM_MN10200	90	/* Matsushita MN10200 */
+#define EM_PJ		91	/* picoJava */
+#define EM_OPENRISC	92	/* OpenRISC 32-bit embedded processor */
+#define EM_ARC_COMPACT	93	/* ARC International ARCompact */
+#define EM_XTENSA	94	/* Tensilica Xtensa Architecture */
+#define EM_VIDEOCORE	95	/* Alphamosaic VideoCore */
+#define EM_TMM_GPP	96	/* Thompson Multimedia General Purpose Proc */
+#define EM_NS32K	97	/* National Semi. 32000 */
+#define EM_TPC		98	/* Tenor Network TPC */
+#define EM_SNP1K	99	/* Trebia SNP 1000 */
+#define EM_ST200	100	/* STMicroelectronics ST200 */
+#define EM_IP2K		101	/* Ubicom IP2xxx */
+#define EM_MAX		102	/* MAX processor */
+#define EM_CR		103	/* National Semi. CompactRISC */
+#define EM_F2MC16	104	/* Fujitsu F2MC16 */
+#define EM_MSP430	105	/* Texas Instruments msp430 */
+#define EM_BLACKFIN	106	/* Analog Devices Blackfin DSP */
+#define EM_SE_C33	107	/* Seiko Epson S1C33 family */
+#define EM_SEP		108	/* Sharp embedded microprocessor */
+#define EM_ARCA		109	/* Arca RISC */
+#define EM_UNICORE	110	/* PKU-Unity & MPRC Peking Uni. mc series */
+#define EM_EXCESS	111	/* eXcess configurable cpu */
+#define EM_DXP		112	/* Icera Semi. Deep Execution Processor */
+#define EM_ALTERA_NIOS2 113	/* Altera Nios II */
+#define EM_CRX		114	/* National Semi. CompactRISC CRX */
+#define EM_XGATE	115	/* Motorola XGATE */
+#define EM_C166		116	/* Infineon C16x/XC16x */
+#define EM_M16C		117	/* Renesas M16C */
+#define EM_DSPIC30F	118	/* Microchip Technology dsPIC30F */
+#define EM_CE		119	/* Freescale Communication Engine RISC */
+#define EM_M32C		120	/* Renesas M32C */
+				/* reserved 121-130 */
+#define EM_TSK3000	131	/* Altium TSK3000 */
+#define EM_RS08		132	/* Freescale RS08 */
+#define EM_SHARC	133	/* Analog Devices SHARC family */
+#define EM_ECOG2	134	/* Cyan Technology eCOG2 */
+#define EM_SCORE7	135	/* Sunplus S+core7 RISC */
+#define EM_DSP24	136	/* New Japan Radio (NJR) 24-bit DSP */
+#define EM_VIDEOCORE3	137	/* Broadcom VideoCore III */
+#define EM_LATTICEMICO32 138	/* RISC for Lattice FPGA */
+#define EM_SE_C17	139	/* Seiko Epson C17 */
+#define EM_TI_C6000	140	/* Texas Instruments TMS320C6000 DSP */
+#define EM_TI_C2000	141	/* Texas Instruments TMS320C2000 DSP */
+#define EM_TI_C5500	142	/* Texas Instruments TMS320C55x DSP */
+#define EM_TI_ARP32	143	/* Texas Instruments App. Specific RISC */
+#define EM_TI_PRU	144	/* Texas Instruments Prog. Realtime Unit */
+				/* reserved 145-159 */
+#define EM_MMDSP_PLUS	160	/* STMicroelectronics 64bit VLIW DSP */
+#define EM_CYPRESS_M8C	161	/* Cypress M8C */
+#define EM_R32C		162	/* Renesas R32C */
+#define EM_TRIMEDIA	163	/* NXP Semi. TriMedia */
+#define EM_QDSP6	164	/* QUALCOMM DSP6 */
+#define EM_8051		165	/* Intel 8051 and variants */
+#define EM_STXP7X	166	/* STMicroelectronics STxP7x */
+#define EM_NDS32	167	/* Andes Tech. compact code emb. RISC */
+#define EM_ECOG1X	168	/* Cyan Technology eCOG1X */
+#define EM_MAXQ30	169	/* Dallas Semi. MAXQ30 mc */
+#define EM_XIMO16	170	/* New Japan Radio (NJR) 16-bit DSP */
+#define EM_MANIK	171	/* M2000 Reconfigurable RISC */
+#define EM_CRAYNV2	172	/* Cray NV2 vector architecture */
+#define EM_RX		173	/* Renesas RX */
+#define EM_METAG	174	/* Imagination Tech. META */
+#define EM_MCST_ELBRUS	175	/* MCST Elbrus */
+#define EM_ECOG16	176	/* Cyan Technology eCOG16 */
+#define EM_CR16		177	/* National Semi. CompactRISC CR16 */
+#define EM_ETPU		178	/* Freescale Extended Time Processing Unit */
+#define EM_SLE9X	179	/* Infineon Tech. SLE9X */
+#define EM_L10M		180	/* Intel L10M */
+#define EM_K10M		181	/* Intel K10M */
+				/* reserved 182 */
+#define EM_AARCH64	183	/* ARM AARCH64 */
+				/* reserved 184 */
+#define EM_AVR32	185	/* Amtel 32-bit microprocessor */
+#define EM_STM8		186	/* STMicroelectronics STM8 */
+#define EM_TILE64	187	/* Tileta TILE64 */
+#define EM_TILEPRO	188	/* Tilera TILEPro */
+#define EM_MICROBLAZE	189	/* Xilinx MicroBlaze */
+#define EM_CUDA		190	/* NVIDIA CUDA */
+#define EM_TILEGX	191	/* Tilera TILE-Gx */
+#define EM_CLOUDSHIELD	192	/* CloudShield */
+#define EM_COREA_1ST	193	/* KIPO-KAIST Core-A 1st gen. */
+#define EM_COREA_2ND	194	/* KIPO-KAIST Core-A 2nd gen. */
+#define EM_ARC_COMPACT2	195	/* Synopsys ARCompact V2 */
+#define EM_OPEN8	196	/* Open8 RISC */
+#define EM_RL78		197	/* Renesas RL78 */
+#define EM_VIDEOCORE5	198	/* Broadcom VideoCore V */
+#define EM_78KOR	199	/* Renesas 78KOR */
+#define EM_56800EX	200	/* Freescale 56800EX DSC */
+#define EM_BA1		201	/* Beyond BA1 */
+#define EM_BA2		202	/* Beyond BA2 */
+#define EM_XCORE	203	/* XMOS xCORE */
+#define EM_MCHP_PIC	204	/* Microchip 8-bit PIC(r) */
+				/* reserved 205-209 */
+#define EM_KM32		210	/* KM211 KM32 */
+#define EM_KMX32	211	/* KM211 KMX32 */
+#define EM_EMX16	212	/* KM211 KMX16 */
+#define EM_EMX8		213	/* KM211 KMX8 */
+#define EM_KVARC	214	/* KM211 KVARC */
+#define EM_CDP		215	/* Paneve CDP */
+#define EM_COGE		216	/* Cognitive Smart Memory Processor */
+#define EM_COOL		217	/* Bluechip CoolEngine */
+#define EM_NORC		218	/* Nanoradio Optimized RISC */
+#define EM_CSR_KALIMBA	219	/* CSR Kalimba */
+#define EM_Z80		220	/* Zilog Z80 */
+#define EM_VISIUM	221	/* Controls and Data Services VISIUMcore */
+#define EM_FT32		222	/* FTDI Chip FT32 */
+#define EM_MOXIE	223	/* Moxie processor */
+#define EM_AMDGPU	224	/* AMD GPU */
+				/* reserved 225-242 */
+#define EM_RISCV	243	/* RISC-V */
+
+#define EM_BPF		247	/* Linux BPF -- in-kernel virtual machine */
+#define EM_CSKY		252     /* C_SKY */
+
+#define EM_NUM		253
+
+/* Old spellings/synonyms.  */
+
+#define EM_ARC_A5	EM_ARC_COMPACT
+
+/* If it is necessary to assign new unofficial EM_* values, please
+   pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
+   chances of collision with official or non-GNU unofficial values.  */
+
+#define EM_ALPHA	0x9026
+
+/* Legal values for e_version (version).  */
+
+#define EV_NONE		0		/* Invalid ELF version */
+#define EV_CURRENT	1		/* Current version */
+#define EV_NUM		2
+
+/* Section header.  */
+
+typedef struct
+{
+  Elf32_Word	sh_name;		/* Section name (string tbl index) */
+  Elf32_Word	sh_type;		/* Section type */
+  Elf32_Word	sh_flags;		/* Section flags */
+  Elf32_Addr	sh_addr;		/* Section virtual addr at execution */
+  Elf32_Off	sh_offset;		/* Section file offset */
+  Elf32_Word	sh_size;		/* Section size in bytes */
+  Elf32_Word	sh_link;		/* Link to another section */
+  Elf32_Word	sh_info;		/* Additional section information */
+  Elf32_Word	sh_addralign;		/* Section alignment */
+  Elf32_Word	sh_entsize;		/* Entry size if section holds table */
+} Elf32_Shdr;
+
+typedef struct
+{
+  Elf64_Word	sh_name;		/* Section name (string tbl index) */
+  Elf64_Word	sh_type;		/* Section type */
+  Elf64_Xword	sh_flags;		/* Section flags */
+  Elf64_Addr	sh_addr;		/* Section virtual addr at execution */
+  Elf64_Off	sh_offset;		/* Section file offset */
+  Elf64_Xword	sh_size;		/* Section size in bytes */
+  Elf64_Word	sh_link;		/* Link to another section */
+  Elf64_Word	sh_info;		/* Additional section information */
+  Elf64_Xword	sh_addralign;		/* Section alignment */
+  Elf64_Xword	sh_entsize;		/* Entry size if section holds table */
+} Elf64_Shdr;
+
+/* Special section indices.  */
+
+#define SHN_UNDEF	0		/* Undefined section */
+#define SHN_LORESERVE	0xff00		/* Start of reserved indices */
+#define SHN_LOPROC	0xff00		/* Start of processor-specific */
+#define SHN_BEFORE	0xff00		/* Order section before all others
+					   (Solaris).  */
+#define SHN_AFTER	0xff01		/* Order section after all others
+					   (Solaris).  */
+#define SHN_HIPROC	0xff1f		/* End of processor-specific */
+#define SHN_LOOS	0xff20		/* Start of OS-specific */
+#define SHN_HIOS	0xff3f		/* End of OS-specific */
+#define SHN_ABS		0xfff1		/* Associated symbol is absolute */
+#define SHN_COMMON	0xfff2		/* Associated symbol is common */
+#define SHN_XINDEX	0xffff		/* Index is in extra table.  */
+#define SHN_HIRESERVE	0xffff		/* End of reserved indices */
+
+/* Legal values for sh_type (section type).  */
+
+#define SHT_NULL	  0		/* Section header table entry unused */
+#define SHT_PROGBITS	  1		/* Program data */
+#define SHT_SYMTAB	  2		/* Symbol table */
+#define SHT_STRTAB	  3		/* String table */
+#define SHT_RELA	  4		/* Relocation entries with addends */
+#define SHT_HASH	  5		/* Symbol hash table */
+#define SHT_DYNAMIC	  6		/* Dynamic linking information */
+#define SHT_NOTE	  7		/* Notes */
+#define SHT_NOBITS	  8		/* Program space with no data (bss) */
+#define SHT_REL		  9		/* Relocation entries, no addends */
+#define SHT_SHLIB	  10		/* Reserved */
+#define SHT_DYNSYM	  11		/* Dynamic linker symbol table */
+#define SHT_INIT_ARRAY	  14		/* Array of constructors */
+#define SHT_FINI_ARRAY	  15		/* Array of destructors */
+#define SHT_PREINIT_ARRAY 16		/* Array of pre-constructors */
+#define SHT_GROUP	  17		/* Section group */
+#define SHT_SYMTAB_SHNDX  18		/* Extended section indeces */
+#define	SHT_NUM		  19		/* Number of defined types.  */
+#define SHT_LOOS	  0x60000000	/* Start OS-specific.  */
+#define SHT_GNU_ATTRIBUTES 0x6ffffff5	/* Object attributes.  */
+#define SHT_GNU_HASH	  0x6ffffff6	/* GNU-style hash table.  */
+#define SHT_GNU_LIBLIST	  0x6ffffff7	/* Prelink library list */
+#define SHT_CHECKSUM	  0x6ffffff8	/* Checksum for DSO content.  */
+#define SHT_LOSUNW	  0x6ffffffa	/* Sun-specific low bound.  */
+#define SHT_SUNW_move	  0x6ffffffa
+#define SHT_SUNW_COMDAT   0x6ffffffb
+#define SHT_SUNW_syminfo  0x6ffffffc
+#define SHT_GNU_verdef	  0x6ffffffd	/* Version definition section.  */
+#define SHT_GNU_verneed	  0x6ffffffe	/* Version needs section.  */
+#define SHT_GNU_versym	  0x6fffffff	/* Version symbol table.  */
+#define SHT_HISUNW	  0x6fffffff	/* Sun-specific high bound.  */
+#define SHT_HIOS	  0x6fffffff	/* End OS-specific type */
+#define SHT_LOPROC	  0x70000000	/* Start of processor-specific */
+#define SHT_HIPROC	  0x7fffffff	/* End of processor-specific */
+#define SHT_LOUSER	  0x80000000	/* Start of application-specific */
+#define SHT_HIUSER	  0x8fffffff	/* End of application-specific */
+
+/* Legal values for sh_flags (section flags).  */
+
+#define SHF_WRITE	     (1 << 0)	/* Writable */
+#define SHF_ALLOC	     (1 << 1)	/* Occupies memory during execution */
+#define SHF_EXECINSTR	     (1 << 2)	/* Executable */
+#define SHF_MERGE	     (1 << 4)	/* Might be merged */
+#define SHF_STRINGS	     (1 << 5)	/* Contains nul-terminated strings */
+#define SHF_INFO_LINK	     (1 << 6)	/* `sh_info' contains SHT index */
+#define SHF_LINK_ORDER	     (1 << 7)	/* Preserve order after combining */
+#define SHF_OS_NONCONFORMING (1 << 8)	/* Non-standard OS specific handling
+					   required */
+#define SHF_GROUP	     (1 << 9)	/* Section is member of a group.  */
+#define SHF_TLS		     (1 << 10)	/* Section hold thread-local data.  */
+#define SHF_COMPRESSED	     (1 << 11)	/* Section with compressed data. */
+#define SHF_MASKOS	     0x0ff00000	/* OS-specific.  */
+#define SHF_MASKPROC	     0xf0000000	/* Processor-specific */
+#define SHF_ORDERED	     (1 << 30)	/* Special ordering requirement
+					   (Solaris).  */
+#define SHF_EXCLUDE	     (1U << 31)	/* Section is excluded unless
+					   referenced or allocated (Solaris).*/
+
+/* Section compression header.  Used when SHF_COMPRESSED is set.  */
+
+typedef struct
+{
+  Elf32_Word	ch_type;	/* Compression format.  */
+  Elf32_Word	ch_size;	/* Uncompressed data size.  */
+  Elf32_Word	ch_addralign;	/* Uncompressed data alignment.  */
+} Elf32_Chdr;
+
+typedef struct
+{
+  Elf64_Word	ch_type;	/* Compression format.  */
+  Elf64_Word	ch_reserved;
+  Elf64_Xword	ch_size;	/* Uncompressed data size.  */
+  Elf64_Xword	ch_addralign;	/* Uncompressed data alignment.  */
+} Elf64_Chdr;
+
+/* Legal values for ch_type (compression algorithm).  */
+#define ELFCOMPRESS_ZLIB	1	   /* ZLIB/DEFLATE algorithm.  */
+#define ELFCOMPRESS_LOOS	0x60000000 /* Start of OS-specific.  */
+#define ELFCOMPRESS_HIOS	0x6fffffff /* End of OS-specific.  */
+#define ELFCOMPRESS_LOPROC	0x70000000 /* Start of processor-specific.  */
+#define ELFCOMPRESS_HIPROC	0x7fffffff /* End of processor-specific.  */
+
+/* Section group handling.  */
+#define GRP_COMDAT	0x1		/* Mark group as COMDAT.  */
+
+/* Symbol table entry.  */
+
+typedef struct
+{
+  Elf32_Word	st_name;		/* Symbol name (string tbl index) */
+  Elf32_Addr	st_value;		/* Symbol value */
+  Elf32_Word	st_size;		/* Symbol size */
+  unsigned char	st_info;		/* Symbol type and binding */
+  unsigned char	st_other;		/* Symbol visibility */
+  Elf32_Section	st_shndx;		/* Section index */
+} Elf32_Sym;
+
+typedef struct
+{
+  Elf64_Word	st_name;		/* Symbol name (string tbl index) */
+  unsigned char	st_info;		/* Symbol type and binding */
+  unsigned char st_other;		/* Symbol visibility */
+  Elf64_Section	st_shndx;		/* Section index */
+  Elf64_Addr	st_value;		/* Symbol value */
+  Elf64_Xword	st_size;		/* Symbol size */
+} Elf64_Sym;
+
+/* The syminfo section if available contains additional information about
+   every dynamic symbol.  */
+
+typedef struct
+{
+  Elf32_Half si_boundto;		/* Direct bindings, symbol bound to */
+  Elf32_Half si_flags;			/* Per symbol flags */
+} Elf32_Syminfo;
+
+typedef struct
+{
+  Elf64_Half si_boundto;		/* Direct bindings, symbol bound to */
+  Elf64_Half si_flags;			/* Per symbol flags */
+} Elf64_Syminfo;
+
+/* Possible values for si_boundto.  */
+#define SYMINFO_BT_SELF		0xffff	/* Symbol bound to self */
+#define SYMINFO_BT_PARENT	0xfffe	/* Symbol bound to parent */
+#define SYMINFO_BT_LOWRESERVE	0xff00	/* Beginning of reserved entries */
+
+/* Possible bitmasks for si_flags.  */
+#define SYMINFO_FLG_DIRECT	0x0001	/* Direct bound symbol */
+#define SYMINFO_FLG_PASSTHRU	0x0002	/* Pass-thru symbol for translator */
+#define SYMINFO_FLG_COPY	0x0004	/* Symbol is a copy-reloc */
+#define SYMINFO_FLG_LAZYLOAD	0x0008	/* Symbol bound to object to be lazy
+					   loaded */
+/* Syminfo version values.  */
+#define SYMINFO_NONE		0
+#define SYMINFO_CURRENT		1
+#define SYMINFO_NUM		2
+
+
+/* How to extract and insert information held in the st_info field.  */
+
+#define ELF32_ST_BIND(val)		(((unsigned char) (val)) >> 4)
+#define ELF32_ST_TYPE(val)		((val) & 0xf)
+#define ELF32_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
+
+/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field.  */
+#define ELF64_ST_BIND(val)		ELF32_ST_BIND (val)
+#define ELF64_ST_TYPE(val)		ELF32_ST_TYPE (val)
+#define ELF64_ST_INFO(bind, type)	ELF32_ST_INFO ((bind), (type))
+
+/* Legal values for ST_BIND subfield of st_info (symbol binding).  */
+
+#define STB_LOCAL	0		/* Local symbol */
+#define STB_GLOBAL	1		/* Global symbol */
+#define STB_WEAK	2		/* Weak symbol */
+#define	STB_NUM		3		/* Number of defined types.  */
+#define STB_LOOS	10		/* Start of OS-specific */
+#define STB_GNU_UNIQUE	10		/* Unique symbol.  */
+#define STB_HIOS	12		/* End of OS-specific */
+#define STB_LOPROC	13		/* Start of processor-specific */
+#define STB_HIPROC	15		/* End of processor-specific */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_NOTYPE	0		/* Symbol type is unspecified */
+#define STT_OBJECT	1		/* Symbol is a data object */
+#define STT_FUNC	2		/* Symbol is a code object */
+#define STT_SECTION	3		/* Symbol associated with a section */
+#define STT_FILE	4		/* Symbol's name is file name */
+#define STT_COMMON	5		/* Symbol is a common data object */
+#define STT_TLS		6		/* Symbol is thread-local data object*/
+#define	STT_NUM		7		/* Number of defined types.  */
+#define STT_LOOS	10		/* Start of OS-specific */
+#define STT_GNU_IFUNC	10		/* Symbol is indirect code object */
+#define STT_HIOS	12		/* End of OS-specific */
+#define STT_LOPROC	13		/* Start of processor-specific */
+#define STT_HIPROC	15		/* End of processor-specific */
+
+
+/* Symbol table indices are found in the hash buckets and chain table
+   of a symbol hash table section.  This special index value indicates
+   the end of a chain, meaning no further symbols are found in that bucket.  */
+
+#define STN_UNDEF	0		/* End of a chain.  */
+
+
+/* How to extract and insert information held in the st_other field.  */
+
+#define ELF32_ST_VISIBILITY(o)	((o) & 0x03)
+
+/* For ELF64 the definitions are the same.  */
+#define ELF64_ST_VISIBILITY(o)	ELF32_ST_VISIBILITY (o)
+
+/* Symbol visibility specification encoded in the st_other field.  */
+#define STV_DEFAULT	0		/* Default symbol visibility rules */
+#define STV_INTERNAL	1		/* Processor specific hidden class */
+#define STV_HIDDEN	2		/* Sym unavailable in other modules */
+#define STV_PROTECTED	3		/* Not preemptible, not exported */
+
+
+/* Relocation table entry without addend (in section of type SHT_REL).  */
+
+typedef struct
+{
+  Elf32_Addr	r_offset;		/* Address */
+  Elf32_Word	r_info;			/* Relocation type and symbol index */
+} Elf32_Rel;
+
+/* I have seen two different definitions of the Elf64_Rel and
+   Elf64_Rela structures, so we'll leave them out until Novell (or
+   whoever) gets their act together.  */
+/* The following, at least, is used on Sparc v9, MIPS, and Alpha.  */
+
+typedef struct
+{
+  Elf64_Addr	r_offset;		/* Address */
+  Elf64_Xword	r_info;			/* Relocation type and symbol index */
+} Elf64_Rel;
+
+/* Relocation table entry with addend (in section of type SHT_RELA).  */
+
+typedef struct
+{
+  Elf32_Addr	r_offset;		/* Address */
+  Elf32_Word	r_info;			/* Relocation type and symbol index */
+  Elf32_Sword	r_addend;		/* Addend */
+} Elf32_Rela;
+
+typedef struct
+{
+  Elf64_Addr	r_offset;		/* Address */
+  Elf64_Xword	r_info;			/* Relocation type and symbol index */
+  Elf64_Sxword	r_addend;		/* Addend */
+} Elf64_Rela;
+
+/* How to extract and insert information held in the r_info field.  */
+
+#define ELF32_R_SYM(val)		((val) >> 8)
+#define ELF32_R_TYPE(val)		((val) & 0xff)
+#define ELF32_R_INFO(sym, type)		(((sym) << 8) + ((type) & 0xff))
+
+#define ELF64_R_SYM(i)			((i) >> 32)
+#define ELF64_R_TYPE(i)			((i) & 0xffffffff)
+#define ELF64_R_INFO(sym,type)		((((Elf64_Xword) (sym)) << 32) + (type))
+
+/* Program segment header.  */
+
+typedef struct
+{
+  Elf32_Word	p_type;			/* Segment type */
+  Elf32_Off	p_offset;		/* Segment file offset */
+  Elf32_Addr	p_vaddr;		/* Segment virtual address */
+  Elf32_Addr	p_paddr;		/* Segment physical address */
+  Elf32_Word	p_filesz;		/* Segment size in file */
+  Elf32_Word	p_memsz;		/* Segment size in memory */
+  Elf32_Word	p_flags;		/* Segment flags */
+  Elf32_Word	p_align;		/* Segment alignment */
+} Elf32_Phdr;
+
+typedef struct
+{
+  Elf64_Word	p_type;			/* Segment type */
+  Elf64_Word	p_flags;		/* Segment flags */
+  Elf64_Off	p_offset;		/* Segment file offset */
+  Elf64_Addr	p_vaddr;		/* Segment virtual address */
+  Elf64_Addr	p_paddr;		/* Segment physical address */
+  Elf64_Xword	p_filesz;		/* Segment size in file */
+  Elf64_Xword	p_memsz;		/* Segment size in memory */
+  Elf64_Xword	p_align;		/* Segment alignment */
+} Elf64_Phdr;
+
+/* Special value for e_phnum.  This indicates that the real number of
+   program headers is too large to fit into e_phnum.  Instead the real
+   value is in the field sh_info of section 0.  */
+
+#define PN_XNUM		0xffff
+
+/* Legal values for p_type (segment type).  */
+
+#define	PT_NULL		0		/* Program header table entry unused */
+#define PT_LOAD		1		/* Loadable program segment */
+#define PT_DYNAMIC	2		/* Dynamic linking information */
+#define PT_INTERP	3		/* Program interpreter */
+#define PT_NOTE		4		/* Auxiliary information */
+#define PT_SHLIB	5		/* Reserved */
+#define PT_PHDR		6		/* Entry for header table itself */
+#define PT_TLS		7		/* Thread-local storage segment */
+#define	PT_NUM		8		/* Number of defined types */
+#define PT_LOOS		0x60000000	/* Start of OS-specific */
+#define PT_GNU_EH_FRAME	0x6474e550	/* GCC .eh_frame_hdr segment */
+#define PT_GNU_STACK	0x6474e551	/* Indicates stack executability */
+#define PT_GNU_RELRO	0x6474e552	/* Read-only after relocation */
+#define PT_LOSUNW	0x6ffffffa
+#define PT_SUNWBSS	0x6ffffffa	/* Sun Specific segment */
+#define PT_SUNWSTACK	0x6ffffffb	/* Stack segment */
+#define PT_HISUNW	0x6fffffff
+#define PT_HIOS		0x6fffffff	/* End of OS-specific */
+#define PT_LOPROC	0x70000000	/* Start of processor-specific */
+#define PT_HIPROC	0x7fffffff	/* End of processor-specific */
+
+/* Legal values for p_flags (segment flags).  */
+
+#define PF_X		(1 << 0)	/* Segment is executable */
+#define PF_W		(1 << 1)	/* Segment is writable */
+#define PF_R		(1 << 2)	/* Segment is readable */
+#define PF_MASKOS	0x0ff00000	/* OS-specific */
+#define PF_MASKPROC	0xf0000000	/* Processor-specific */
+
+/* Legal values for note segment descriptor types for core files. */
+
+#define NT_PRSTATUS	1		/* Contains copy of prstatus struct */
+#define NT_PRFPREG	2		/* Contains copy of fpregset
+					   struct.  */
+#define NT_FPREGSET	2		/* Contains copy of fpregset struct */
+#define NT_PRPSINFO	3		/* Contains copy of prpsinfo struct */
+#define NT_PRXREG	4		/* Contains copy of prxregset struct */
+#define NT_TASKSTRUCT	4		/* Contains copy of task structure */
+#define NT_PLATFORM	5		/* String from sysinfo(SI_PLATFORM) */
+#define NT_AUXV		6		/* Contains copy of auxv array */
+#define NT_GWINDOWS	7		/* Contains copy of gwindows struct */
+#define NT_ASRS		8		/* Contains copy of asrset struct */
+#define NT_PSTATUS	10		/* Contains copy of pstatus struct */
+#define NT_PSINFO	13		/* Contains copy of psinfo struct */
+#define NT_PRCRED	14		/* Contains copy of prcred struct */
+#define NT_UTSNAME	15		/* Contains copy of utsname struct */
+#define NT_LWPSTATUS	16		/* Contains copy of lwpstatus struct */
+#define NT_LWPSINFO	17		/* Contains copy of lwpinfo struct */
+#define NT_PRFPXREG	20		/* Contains copy of fprxregset struct */
+#define NT_SIGINFO	0x53494749	/* Contains copy of siginfo_t,
+					   size might increase */
+#define NT_FILE		0x46494c45	/* Contains information about mapped
+					   files */
+#define NT_PRXFPREG	0x46e62b7f	/* Contains copy of user_fxsr_struct */
+#define NT_PPC_VMX	0x100		/* PowerPC Altivec/VMX registers */
+#define NT_PPC_SPE	0x101		/* PowerPC SPE/EVR registers */
+#define NT_PPC_VSX	0x102		/* PowerPC VSX registers */
+#define NT_PPC_TAR	0x103		/* Target Address Register */
+#define NT_PPC_PPR	0x104		/* Program Priority Register */
+#define NT_PPC_DSCR	0x105		/* Data Stream Control Register */
+#define NT_PPC_EBB	0x106		/* Event Based Branch Registers */
+#define NT_PPC_PMU	0x107		/* Performance Monitor Registers */
+#define NT_PPC_TM_CGPR	0x108		/* TM checkpointed GPR Registers */
+#define NT_PPC_TM_CFPR	0x109		/* TM checkpointed FPR Registers */
+#define NT_PPC_TM_CVMX	0x10a		/* TM checkpointed VMX Registers */
+#define NT_PPC_TM_CVSX	0x10b		/* TM checkpointed VSX Registers */
+#define NT_PPC_TM_SPR	0x10c		/* TM Special Purpose Registers */
+#define NT_PPC_TM_CTAR	0x10d		/* TM checkpointed Target Address
+					   Register */
+#define NT_PPC_TM_CPPR	0x10e		/* TM checkpointed Program Priority
+					   Register */
+#define NT_PPC_TM_CDSCR	0x10f		/* TM checkpointed Data Stream Control
+					   Register */
+#define NT_PPC_PKEY	0x110		/* Memory Protection Keys
+					   registers.  */
+#define NT_386_TLS	0x200		/* i386 TLS slots (struct user_desc) */
+#define NT_386_IOPERM	0x201		/* x86 io permission bitmap (1=deny) */
+#define NT_X86_XSTATE	0x202		/* x86 extended state using xsave */
+#define NT_S390_HIGH_GPRS	0x300	/* s390 upper register halves */
+#define NT_S390_TIMER	0x301		/* s390 timer register */
+#define NT_S390_TODCMP	0x302		/* s390 TOD clock comparator register */
+#define NT_S390_TODPREG	0x303		/* s390 TOD programmable register */
+#define NT_S390_CTRS	0x304		/* s390 control registers */
+#define NT_S390_PREFIX	0x305		/* s390 prefix register */
+#define NT_S390_LAST_BREAK	0x306	/* s390 breaking event address */
+#define NT_S390_SYSTEM_CALL	0x307	/* s390 system call restart data */
+#define NT_S390_TDB	0x308		/* s390 transaction diagnostic block */
+#define NT_S390_VXRS_LOW	0x309	/* s390 vector registers 0-15
+					   upper half.  */
+#define NT_S390_VXRS_HIGH	0x30a	/* s390 vector registers 16-31.  */
+#define NT_S390_GS_CB	0x30b		/* s390 guarded storage registers.  */
+#define NT_S390_GS_BC	0x30c		/* s390 guarded storage
+					   broadcast control block.  */
+#define NT_S390_RI_CB	0x30d		/* s390 runtime instrumentation.  */
+#define NT_ARM_VFP	0x400		/* ARM VFP/NEON registers */
+#define NT_ARM_TLS	0x401		/* ARM TLS register */
+#define NT_ARM_HW_BREAK	0x402		/* ARM hardware breakpoint registers */
+#define NT_ARM_HW_WATCH	0x403		/* ARM hardware watchpoint registers */
+#define NT_ARM_SYSTEM_CALL	0x404	/* ARM system call number */
+#define NT_ARM_SVE	0x405		/* ARM Scalable Vector Extension
+					   registers */
+#define NT_VMCOREDD	0x700		/* Vmcore Device Dump Note.  */
+#define NT_MIPS_DSP	0x800		/* MIPS DSP ASE registers.  */
+#define NT_MIPS_FP_MODE	0x801		/* MIPS floating-point mode.  */
+
+/* Legal values for the note segment descriptor types for object files.  */
+
+#define NT_VERSION	1		/* Contains a version string.  */
+
+
+/* Dynamic section entry.  */
+
+typedef struct
+{
+  Elf32_Sword	d_tag;			/* Dynamic entry type */
+  union
+    {
+      Elf32_Word d_val;			/* Integer value */
+      Elf32_Addr d_ptr;			/* Address value */
+    } d_un;
+} Elf32_Dyn;
+
+typedef struct
+{
+  Elf64_Sxword	d_tag;			/* Dynamic entry type */
+  union
+    {
+      Elf64_Xword d_val;		/* Integer value */
+      Elf64_Addr d_ptr;			/* Address value */
+    } d_un;
+} Elf64_Dyn;
+
+/* Legal values for d_tag (dynamic entry type).  */
+
+#define DT_NULL		0		/* Marks end of dynamic section */
+#define DT_NEEDED	1		/* Name of needed library */
+#define DT_PLTRELSZ	2		/* Size in bytes of PLT relocs */
+#define DT_PLTGOT	3		/* Processor defined value */
+#define DT_HASH		4		/* Address of symbol hash table */
+#define DT_STRTAB	5		/* Address of string table */
+#define DT_SYMTAB	6		/* Address of symbol table */
+#define DT_RELA		7		/* Address of Rela relocs */
+#define DT_RELASZ	8		/* Total size of Rela relocs */
+#define DT_RELAENT	9		/* Size of one Rela reloc */
+#define DT_STRSZ	10		/* Size of string table */
+#define DT_SYMENT	11		/* Size of one symbol table entry */
+#define DT_INIT		12		/* Address of init function */
+#define DT_FINI		13		/* Address of termination function */
+#define DT_SONAME	14		/* Name of shared object */
+#define DT_RPATH	15		/* Library search path (deprecated) */
+#define DT_SYMBOLIC	16		/* Start symbol search here */
+#define DT_REL		17		/* Address of Rel relocs */
+#define DT_RELSZ	18		/* Total size of Rel relocs */
+#define DT_RELENT	19		/* Size of one Rel reloc */
+#define DT_PLTREL	20		/* Type of reloc in PLT */
+#define DT_DEBUG	21		/* For debugging; unspecified */
+#define DT_TEXTREL	22		/* Reloc might modify .text */
+#define DT_JMPREL	23		/* Address of PLT relocs */
+#define	DT_BIND_NOW	24		/* Process relocations of object */
+#define	DT_INIT_ARRAY	25		/* Array with addresses of init fct */
+#define	DT_FINI_ARRAY	26		/* Array with addresses of fini fct */
+#define	DT_INIT_ARRAYSZ	27		/* Size in bytes of DT_INIT_ARRAY */
+#define	DT_FINI_ARRAYSZ	28		/* Size in bytes of DT_FINI_ARRAY */
+#define DT_RUNPATH	29		/* Library search path */
+#define DT_FLAGS	30		/* Flags for the object being loaded */
+#define DT_ENCODING	32		/* Start of encoded range */
+#define DT_PREINIT_ARRAY 32		/* Array with addresses of preinit fct*/
+#define DT_PREINIT_ARRAYSZ 33		/* size in bytes of DT_PREINIT_ARRAY */
+#define DT_SYMTAB_SHNDX	34		/* Address of SYMTAB_SHNDX section */
+#define	DT_NUM		35		/* Number used */
+#define DT_LOOS		0x6000000d	/* Start of OS-specific */
+#define DT_HIOS		0x6ffff000	/* End of OS-specific */
+#define DT_LOPROC	0x70000000	/* Start of processor-specific */
+#define DT_HIPROC	0x7fffffff	/* End of processor-specific */
+#define	DT_PROCNUM	DT_MIPS_NUM	/* Most used by any processor */
+
+/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
+   Dyn.d_un.d_val field of the Elf*_Dyn structure.  This follows Sun's
+   approach.  */
+#define DT_VALRNGLO	0x6ffffd00
+#define DT_GNU_PRELINKED 0x6ffffdf5	/* Prelinking timestamp */
+#define DT_GNU_CONFLICTSZ 0x6ffffdf6	/* Size of conflict section */
+#define DT_GNU_LIBLISTSZ 0x6ffffdf7	/* Size of library list */
+#define DT_CHECKSUM	0x6ffffdf8
+#define DT_PLTPADSZ	0x6ffffdf9
+#define DT_MOVEENT	0x6ffffdfa
+#define DT_MOVESZ	0x6ffffdfb
+#define DT_FEATURE_1	0x6ffffdfc	/* Feature selection (DTF_*).  */
+#define DT_POSFLAG_1	0x6ffffdfd	/* Flags for DT_* entries, effecting
+					   the following DT_* entry.  */
+#define DT_SYMINSZ	0x6ffffdfe	/* Size of syminfo table (in bytes) */
+#define DT_SYMINENT	0x6ffffdff	/* Entry size of syminfo */
+#define DT_VALRNGHI	0x6ffffdff
+#define DT_VALTAGIDX(tag)	(DT_VALRNGHI - (tag))	/* Reverse order! */
+#define DT_VALNUM 12
+
+/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
+   Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
+
+   If any adjustment is made to the ELF object after it has been
+   built these entries will need to be adjusted.  */
+#define DT_ADDRRNGLO	0x6ffffe00
+#define DT_GNU_HASH	0x6ffffef5	/* GNU-style hash table.  */
+#define DT_TLSDESC_PLT	0x6ffffef6
+#define DT_TLSDESC_GOT	0x6ffffef7
+#define DT_GNU_CONFLICT	0x6ffffef8	/* Start of conflict section */
+#define DT_GNU_LIBLIST	0x6ffffef9	/* Library list */
+#define DT_CONFIG	0x6ffffefa	/* Configuration information.  */
+#define DT_DEPAUDIT	0x6ffffefb	/* Dependency auditing.  */
+#define DT_AUDIT	0x6ffffefc	/* Object auditing.  */
+#define	DT_PLTPAD	0x6ffffefd	/* PLT padding.  */
+#define	DT_MOVETAB	0x6ffffefe	/* Move table.  */
+#define DT_SYMINFO	0x6ffffeff	/* Syminfo table.  */
+#define DT_ADDRRNGHI	0x6ffffeff
+#define DT_ADDRTAGIDX(tag)	(DT_ADDRRNGHI - (tag))	/* Reverse order! */
+#define DT_ADDRNUM 11
+
+/* The versioning entry types.  The next are defined as part of the
+   GNU extension.  */
+#define DT_VERSYM	0x6ffffff0
+
+#define DT_RELACOUNT	0x6ffffff9
+#define DT_RELCOUNT	0x6ffffffa
+
+/* These were chosen by Sun.  */
+#define DT_FLAGS_1	0x6ffffffb	/* State flags, see DF_1_* below.  */
+#define	DT_VERDEF	0x6ffffffc	/* Address of version definition
+					   table */
+#define	DT_VERDEFNUM	0x6ffffffd	/* Number of version definitions */
+#define	DT_VERNEED	0x6ffffffe	/* Address of table with needed
+					   versions */
+#define	DT_VERNEEDNUM	0x6fffffff	/* Number of needed versions */
+#define DT_VERSIONTAGIDX(tag)	(DT_VERNEEDNUM - (tag))	/* Reverse order! */
+#define DT_VERSIONTAGNUM 16
+
+/* Sun added these machine-independent extensions in the "processor-specific"
+   range.  Be compatible.  */
+#define DT_AUXILIARY    0x7ffffffd      /* Shared object to load before self */
+#define DT_FILTER       0x7fffffff      /* Shared object to get values from */
+#define DT_EXTRATAGIDX(tag)	((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
+#define DT_EXTRANUM	3
+
+/* Values of `d_un.d_val' in the DT_FLAGS entry.  */
+#define DF_ORIGIN	0x00000001	/* Object may use DF_ORIGIN */
+#define DF_SYMBOLIC	0x00000002	/* Symbol resolutions starts here */
+#define DF_TEXTREL	0x00000004	/* Object contains text relocations */
+#define DF_BIND_NOW	0x00000008	/* No lazy binding for this object */
+#define DF_STATIC_TLS	0x00000010	/* Module uses the static TLS model */
+
+/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
+   entry in the dynamic section.  */
+#define DF_1_NOW	0x00000001	/* Set RTLD_NOW for this object.  */
+#define DF_1_GLOBAL	0x00000002	/* Set RTLD_GLOBAL for this object.  */
+#define DF_1_GROUP	0x00000004	/* Set RTLD_GROUP for this object.  */
+#define DF_1_NODELETE	0x00000008	/* Set RTLD_NODELETE for this object.*/
+#define DF_1_LOADFLTR	0x00000010	/* Trigger filtee loading at runtime.*/
+#define DF_1_INITFIRST	0x00000020	/* Set RTLD_INITFIRST for this object*/
+#define DF_1_NOOPEN	0x00000040	/* Set RTLD_NOOPEN for this object.  */
+#define DF_1_ORIGIN	0x00000080	/* $ORIGIN must be handled.  */
+#define DF_1_DIRECT	0x00000100	/* Direct binding enabled.  */
+#define DF_1_TRANS	0x00000200
+#define DF_1_INTERPOSE	0x00000400	/* Object is used to interpose.  */
+#define DF_1_NODEFLIB	0x00000800	/* Ignore default lib search path.  */
+#define DF_1_NODUMP	0x00001000	/* Object can't be dldump'ed.  */
+#define DF_1_CONFALT	0x00002000	/* Configuration alternative created.*/
+#define DF_1_ENDFILTEE	0x00004000	/* Filtee terminates filters search. */
+#define	DF_1_DISPRELDNE	0x00008000	/* Disp reloc applied at build time. */
+#define	DF_1_DISPRELPND	0x00010000	/* Disp reloc applied at run-time.  */
+#define	DF_1_NODIRECT	0x00020000	/* Object has no-direct binding. */
+#define	DF_1_IGNMULDEF	0x00040000
+#define	DF_1_NOKSYMS	0x00080000
+#define	DF_1_NOHDR	0x00100000
+#define	DF_1_EDITED	0x00200000	/* Object is modified after built.  */
+#define	DF_1_NORELOC	0x00400000
+#define	DF_1_SYMINTPOSE	0x00800000	/* Object has individual interposers.  */
+#define	DF_1_GLOBAUDIT	0x01000000	/* Global auditing required.  */
+#define	DF_1_SINGLETON	0x02000000	/* Singleton symbols are used.  */
+#define	DF_1_STUB	0x04000000
+#define	DF_1_PIE	0x08000000
+
+/* Flags for the feature selection in DT_FEATURE_1.  */
+#define DTF_1_PARINIT	0x00000001
+#define DTF_1_CONFEXP	0x00000002
+
+/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry.  */
+#define DF_P1_LAZYLOAD	0x00000001	/* Lazyload following object.  */
+#define DF_P1_GROUPPERM	0x00000002	/* Symbols from next object are not
+					   generally available.  */
+
+/* Version definition sections.  */
+
+typedef struct
+{
+  Elf32_Half	vd_version;		/* Version revision */
+  Elf32_Half	vd_flags;		/* Version information */
+  Elf32_Half	vd_ndx;			/* Version Index */
+  Elf32_Half	vd_cnt;			/* Number of associated aux entries */
+  Elf32_Word	vd_hash;		/* Version name hash value */
+  Elf32_Word	vd_aux;			/* Offset in bytes to verdaux array */
+  Elf32_Word	vd_next;		/* Offset in bytes to next verdef
+					   entry */
+} Elf32_Verdef;
+
+typedef struct
+{
+  Elf64_Half	vd_version;		/* Version revision */
+  Elf64_Half	vd_flags;		/* Version information */
+  Elf64_Half	vd_ndx;			/* Version Index */
+  Elf64_Half	vd_cnt;			/* Number of associated aux entries */
+  Elf64_Word	vd_hash;		/* Version name hash value */
+  Elf64_Word	vd_aux;			/* Offset in bytes to verdaux array */
+  Elf64_Word	vd_next;		/* Offset in bytes to next verdef
+					   entry */
+} Elf64_Verdef;
+
+
+/* Legal values for vd_version (version revision).  */
+#define VER_DEF_NONE	0		/* No version */
+#define VER_DEF_CURRENT	1		/* Current version */
+#define VER_DEF_NUM	2		/* Given version number */
+
+/* Legal values for vd_flags (version information flags).  */
+#define VER_FLG_BASE	0x1		/* Version definition of file itself */
+#define VER_FLG_WEAK	0x2		/* Weak version identifier */
+
+/* Versym symbol index values.  */
+#define	VER_NDX_LOCAL		0	/* Symbol is local.  */
+#define	VER_NDX_GLOBAL		1	/* Symbol is global.  */
+#define	VER_NDX_LORESERVE	0xff00	/* Beginning of reserved entries.  */
+#define	VER_NDX_ELIMINATE	0xff01	/* Symbol is to be eliminated.  */
+
+/* Auxialiary version information.  */
+
+typedef struct
+{
+  Elf32_Word	vda_name;		/* Version or dependency names */
+  Elf32_Word	vda_next;		/* Offset in bytes to next verdaux
+					   entry */
+} Elf32_Verdaux;
+
+typedef struct
+{
+  Elf64_Word	vda_name;		/* Version or dependency names */
+  Elf64_Word	vda_next;		/* Offset in bytes to next verdaux
+					   entry */
+} Elf64_Verdaux;
+
+
+/* Version dependency section.  */
+
+typedef struct
+{
+  Elf32_Half	vn_version;		/* Version of structure */
+  Elf32_Half	vn_cnt;			/* Number of associated aux entries */
+  Elf32_Word	vn_file;		/* Offset of filename for this
+					   dependency */
+  Elf32_Word	vn_aux;			/* Offset in bytes to vernaux array */
+  Elf32_Word	vn_next;		/* Offset in bytes to next verneed
+					   entry */
+} Elf32_Verneed;
+
+typedef struct
+{
+  Elf64_Half	vn_version;		/* Version of structure */
+  Elf64_Half	vn_cnt;			/* Number of associated aux entries */
+  Elf64_Word	vn_file;		/* Offset of filename for this
+					   dependency */
+  Elf64_Word	vn_aux;			/* Offset in bytes to vernaux array */
+  Elf64_Word	vn_next;		/* Offset in bytes to next verneed
+					   entry */
+} Elf64_Verneed;
+
+
+/* Legal values for vn_version (version revision).  */
+#define VER_NEED_NONE	 0		/* No version */
+#define VER_NEED_CURRENT 1		/* Current version */
+#define VER_NEED_NUM	 2		/* Given version number */
+
+/* Auxiliary needed version information.  */
+
+typedef struct
+{
+  Elf32_Word	vna_hash;		/* Hash value of dependency name */
+  Elf32_Half	vna_flags;		/* Dependency specific information */
+  Elf32_Half	vna_other;		/* Unused */
+  Elf32_Word	vna_name;		/* Dependency name string offset */
+  Elf32_Word	vna_next;		/* Offset in bytes to next vernaux
+					   entry */
+} Elf32_Vernaux;
+
+typedef struct
+{
+  Elf64_Word	vna_hash;		/* Hash value of dependency name */
+  Elf64_Half	vna_flags;		/* Dependency specific information */
+  Elf64_Half	vna_other;		/* Unused */
+  Elf64_Word	vna_name;		/* Dependency name string offset */
+  Elf64_Word	vna_next;		/* Offset in bytes to next vernaux
+					   entry */
+} Elf64_Vernaux;
+
+
+/* Legal values for vna_flags.  */
+#define VER_FLG_WEAK	0x2		/* Weak version identifier */
+
+
+/* Auxiliary vector.  */
+
+/* This vector is normally only used by the program interpreter.  The
+   usual definition in an ABI supplement uses the name auxv_t.  The
+   vector is not usually defined in a standard <elf.h> file, but it
+   can't hurt.  We rename it to avoid conflicts.  The sizes of these
+   types are an arrangement between the exec server and the program
+   interpreter, so we don't fully specify them here.  */
+
+typedef struct
+{
+  uint32_t a_type;		/* Entry type */
+  union
+    {
+      uint32_t a_val;		/* Integer value */
+      /* We use to have pointer elements added here.  We cannot do that,
+	 though, since it does not work when using 32-bit definitions
+	 on 64-bit platforms and vice versa.  */
+    } a_un;
+} Elf32_auxv_t;
+
+typedef struct
+{
+  uint64_t a_type;		/* Entry type */
+  union
+    {
+      uint64_t a_val;		/* Integer value */
+      /* We use to have pointer elements added here.  We cannot do that,
+	 though, since it does not work when using 32-bit definitions
+	 on 64-bit platforms and vice versa.  */
+    } a_un;
+} Elf64_auxv_t;
+
+/* Legal values for a_type (entry type).  */
+
+#define AT_NULL		0		/* End of vector */
+#define AT_IGNORE	1		/* Entry should be ignored */
+#define AT_EXECFD	2		/* File descriptor of program */
+#define AT_PHDR		3		/* Program headers for program */
+#define AT_PHENT	4		/* Size of program header entry */
+#define AT_PHNUM	5		/* Number of program headers */
+#define AT_PAGESZ	6		/* System page size */
+#define AT_BASE		7		/* Base address of interpreter */
+#define AT_FLAGS	8		/* Flags */
+#define AT_ENTRY	9		/* Entry point of program */
+#define AT_NOTELF	10		/* Program is not ELF */
+#define AT_UID		11		/* Real uid */
+#define AT_EUID		12		/* Effective uid */
+#define AT_GID		13		/* Real gid */
+#define AT_EGID		14		/* Effective gid */
+#define AT_CLKTCK	17		/* Frequency of times() */
+
+/* Some more special a_type values describing the hardware.  */
+#define AT_PLATFORM	15		/* String identifying platform.  */
+#define AT_HWCAP	16		/* Machine-dependent hints about
+					   processor capabilities.  */
+
+/* This entry gives some information about the FPU initialization
+   performed by the kernel.  */
+#define AT_FPUCW	18		/* Used FPU control word.  */
+
+/* Cache block sizes.  */
+#define AT_DCACHEBSIZE	19		/* Data cache block size.  */
+#define AT_ICACHEBSIZE	20		/* Instruction cache block size.  */
+#define AT_UCACHEBSIZE	21		/* Unified cache block size.  */
+
+/* A special ignored value for PPC, used by the kernel to control the
+   interpretation of the AUXV. Must be > 16.  */
+#define AT_IGNOREPPC	22		/* Entry should be ignored.  */
+
+#define	AT_SECURE	23		/* Boolean, was exec setuid-like?  */
+
+#define AT_BASE_PLATFORM 24		/* String identifying real platforms.*/
+
+#define AT_RANDOM	25		/* Address of 16 random bytes.  */
+
+#define AT_HWCAP2	26		/* More machine-dependent hints about
+					   processor capabilities.  */
+
+#define AT_EXECFN	31		/* Filename of executable.  */
+
+/* Pointer to the global system page used for system calls and other
+   nice things.  */
+#define AT_SYSINFO	32
+#define AT_SYSINFO_EHDR	33
+
+/* Shapes of the caches.  Bits 0-3 contains associativity; bits 4-7 contains
+   log2 of line size; mask those to get cache size.  */
+#define AT_L1I_CACHESHAPE	34
+#define AT_L1D_CACHESHAPE	35
+#define AT_L2_CACHESHAPE	36
+#define AT_L3_CACHESHAPE	37
+
+/* Shapes of the caches, with more room to describe them.
+   *GEOMETRY are comprised of cache line size in bytes in the bottom 16 bits
+   and the cache associativity in the next 16 bits.  */
+#define AT_L1I_CACHESIZE	40
+#define AT_L1I_CACHEGEOMETRY	41
+#define AT_L1D_CACHESIZE	42
+#define AT_L1D_CACHEGEOMETRY	43
+#define AT_L2_CACHESIZE		44
+#define AT_L2_CACHEGEOMETRY	45
+#define AT_L3_CACHESIZE		46
+#define AT_L3_CACHEGEOMETRY	47
+
+#define AT_MINSIGSTKSZ		51 /* Stack needed for signal delivery
+				      (AArch64).  */
+
+/* Note section contents.  Each entry in the note section begins with
+   a header of a fixed form.  */
+
+typedef struct
+{
+  Elf32_Word n_namesz;			/* Length of the note's name.  */
+  Elf32_Word n_descsz;			/* Length of the note's descriptor.  */
+  Elf32_Word n_type;			/* Type of the note.  */
+} Elf32_Nhdr;
+
+typedef struct
+{
+  Elf64_Word n_namesz;			/* Length of the note's name.  */
+  Elf64_Word n_descsz;			/* Length of the note's descriptor.  */
+  Elf64_Word n_type;			/* Type of the note.  */
+} Elf64_Nhdr;
+
+/* Known names of notes.  */
+
+/* Solaris entries in the note section have this name.  */
+#define ELF_NOTE_SOLARIS	"SUNW Solaris"
+
+/* Note entries for GNU systems have this name.  */
+#define ELF_NOTE_GNU		"GNU"
+
+
+/* Defined types of notes for Solaris.  */
+
+/* Value of descriptor (one word) is desired pagesize for the binary.  */
+#define ELF_NOTE_PAGESIZE_HINT	1
+
+
+/* Defined note types for GNU systems.  */
+
+/* ABI information.  The descriptor consists of words:
+   word 0: OS descriptor
+   word 1: major version of the ABI
+   word 2: minor version of the ABI
+   word 3: subminor version of the ABI
+*/
+#define NT_GNU_ABI_TAG	1
+#define ELF_NOTE_ABI	NT_GNU_ABI_TAG /* Old name.  */
+
+/* Known OSes.  These values can appear in word 0 of an
+   NT_GNU_ABI_TAG note section entry.  */
+#define ELF_NOTE_OS_LINUX	0
+#define ELF_NOTE_OS_GNU		1
+#define ELF_NOTE_OS_SOLARIS2	2
+#define ELF_NOTE_OS_FREEBSD	3
+
+/* Synthetic hwcap information.  The descriptor begins with two words:
+   word 0: number of entries
+   word 1: bitmask of enabled entries
+   Then follow variable-length entries, one byte followed by a
+   '\0'-terminated hwcap name string.  The byte gives the bit
+   number to test if enabled, (1U << bit) & bitmask.  */
+#define NT_GNU_HWCAP	2
+
+/* Build ID bits as generated by ld --build-id.
+   The descriptor consists of any nonzero number of bytes.  */
+#define NT_GNU_BUILD_ID	3
+
+/* Version note generated by GNU gold containing a version string.  */
+#define NT_GNU_GOLD_VERSION	4
+
+/* Program property.  */
+#define NT_GNU_PROPERTY_TYPE_0 5
+
+/* Note section name of program property.   */
+#define NOTE_GNU_PROPERTY_SECTION_NAME ".note.gnu.property"
+
+/* Values used in GNU .note.gnu.property notes (NT_GNU_PROPERTY_TYPE_0).  */
+
+/* Stack size.  */
+#define GNU_PROPERTY_STACK_SIZE			1
+/* No copy relocation on protected data symbol.  */
+#define GNU_PROPERTY_NO_COPY_ON_PROTECTED	2
+
+/* Processor-specific semantics, lo */
+#define GNU_PROPERTY_LOPROC			0xc0000000
+/* Processor-specific semantics, hi */
+#define GNU_PROPERTY_HIPROC			0xdfffffff
+/* Application-specific semantics, lo */
+#define GNU_PROPERTY_LOUSER			0xe0000000
+/* Application-specific semantics, hi */
+#define GNU_PROPERTY_HIUSER			0xffffffff
+
+/* The x86 instruction sets indicated by the corresponding bits are
+   used in program.  Their support in the hardware is optional.  */
+#define GNU_PROPERTY_X86_ISA_1_USED		0xc0000000
+/* The x86 instruction sets indicated by the corresponding bits are
+   used in program and they must be supported by the hardware.   */
+#define GNU_PROPERTY_X86_ISA_1_NEEDED		0xc0000001
+/* X86 processor-specific features used in program.  */
+#define GNU_PROPERTY_X86_FEATURE_1_AND		0xc0000002
+
+#define GNU_PROPERTY_X86_ISA_1_486		(1U << 0)
+#define GNU_PROPERTY_X86_ISA_1_586		(1U << 1)
+#define GNU_PROPERTY_X86_ISA_1_686		(1U << 2)
+#define GNU_PROPERTY_X86_ISA_1_SSE		(1U << 3)
+#define GNU_PROPERTY_X86_ISA_1_SSE2		(1U << 4)
+#define GNU_PROPERTY_X86_ISA_1_SSE3		(1U << 5)
+#define GNU_PROPERTY_X86_ISA_1_SSSE3		(1U << 6)
+#define GNU_PROPERTY_X86_ISA_1_SSE4_1		(1U << 7)
+#define GNU_PROPERTY_X86_ISA_1_SSE4_2		(1U << 8)
+#define GNU_PROPERTY_X86_ISA_1_AVX		(1U << 9)
+#define GNU_PROPERTY_X86_ISA_1_AVX2		(1U << 10)
+#define GNU_PROPERTY_X86_ISA_1_AVX512F		(1U << 11)
+#define GNU_PROPERTY_X86_ISA_1_AVX512CD		(1U << 12)
+#define GNU_PROPERTY_X86_ISA_1_AVX512ER		(1U << 13)
+#define GNU_PROPERTY_X86_ISA_1_AVX512PF		(1U << 14)
+#define GNU_PROPERTY_X86_ISA_1_AVX512VL		(1U << 15)
+#define GNU_PROPERTY_X86_ISA_1_AVX512DQ		(1U << 16)
+#define GNU_PROPERTY_X86_ISA_1_AVX512BW		(1U << 17)
+
+/* This indicates that all executable sections are compatible with
+   IBT.  */
+#define GNU_PROPERTY_X86_FEATURE_1_IBT		(1U << 0)
+/* This indicates that all executable sections are compatible with
+   SHSTK.  */
+#define GNU_PROPERTY_X86_FEATURE_1_SHSTK	(1U << 1)
+
+/* Move records.  */
+typedef struct
+{
+  Elf32_Xword m_value;		/* Symbol value.  */
+  Elf32_Word m_info;		/* Size and index.  */
+  Elf32_Word m_poffset;		/* Symbol offset.  */
+  Elf32_Half m_repeat;		/* Repeat count.  */
+  Elf32_Half m_stride;		/* Stride info.  */
+} Elf32_Move;
+
+typedef struct
+{
+  Elf64_Xword m_value;		/* Symbol value.  */
+  Elf64_Xword m_info;		/* Size and index.  */
+  Elf64_Xword m_poffset;	/* Symbol offset.  */
+  Elf64_Half m_repeat;		/* Repeat count.  */
+  Elf64_Half m_stride;		/* Stride info.  */
+} Elf64_Move;
+
+/* Macro to construct move records.  */
+#define ELF32_M_SYM(info)	((info) >> 8)
+#define ELF32_M_SIZE(info)	((unsigned char) (info))
+#define ELF32_M_INFO(sym, size)	(((sym) << 8) + (unsigned char) (size))
+
+#define ELF64_M_SYM(info)	ELF32_M_SYM (info)
+#define ELF64_M_SIZE(info)	ELF32_M_SIZE (info)
+#define ELF64_M_INFO(sym, size)	ELF32_M_INFO (sym, size)
+
+
+/* Motorola 68k specific definitions.  */
+
+/* Values for Elf32_Ehdr.e_flags.  */
+#define EF_CPU32	0x00810000
+
+/* m68k relocs.  */
+
+#define R_68K_NONE	0		/* No reloc */
+#define R_68K_32	1		/* Direct 32 bit  */
+#define R_68K_16	2		/* Direct 16 bit  */
+#define R_68K_8		3		/* Direct 8 bit  */
+#define R_68K_PC32	4		/* PC relative 32 bit */
+#define R_68K_PC16	5		/* PC relative 16 bit */
+#define R_68K_PC8	6		/* PC relative 8 bit */
+#define R_68K_GOT32	7		/* 32 bit PC relative GOT entry */
+#define R_68K_GOT16	8		/* 16 bit PC relative GOT entry */
+#define R_68K_GOT8	9		/* 8 bit PC relative GOT entry */
+#define R_68K_GOT32O	10		/* 32 bit GOT offset */
+#define R_68K_GOT16O	11		/* 16 bit GOT offset */
+#define R_68K_GOT8O	12		/* 8 bit GOT offset */
+#define R_68K_PLT32	13		/* 32 bit PC relative PLT address */
+#define R_68K_PLT16	14		/* 16 bit PC relative PLT address */
+#define R_68K_PLT8	15		/* 8 bit PC relative PLT address */
+#define R_68K_PLT32O	16		/* 32 bit PLT offset */
+#define R_68K_PLT16O	17		/* 16 bit PLT offset */
+#define R_68K_PLT8O	18		/* 8 bit PLT offset */
+#define R_68K_COPY	19		/* Copy symbol at runtime */
+#define R_68K_GLOB_DAT	20		/* Create GOT entry */
+#define R_68K_JMP_SLOT	21		/* Create PLT entry */
+#define R_68K_RELATIVE	22		/* Adjust by program base */
+#define R_68K_TLS_GD32      25          /* 32 bit GOT offset for GD */
+#define R_68K_TLS_GD16      26          /* 16 bit GOT offset for GD */
+#define R_68K_TLS_GD8       27          /* 8 bit GOT offset for GD */
+#define R_68K_TLS_LDM32     28          /* 32 bit GOT offset for LDM */
+#define R_68K_TLS_LDM16     29          /* 16 bit GOT offset for LDM */
+#define R_68K_TLS_LDM8      30          /* 8 bit GOT offset for LDM */
+#define R_68K_TLS_LDO32     31          /* 32 bit module-relative offset */
+#define R_68K_TLS_LDO16     32          /* 16 bit module-relative offset */
+#define R_68K_TLS_LDO8      33          /* 8 bit module-relative offset */
+#define R_68K_TLS_IE32      34          /* 32 bit GOT offset for IE */
+#define R_68K_TLS_IE16      35          /* 16 bit GOT offset for IE */
+#define R_68K_TLS_IE8       36          /* 8 bit GOT offset for IE */
+#define R_68K_TLS_LE32      37          /* 32 bit offset relative to
+					   static TLS block */
+#define R_68K_TLS_LE16      38          /* 16 bit offset relative to
+					   static TLS block */
+#define R_68K_TLS_LE8       39          /* 8 bit offset relative to
+					   static TLS block */
+#define R_68K_TLS_DTPMOD32  40          /* 32 bit module number */
+#define R_68K_TLS_DTPREL32  41          /* 32 bit module-relative offset */
+#define R_68K_TLS_TPREL32   42          /* 32 bit TP-relative offset */
+/* Keep this the last entry.  */
+#define R_68K_NUM	43
+
+/* Intel 80386 specific definitions.  */
+
+/* i386 relocs.  */
+
+#define R_386_NONE	   0		/* No reloc */
+#define R_386_32	   1		/* Direct 32 bit  */
+#define R_386_PC32	   2		/* PC relative 32 bit */
+#define R_386_GOT32	   3		/* 32 bit GOT entry */
+#define R_386_PLT32	   4		/* 32 bit PLT address */
+#define R_386_COPY	   5		/* Copy symbol at runtime */
+#define R_386_GLOB_DAT	   6		/* Create GOT entry */
+#define R_386_JMP_SLOT	   7		/* Create PLT entry */
+#define R_386_RELATIVE	   8		/* Adjust by program base */
+#define R_386_GOTOFF	   9		/* 32 bit offset to GOT */
+#define R_386_GOTPC	   10		/* 32 bit PC relative offset to GOT */
+#define R_386_32PLT	   11
+#define R_386_TLS_TPOFF	   14		/* Offset in static TLS block */
+#define R_386_TLS_IE	   15		/* Address of GOT entry for static TLS
+					   block offset */
+#define R_386_TLS_GOTIE	   16		/* GOT entry for static TLS block
+					   offset */
+#define R_386_TLS_LE	   17		/* Offset relative to static TLS
+					   block */
+#define R_386_TLS_GD	   18		/* Direct 32 bit for GNU version of
+					   general dynamic thread local data */
+#define R_386_TLS_LDM	   19		/* Direct 32 bit for GNU version of
+					   local dynamic thread local data
+					   in LE code */
+#define R_386_16	   20
+#define R_386_PC16	   21
+#define R_386_8		   22
+#define R_386_PC8	   23
+#define R_386_TLS_GD_32	   24		/* Direct 32 bit for general dynamic
+					   thread local data */
+#define R_386_TLS_GD_PUSH  25		/* Tag for pushl in GD TLS code */
+#define R_386_TLS_GD_CALL  26		/* Relocation for call to
+					   __tls_get_addr() */
+#define R_386_TLS_GD_POP   27		/* Tag for popl in GD TLS code */
+#define R_386_TLS_LDM_32   28		/* Direct 32 bit for local dynamic
+					   thread local data in LE code */
+#define R_386_TLS_LDM_PUSH 29		/* Tag for pushl in LDM TLS code */
+#define R_386_TLS_LDM_CALL 30		/* Relocation for call to
+					   __tls_get_addr() in LDM code */
+#define R_386_TLS_LDM_POP  31		/* Tag for popl in LDM TLS code */
+#define R_386_TLS_LDO_32   32		/* Offset relative to TLS block */
+#define R_386_TLS_IE_32	   33		/* GOT entry for negated static TLS
+					   block offset */
+#define R_386_TLS_LE_32	   34		/* Negated offset relative to static
+					   TLS block */
+#define R_386_TLS_DTPMOD32 35		/* ID of module containing symbol */
+#define R_386_TLS_DTPOFF32 36		/* Offset in TLS block */
+#define R_386_TLS_TPOFF32  37		/* Negated offset in static TLS block */
+#define R_386_SIZE32	   38 		/* 32-bit symbol size */
+#define R_386_TLS_GOTDESC  39		/* GOT offset for TLS descriptor.  */
+#define R_386_TLS_DESC_CALL 40		/* Marker of call through TLS
+					   descriptor for
+					   relaxation.  */
+#define R_386_TLS_DESC     41		/* TLS descriptor containing
+					   pointer to code and to
+					   argument, returning the TLS
+					   offset for the symbol.  */
+#define R_386_IRELATIVE	   42		/* Adjust indirectly by program base */
+#define R_386_GOT32X	   43		/* Load from 32 bit GOT entry,
+					   relaxable. */
+/* Keep this the last entry.  */
+#define R_386_NUM	   44
+
+/* SUN SPARC specific definitions.  */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_SPARC_REGISTER	13	/* Global register reserved to app. */
+
+/* Values for Elf64_Ehdr.e_flags.  */
+
+#define EF_SPARCV9_MM		3
+#define EF_SPARCV9_TSO		0
+#define EF_SPARCV9_PSO		1
+#define EF_SPARCV9_RMO		2
+#define EF_SPARC_LEDATA		0x800000 /* little endian data */
+#define EF_SPARC_EXT_MASK	0xFFFF00
+#define EF_SPARC_32PLUS		0x000100 /* generic V8+ features */
+#define EF_SPARC_SUN_US1	0x000200 /* Sun UltraSPARC1 extensions */
+#define EF_SPARC_HAL_R1		0x000400 /* HAL R1 extensions */
+#define EF_SPARC_SUN_US3	0x000800 /* Sun UltraSPARCIII extensions */
+
+/* SPARC relocs.  */
+
+#define R_SPARC_NONE		0	/* No reloc */
+#define R_SPARC_8		1	/* Direct 8 bit */
+#define R_SPARC_16		2	/* Direct 16 bit */
+#define R_SPARC_32		3	/* Direct 32 bit */
+#define R_SPARC_DISP8		4	/* PC relative 8 bit */
+#define R_SPARC_DISP16		5	/* PC relative 16 bit */
+#define R_SPARC_DISP32		6	/* PC relative 32 bit */
+#define R_SPARC_WDISP30		7	/* PC relative 30 bit shifted */
+#define R_SPARC_WDISP22		8	/* PC relative 22 bit shifted */
+#define R_SPARC_HI22		9	/* High 22 bit */
+#define R_SPARC_22		10	/* Direct 22 bit */
+#define R_SPARC_13		11	/* Direct 13 bit */
+#define R_SPARC_LO10		12	/* Truncated 10 bit */
+#define R_SPARC_GOT10		13	/* Truncated 10 bit GOT entry */
+#define R_SPARC_GOT13		14	/* 13 bit GOT entry */
+#define R_SPARC_GOT22		15	/* 22 bit GOT entry shifted */
+#define R_SPARC_PC10		16	/* PC relative 10 bit truncated */
+#define R_SPARC_PC22		17	/* PC relative 22 bit shifted */
+#define R_SPARC_WPLT30		18	/* 30 bit PC relative PLT address */
+#define R_SPARC_COPY		19	/* Copy symbol at runtime */
+#define R_SPARC_GLOB_DAT	20	/* Create GOT entry */
+#define R_SPARC_JMP_SLOT	21	/* Create PLT entry */
+#define R_SPARC_RELATIVE	22	/* Adjust by program base */
+#define R_SPARC_UA32		23	/* Direct 32 bit unaligned */
+
+/* Additional Sparc64 relocs.  */
+
+#define R_SPARC_PLT32		24	/* Direct 32 bit ref to PLT entry */
+#define R_SPARC_HIPLT22		25	/* High 22 bit PLT entry */
+#define R_SPARC_LOPLT10		26	/* Truncated 10 bit PLT entry */
+#define R_SPARC_PCPLT32		27	/* PC rel 32 bit ref to PLT entry */
+#define R_SPARC_PCPLT22		28	/* PC rel high 22 bit PLT entry */
+#define R_SPARC_PCPLT10		29	/* PC rel trunc 10 bit PLT entry */
+#define R_SPARC_10		30	/* Direct 10 bit */
+#define R_SPARC_11		31	/* Direct 11 bit */
+#define R_SPARC_64		32	/* Direct 64 bit */
+#define R_SPARC_OLO10		33	/* 10bit with secondary 13bit addend */
+#define R_SPARC_HH22		34	/* Top 22 bits of direct 64 bit */
+#define R_SPARC_HM10		35	/* High middle 10 bits of ... */
+#define R_SPARC_LM22		36	/* Low middle 22 bits of ... */
+#define R_SPARC_PC_HH22		37	/* Top 22 bits of pc rel 64 bit */
+#define R_SPARC_PC_HM10		38	/* High middle 10 bit of ... */
+#define R_SPARC_PC_LM22		39	/* Low miggle 22 bits of ... */
+#define R_SPARC_WDISP16		40	/* PC relative 16 bit shifted */
+#define R_SPARC_WDISP19		41	/* PC relative 19 bit shifted */
+#define R_SPARC_GLOB_JMP	42	/* was part of v9 ABI but was removed */
+#define R_SPARC_7		43	/* Direct 7 bit */
+#define R_SPARC_5		44	/* Direct 5 bit */
+#define R_SPARC_6		45	/* Direct 6 bit */
+#define R_SPARC_DISP64		46	/* PC relative 64 bit */
+#define R_SPARC_PLT64		47	/* Direct 64 bit ref to PLT entry */
+#define R_SPARC_HIX22		48	/* High 22 bit complemented */
+#define R_SPARC_LOX10		49	/* Truncated 11 bit complemented */
+#define R_SPARC_H44		50	/* Direct high 12 of 44 bit */
+#define R_SPARC_M44		51	/* Direct mid 22 of 44 bit */
+#define R_SPARC_L44		52	/* Direct low 10 of 44 bit */
+#define R_SPARC_REGISTER	53	/* Global register usage */
+#define R_SPARC_UA64		54	/* Direct 64 bit unaligned */
+#define R_SPARC_UA16		55	/* Direct 16 bit unaligned */
+#define R_SPARC_TLS_GD_HI22	56
+#define R_SPARC_TLS_GD_LO10	57
+#define R_SPARC_TLS_GD_ADD	58
+#define R_SPARC_TLS_GD_CALL	59
+#define R_SPARC_TLS_LDM_HI22	60
+#define R_SPARC_TLS_LDM_LO10	61
+#define R_SPARC_TLS_LDM_ADD	62
+#define R_SPARC_TLS_LDM_CALL	63
+#define R_SPARC_TLS_LDO_HIX22	64
+#define R_SPARC_TLS_LDO_LOX10	65
+#define R_SPARC_TLS_LDO_ADD	66
+#define R_SPARC_TLS_IE_HI22	67
+#define R_SPARC_TLS_IE_LO10	68
+#define R_SPARC_TLS_IE_LD	69
+#define R_SPARC_TLS_IE_LDX	70
+#define R_SPARC_TLS_IE_ADD	71
+#define R_SPARC_TLS_LE_HIX22	72
+#define R_SPARC_TLS_LE_LOX10	73
+#define R_SPARC_TLS_DTPMOD32	74
+#define R_SPARC_TLS_DTPMOD64	75
+#define R_SPARC_TLS_DTPOFF32	76
+#define R_SPARC_TLS_DTPOFF64	77
+#define R_SPARC_TLS_TPOFF32	78
+#define R_SPARC_TLS_TPOFF64	79
+#define R_SPARC_GOTDATA_HIX22	80
+#define R_SPARC_GOTDATA_LOX10	81
+#define R_SPARC_GOTDATA_OP_HIX22	82
+#define R_SPARC_GOTDATA_OP_LOX10	83
+#define R_SPARC_GOTDATA_OP	84
+#define R_SPARC_H34		85
+#define R_SPARC_SIZE32		86
+#define R_SPARC_SIZE64		87
+#define R_SPARC_WDISP10		88
+#define R_SPARC_JMP_IREL	248
+#define R_SPARC_IRELATIVE	249
+#define R_SPARC_GNU_VTINHERIT	250
+#define R_SPARC_GNU_VTENTRY	251
+#define R_SPARC_REV32		252
+/* Keep this the last entry.  */
+#define R_SPARC_NUM		253
+
+/* For Sparc64, legal values for d_tag of Elf64_Dyn.  */
+
+#define DT_SPARC_REGISTER	0x70000001
+#define DT_SPARC_NUM		2
+
+/* MIPS R3000 specific definitions.  */
+
+/* Legal values for e_flags field of Elf32_Ehdr.  */
+
+#define EF_MIPS_NOREORDER	1     /* A .noreorder directive was used.  */
+#define EF_MIPS_PIC		2     /* Contains PIC code.  */
+#define EF_MIPS_CPIC		4     /* Uses PIC calling sequence.  */
+#define EF_MIPS_XGOT		8
+#define EF_MIPS_64BIT_WHIRL	16
+#define EF_MIPS_ABI2		32
+#define EF_MIPS_ABI_ON32	64
+#define EF_MIPS_FP64		512  /* Uses FP64 (12 callee-saved).  */
+#define EF_MIPS_NAN2008	1024  /* Uses IEEE 754-2008 NaN encoding.  */
+#define EF_MIPS_ARCH		0xf0000000 /* MIPS architecture level.  */
+
+/* Legal values for MIPS architecture level.  */
+
+#define EF_MIPS_ARCH_1		0x00000000 /* -mips1 code.  */
+#define EF_MIPS_ARCH_2		0x10000000 /* -mips2 code.  */
+#define EF_MIPS_ARCH_3		0x20000000 /* -mips3 code.  */
+#define EF_MIPS_ARCH_4		0x30000000 /* -mips4 code.  */
+#define EF_MIPS_ARCH_5		0x40000000 /* -mips5 code.  */
+#define EF_MIPS_ARCH_32		0x50000000 /* MIPS32 code.  */
+#define EF_MIPS_ARCH_64		0x60000000 /* MIPS64 code.  */
+#define EF_MIPS_ARCH_32R2	0x70000000 /* MIPS32r2 code.  */
+#define EF_MIPS_ARCH_64R2	0x80000000 /* MIPS64r2 code.  */
+
+/* The following are unofficial names and should not be used.  */
+
+#define E_MIPS_ARCH_1		EF_MIPS_ARCH_1
+#define E_MIPS_ARCH_2		EF_MIPS_ARCH_2
+#define E_MIPS_ARCH_3		EF_MIPS_ARCH_3
+#define E_MIPS_ARCH_4		EF_MIPS_ARCH_4
+#define E_MIPS_ARCH_5		EF_MIPS_ARCH_5
+#define E_MIPS_ARCH_32		EF_MIPS_ARCH_32
+#define E_MIPS_ARCH_64		EF_MIPS_ARCH_64
+
+/* Special section indices.  */
+
+#define SHN_MIPS_ACOMMON	0xff00	/* Allocated common symbols.  */
+#define SHN_MIPS_TEXT		0xff01	/* Allocated test symbols.  */
+#define SHN_MIPS_DATA		0xff02	/* Allocated data symbols.  */
+#define SHN_MIPS_SCOMMON 	0xff03	/* Small common symbols.  */
+#define SHN_MIPS_SUNDEFINED	0xff04	/* Small undefined symbols.  */
+
+/* Legal values for sh_type field of Elf32_Shdr.  */
+
+#define SHT_MIPS_LIBLIST	0x70000000 /* Shared objects used in link.  */
+#define SHT_MIPS_MSYM		0x70000001
+#define SHT_MIPS_CONFLICT	0x70000002 /* Conflicting symbols.  */
+#define SHT_MIPS_GPTAB		0x70000003 /* Global data area sizes.  */
+#define SHT_MIPS_UCODE		0x70000004 /* Reserved for SGI/MIPS compilers */
+#define SHT_MIPS_DEBUG		0x70000005 /* MIPS ECOFF debugging info.  */
+#define SHT_MIPS_REGINFO	0x70000006 /* Register usage information.  */
+#define SHT_MIPS_PACKAGE	0x70000007
+#define SHT_MIPS_PACKSYM	0x70000008
+#define SHT_MIPS_RELD		0x70000009
+#define SHT_MIPS_IFACE		0x7000000b
+#define SHT_MIPS_CONTENT	0x7000000c
+#define SHT_MIPS_OPTIONS	0x7000000d /* Miscellaneous options.  */
+#define SHT_MIPS_SHDR		0x70000010
+#define SHT_MIPS_FDESC		0x70000011
+#define SHT_MIPS_EXTSYM		0x70000012
+#define SHT_MIPS_DENSE		0x70000013
+#define SHT_MIPS_PDESC		0x70000014
+#define SHT_MIPS_LOCSYM		0x70000015
+#define SHT_MIPS_AUXSYM		0x70000016
+#define SHT_MIPS_OPTSYM		0x70000017
+#define SHT_MIPS_LOCSTR		0x70000018
+#define SHT_MIPS_LINE		0x70000019
+#define SHT_MIPS_RFDESC		0x7000001a
+#define SHT_MIPS_DELTASYM	0x7000001b
+#define SHT_MIPS_DELTAINST	0x7000001c
+#define SHT_MIPS_DELTACLASS	0x7000001d
+#define SHT_MIPS_DWARF		0x7000001e /* DWARF debugging information.  */
+#define SHT_MIPS_DELTADECL	0x7000001f
+#define SHT_MIPS_SYMBOL_LIB	0x70000020
+#define SHT_MIPS_EVENTS		0x70000021 /* Event section.  */
+#define SHT_MIPS_TRANSLATE	0x70000022
+#define SHT_MIPS_PIXIE		0x70000023
+#define SHT_MIPS_XLATE		0x70000024
+#define SHT_MIPS_XLATE_DEBUG	0x70000025
+#define SHT_MIPS_WHIRL		0x70000026
+#define SHT_MIPS_EH_REGION	0x70000027
+#define SHT_MIPS_XLATE_OLD	0x70000028
+#define SHT_MIPS_PDR_EXCEPTION	0x70000029
+
+/* Legal values for sh_flags field of Elf32_Shdr.  */
+
+#define SHF_MIPS_GPREL		0x10000000 /* Must be in global data area.  */
+#define SHF_MIPS_MERGE		0x20000000
+#define SHF_MIPS_ADDR		0x40000000
+#define SHF_MIPS_STRINGS	0x80000000
+#define SHF_MIPS_NOSTRIP	0x08000000
+#define SHF_MIPS_LOCAL		0x04000000
+#define SHF_MIPS_NAMES		0x02000000
+#define SHF_MIPS_NODUPE		0x01000000
+
+
+/* Symbol tables.  */
+
+/* MIPS specific values for `st_other'.  */
+#define STO_MIPS_DEFAULT		0x0
+#define STO_MIPS_INTERNAL		0x1
+#define STO_MIPS_HIDDEN			0x2
+#define STO_MIPS_PROTECTED		0x3
+#define STO_MIPS_PLT			0x8
+#define STO_MIPS_SC_ALIGN_UNUSED	0xff
+
+/* MIPS specific values for `st_info'.  */
+#define STB_MIPS_SPLIT_COMMON		13
+
+/* Entries found in sections of type SHT_MIPS_GPTAB.  */
+
+typedef union
+{
+  struct
+    {
+      Elf32_Word gt_current_g_value;	/* -G value used for compilation.  */
+      Elf32_Word gt_unused;		/* Not used.  */
+    } gt_header;			/* First entry in section.  */
+  struct
+    {
+      Elf32_Word gt_g_value;		/* If this value were used for -G.  */
+      Elf32_Word gt_bytes;		/* This many bytes would be used.  */
+    } gt_entry;				/* Subsequent entries in section.  */
+} Elf32_gptab;
+
+/* Entry found in sections of type SHT_MIPS_REGINFO.  */
+
+typedef struct
+{
+  Elf32_Word ri_gprmask;		/* General registers used.  */
+  Elf32_Word ri_cprmask[4];		/* Coprocessor registers used.  */
+  Elf32_Sword ri_gp_value;		/* $gp register value.  */
+} Elf32_RegInfo;
+
+/* Entries found in sections of type SHT_MIPS_OPTIONS.  */
+
+typedef struct
+{
+  unsigned char kind;		/* Determines interpretation of the
+				   variable part of descriptor.  */
+  unsigned char size;		/* Size of descriptor, including header.  */
+  Elf32_Section section;	/* Section header index of section affected,
+				   0 for global options.  */
+  Elf32_Word info;		/* Kind-specific information.  */
+} Elf_Options;
+
+/* Values for `kind' field in Elf_Options.  */
+
+#define ODK_NULL	0	/* Undefined.  */
+#define ODK_REGINFO	1	/* Register usage information.  */
+#define ODK_EXCEPTIONS	2	/* Exception processing options.  */
+#define ODK_PAD		3	/* Section padding options.  */
+#define ODK_HWPATCH	4	/* Hardware workarounds performed */
+#define ODK_FILL	5	/* record the fill value used by the linker. */
+#define ODK_TAGS	6	/* reserve space for desktop tools to write. */
+#define ODK_HWAND	7	/* HW workarounds.  'AND' bits when merging. */
+#define ODK_HWOR	8	/* HW workarounds.  'OR' bits when merging.  */
+
+/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries.  */
+
+#define OEX_FPU_MIN	0x1f	/* FPE's which MUST be enabled.  */
+#define OEX_FPU_MAX	0x1f00	/* FPE's which MAY be enabled.  */
+#define OEX_PAGE0	0x10000	/* page zero must be mapped.  */
+#define OEX_SMM		0x20000	/* Force sequential memory mode?  */
+#define OEX_FPDBUG	0x40000	/* Force floating point debug mode?  */
+#define OEX_PRECISEFP	OEX_FPDBUG
+#define OEX_DISMISS	0x80000	/* Dismiss invalid address faults?  */
+
+#define OEX_FPU_INVAL	0x10
+#define OEX_FPU_DIV0	0x08
+#define OEX_FPU_OFLO	0x04
+#define OEX_FPU_UFLO	0x02
+#define OEX_FPU_INEX	0x01
+
+/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry.  */
+
+#define OHW_R4KEOP	0x1	/* R4000 end-of-page patch.  */
+#define OHW_R8KPFETCH	0x2	/* may need R8000 prefetch patch.  */
+#define OHW_R5KEOP	0x4	/* R5000 end-of-page patch.  */
+#define OHW_R5KCVTL	0x8	/* R5000 cvt.[ds].l bug.  clean=1.  */
+
+#define OPAD_PREFIX	0x1
+#define OPAD_POSTFIX	0x2
+#define OPAD_SYMBOL	0x4
+
+/* Entry found in `.options' section.  */
+
+typedef struct
+{
+  Elf32_Word hwp_flags1;	/* Extra flags.  */
+  Elf32_Word hwp_flags2;	/* Extra flags.  */
+} Elf_Options_Hw;
+
+/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries.  */
+
+#define OHWA0_R4KEOP_CHECKED	0x00000001
+#define OHWA1_R4KEOP_CLEAN	0x00000002
+
+/* MIPS relocs.  */
+
+#define R_MIPS_NONE		0	/* No reloc */
+#define R_MIPS_16		1	/* Direct 16 bit */
+#define R_MIPS_32		2	/* Direct 32 bit */
+#define R_MIPS_REL32		3	/* PC relative 32 bit */
+#define R_MIPS_26		4	/* Direct 26 bit shifted */
+#define R_MIPS_HI16		5	/* High 16 bit */
+#define R_MIPS_LO16		6	/* Low 16 bit */
+#define R_MIPS_GPREL16		7	/* GP relative 16 bit */
+#define R_MIPS_LITERAL		8	/* 16 bit literal entry */
+#define R_MIPS_GOT16		9	/* 16 bit GOT entry */
+#define R_MIPS_PC16		10	/* PC relative 16 bit */
+#define R_MIPS_CALL16		11	/* 16 bit GOT entry for function */
+#define R_MIPS_GPREL32		12	/* GP relative 32 bit */
+
+#define R_MIPS_SHIFT5		16
+#define R_MIPS_SHIFT6		17
+#define R_MIPS_64		18
+#define R_MIPS_GOT_DISP		19
+#define R_MIPS_GOT_PAGE		20
+#define R_MIPS_GOT_OFST		21
+#define R_MIPS_GOT_HI16		22
+#define R_MIPS_GOT_LO16		23
+#define R_MIPS_SUB		24
+#define R_MIPS_INSERT_A		25
+#define R_MIPS_INSERT_B		26
+#define R_MIPS_DELETE		27
+#define R_MIPS_HIGHER		28
+#define R_MIPS_HIGHEST		29
+#define R_MIPS_CALL_HI16	30
+#define R_MIPS_CALL_LO16	31
+#define R_MIPS_SCN_DISP		32
+#define R_MIPS_REL16		33
+#define R_MIPS_ADD_IMMEDIATE	34
+#define R_MIPS_PJUMP		35
+#define R_MIPS_RELGOT		36
+#define R_MIPS_JALR		37
+#define R_MIPS_TLS_DTPMOD32	38	/* Module number 32 bit */
+#define R_MIPS_TLS_DTPREL32	39	/* Module-relative offset 32 bit */
+#define R_MIPS_TLS_DTPMOD64	40	/* Module number 64 bit */
+#define R_MIPS_TLS_DTPREL64	41	/* Module-relative offset 64 bit */
+#define R_MIPS_TLS_GD		42	/* 16 bit GOT offset for GD */
+#define R_MIPS_TLS_LDM		43	/* 16 bit GOT offset for LDM */
+#define R_MIPS_TLS_DTPREL_HI16	44	/* Module-relative offset, high 16 bits */
+#define R_MIPS_TLS_DTPREL_LO16	45	/* Module-relative offset, low 16 bits */
+#define R_MIPS_TLS_GOTTPREL	46	/* 16 bit GOT offset for IE */
+#define R_MIPS_TLS_TPREL32	47	/* TP-relative offset, 32 bit */
+#define R_MIPS_TLS_TPREL64	48	/* TP-relative offset, 64 bit */
+#define R_MIPS_TLS_TPREL_HI16	49	/* TP-relative offset, high 16 bits */
+#define R_MIPS_TLS_TPREL_LO16	50	/* TP-relative offset, low 16 bits */
+#define R_MIPS_GLOB_DAT		51
+#define R_MIPS_COPY		126
+#define R_MIPS_JUMP_SLOT        127
+/* Keep this the last entry.  */
+#define R_MIPS_NUM		128
+
+/* Legal values for p_type field of Elf32_Phdr.  */
+
+#define PT_MIPS_REGINFO	  0x70000000	/* Register usage information. */
+#define PT_MIPS_RTPROC	  0x70000001	/* Runtime procedure table. */
+#define PT_MIPS_OPTIONS	  0x70000002
+#define PT_MIPS_ABIFLAGS  0x70000003	/* FP mode requirement. */
+
+/* Special program header types.  */
+
+#define PF_MIPS_LOCAL	0x10000000
+
+/* Legal values for d_tag field of Elf32_Dyn.  */
+
+#define DT_MIPS_RLD_VERSION  0x70000001	/* Runtime linker interface version */
+#define DT_MIPS_TIME_STAMP   0x70000002	/* Timestamp */
+#define DT_MIPS_ICHECKSUM    0x70000003	/* Checksum */
+#define DT_MIPS_IVERSION     0x70000004	/* Version string (string tbl index) */
+#define DT_MIPS_FLAGS	     0x70000005	/* Flags */
+#define DT_MIPS_BASE_ADDRESS 0x70000006	/* Base address */
+#define DT_MIPS_MSYM	     0x70000007
+#define DT_MIPS_CONFLICT     0x70000008	/* Address of CONFLICT section */
+#define DT_MIPS_LIBLIST	     0x70000009	/* Address of LIBLIST section */
+#define DT_MIPS_LOCAL_GOTNO  0x7000000a	/* Number of local GOT entries */
+#define DT_MIPS_CONFLICTNO   0x7000000b	/* Number of CONFLICT entries */
+#define DT_MIPS_LIBLISTNO    0x70000010	/* Number of LIBLIST entries */
+#define DT_MIPS_SYMTABNO     0x70000011	/* Number of DYNSYM entries */
+#define DT_MIPS_UNREFEXTNO   0x70000012	/* First external DYNSYM */
+#define DT_MIPS_GOTSYM	     0x70000013	/* First GOT entry in DYNSYM */
+#define DT_MIPS_HIPAGENO     0x70000014	/* Number of GOT page table entries */
+#define DT_MIPS_RLD_MAP	     0x70000016	/* Address of run time loader map.  */
+#define DT_MIPS_DELTA_CLASS  0x70000017	/* Delta C++ class definition.  */
+#define DT_MIPS_DELTA_CLASS_NO    0x70000018 /* Number of entries in
+						DT_MIPS_DELTA_CLASS.  */
+#define DT_MIPS_DELTA_INSTANCE    0x70000019 /* Delta C++ class instances.  */
+#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in
+						DT_MIPS_DELTA_INSTANCE.  */
+#define DT_MIPS_DELTA_RELOC  0x7000001b /* Delta relocations.  */
+#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in
+					     DT_MIPS_DELTA_RELOC.  */
+#define DT_MIPS_DELTA_SYM    0x7000001d /* Delta symbols that Delta
+					   relocations refer to.  */
+#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in
+					   DT_MIPS_DELTA_SYM.  */
+#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the
+					     class declaration.  */
+#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in
+						DT_MIPS_DELTA_CLASSSYM.  */
+#define DT_MIPS_CXX_FLAGS    0x70000022 /* Flags indicating for C++ flavor.  */
+#define DT_MIPS_PIXIE_INIT   0x70000023
+#define DT_MIPS_SYMBOL_LIB   0x70000024
+#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
+#define DT_MIPS_LOCAL_GOTIDX 0x70000026
+#define DT_MIPS_HIDDEN_GOTIDX 0x70000027
+#define DT_MIPS_PROTECTED_GOTIDX 0x70000028
+#define DT_MIPS_OPTIONS	     0x70000029 /* Address of .options.  */
+#define DT_MIPS_INTERFACE    0x7000002a /* Address of .interface.  */
+#define DT_MIPS_DYNSTR_ALIGN 0x7000002b
+#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */
+#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve
+						    function stored in GOT.  */
+#define DT_MIPS_PERF_SUFFIX  0x7000002e /* Default suffix of dso to be added
+					   by rld on dlopen() calls.  */
+#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
+#define DT_MIPS_GP_VALUE     0x70000030 /* GP value for aux GOTs.  */
+#define DT_MIPS_AUX_DYNAMIC  0x70000031 /* Address of aux .dynamic.  */
+/* The address of .got.plt in an executable using the new non-PIC ABI.  */
+#define DT_MIPS_PLTGOT	     0x70000032
+/* The base of the PLT in an executable using the new non-PIC ABI if that
+   PLT is writable.  For a non-writable PLT, this is omitted or has a zero
+   value.  */
+#define DT_MIPS_RWPLT        0x70000034
+/* An alternative description of the classic MIPS RLD_MAP that is usable
+   in a PIE as it stores a relative offset from the address of the tag
+   rather than an absolute address.  */
+#define DT_MIPS_RLD_MAP_REL  0x70000035
+#define DT_MIPS_NUM	     0x36
+
+/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry.  */
+
+#define RHF_NONE		   0		/* No flags */
+#define RHF_QUICKSTART		   (1 << 0)	/* Use quickstart */
+#define RHF_NOTPOT		   (1 << 1)	/* Hash size not power of 2 */
+#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2)	/* Ignore LD_LIBRARY_PATH */
+#define RHF_NO_MOVE		   (1 << 3)
+#define RHF_SGI_ONLY		   (1 << 4)
+#define RHF_GUARANTEE_INIT	   (1 << 5)
+#define RHF_DELTA_C_PLUS_PLUS	   (1 << 6)
+#define RHF_GUARANTEE_START_INIT   (1 << 7)
+#define RHF_PIXIE		   (1 << 8)
+#define RHF_DEFAULT_DELAY_LOAD	   (1 << 9)
+#define RHF_REQUICKSTART	   (1 << 10)
+#define RHF_REQUICKSTARTED	   (1 << 11)
+#define RHF_CORD		   (1 << 12)
+#define RHF_NO_UNRES_UNDEF	   (1 << 13)
+#define RHF_RLD_ORDER_SAFE	   (1 << 14)
+
+/* Entries found in sections of type SHT_MIPS_LIBLIST.  */
+
+typedef struct
+{
+  Elf32_Word l_name;		/* Name (string table index) */
+  Elf32_Word l_time_stamp;	/* Timestamp */
+  Elf32_Word l_checksum;	/* Checksum */
+  Elf32_Word l_version;		/* Interface version */
+  Elf32_Word l_flags;		/* Flags */
+} Elf32_Lib;
+
+typedef struct
+{
+  Elf64_Word l_name;		/* Name (string table index) */
+  Elf64_Word l_time_stamp;	/* Timestamp */
+  Elf64_Word l_checksum;	/* Checksum */
+  Elf64_Word l_version;		/* Interface version */
+  Elf64_Word l_flags;		/* Flags */
+} Elf64_Lib;
+
+
+/* Legal values for l_flags.  */
+
+#define LL_NONE		  0
+#define LL_EXACT_MATCH	  (1 << 0)	/* Require exact match */
+#define LL_IGNORE_INT_VER (1 << 1)	/* Ignore interface version */
+#define LL_REQUIRE_MINOR  (1 << 2)
+#define LL_EXPORTS	  (1 << 3)
+#define LL_DELAY_LOAD	  (1 << 4)
+#define LL_DELTA	  (1 << 5)
+
+/* Entries found in sections of type SHT_MIPS_CONFLICT.  */
+
+typedef Elf32_Addr Elf32_Conflict;
+
+typedef struct
+{
+  /* Version of flags structure.  */
+  Elf32_Half version;
+  /* The level of the ISA: 1-5, 32, 64.  */
+  unsigned char isa_level;
+  /* The revision of ISA: 0 for MIPS V and below, 1-n otherwise.  */
+  unsigned char isa_rev;
+  /* The size of general purpose registers.  */
+  unsigned char gpr_size;
+  /* The size of co-processor 1 registers.  */
+  unsigned char cpr1_size;
+  /* The size of co-processor 2 registers.  */
+  unsigned char cpr2_size;
+  /* The floating-point ABI.  */
+  unsigned char fp_abi;
+  /* Processor-specific extension.  */
+  Elf32_Word isa_ext;
+  /* Mask of ASEs used.  */
+  Elf32_Word ases;
+  /* Mask of general flags.  */
+  Elf32_Word flags1;
+  Elf32_Word flags2;
+} Elf_MIPS_ABIFlags_v0;
+
+/* Values for the register size bytes of an abi flags structure.  */
+
+#define MIPS_AFL_REG_NONE	0x00	 /* No registers.  */
+#define MIPS_AFL_REG_32		0x01	 /* 32-bit registers.  */
+#define MIPS_AFL_REG_64		0x02	 /* 64-bit registers.  */
+#define MIPS_AFL_REG_128	0x03	 /* 128-bit registers.  */
+
+/* Masks for the ases word of an ABI flags structure.  */
+
+#define MIPS_AFL_ASE_DSP	0x00000001 /* DSP ASE.  */
+#define MIPS_AFL_ASE_DSPR2	0x00000002 /* DSP R2 ASE.  */
+#define MIPS_AFL_ASE_EVA	0x00000004 /* Enhanced VA Scheme.  */
+#define MIPS_AFL_ASE_MCU	0x00000008 /* MCU (MicroController) ASE.  */
+#define MIPS_AFL_ASE_MDMX	0x00000010 /* MDMX ASE.  */
+#define MIPS_AFL_ASE_MIPS3D	0x00000020 /* MIPS-3D ASE.  */
+#define MIPS_AFL_ASE_MT		0x00000040 /* MT ASE.  */
+#define MIPS_AFL_ASE_SMARTMIPS	0x00000080 /* SmartMIPS ASE.  */
+#define MIPS_AFL_ASE_VIRT	0x00000100 /* VZ ASE.  */
+#define MIPS_AFL_ASE_MSA	0x00000200 /* MSA ASE.  */
+#define MIPS_AFL_ASE_MIPS16	0x00000400 /* MIPS16 ASE.  */
+#define MIPS_AFL_ASE_MICROMIPS	0x00000800 /* MICROMIPS ASE.  */
+#define MIPS_AFL_ASE_XPA	0x00001000 /* XPA ASE.  */
+#define MIPS_AFL_ASE_MASK	0x00001fff /* All ASEs.  */
+
+/* Values for the isa_ext word of an ABI flags structure.  */
+
+#define MIPS_AFL_EXT_XLR	  1   /* RMI Xlr instruction.  */
+#define MIPS_AFL_EXT_OCTEON2	  2   /* Cavium Networks Octeon2.  */
+#define MIPS_AFL_EXT_OCTEONP	  3   /* Cavium Networks OcteonP.  */
+#define MIPS_AFL_EXT_LOONGSON_3A  4   /* Loongson 3A.  */
+#define MIPS_AFL_EXT_OCTEON	  5   /* Cavium Networks Octeon.  */
+#define MIPS_AFL_EXT_5900	  6   /* MIPS R5900 instruction.  */
+#define MIPS_AFL_EXT_4650	  7   /* MIPS R4650 instruction.  */
+#define MIPS_AFL_EXT_4010	  8   /* LSI R4010 instruction.  */
+#define MIPS_AFL_EXT_4100	  9   /* NEC VR4100 instruction.  */
+#define MIPS_AFL_EXT_3900	  10  /* Toshiba R3900 instruction.  */
+#define MIPS_AFL_EXT_10000	  11  /* MIPS R10000 instruction.  */
+#define MIPS_AFL_EXT_SB1	  12  /* Broadcom SB-1 instruction.  */
+#define MIPS_AFL_EXT_4111	  13  /* NEC VR4111/VR4181 instruction.  */
+#define MIPS_AFL_EXT_4120	  14  /* NEC VR4120 instruction.  */
+#define MIPS_AFL_EXT_5400	  15  /* NEC VR5400 instruction.  */
+#define MIPS_AFL_EXT_5500	  16  /* NEC VR5500 instruction.  */
+#define MIPS_AFL_EXT_LOONGSON_2E  17  /* ST Microelectronics Loongson 2E.  */
+#define MIPS_AFL_EXT_LOONGSON_2F  18  /* ST Microelectronics Loongson 2F.  */
+
+/* Masks for the flags1 word of an ABI flags structure.  */
+#define MIPS_AFL_FLAGS1_ODDSPREG  1  /* Uses odd single-precision registers.  */
+
+/* Object attribute values.  */
+enum
+{
+  /* Not tagged or not using any ABIs affected by the differences.  */
+  Val_GNU_MIPS_ABI_FP_ANY = 0,
+  /* Using hard-float -mdouble-float.  */
+  Val_GNU_MIPS_ABI_FP_DOUBLE = 1,
+  /* Using hard-float -msingle-float.  */
+  Val_GNU_MIPS_ABI_FP_SINGLE = 2,
+  /* Using soft-float.  */
+  Val_GNU_MIPS_ABI_FP_SOFT = 3,
+  /* Using -mips32r2 -mfp64.  */
+  Val_GNU_MIPS_ABI_FP_OLD_64 = 4,
+  /* Using -mfpxx.  */
+  Val_GNU_MIPS_ABI_FP_XX = 5,
+  /* Using -mips32r2 -mfp64.  */
+  Val_GNU_MIPS_ABI_FP_64 = 6,
+  /* Using -mips32r2 -mfp64 -mno-odd-spreg.  */
+  Val_GNU_MIPS_ABI_FP_64A = 7,
+  /* Maximum allocated FP ABI value.  */
+  Val_GNU_MIPS_ABI_FP_MAX = 7
+};
+
+/* HPPA specific definitions.  */
+
+/* Legal values for e_flags field of Elf32_Ehdr.  */
+
+#define EF_PARISC_TRAPNIL	0x00010000 /* Trap nil pointer dereference.  */
+#define EF_PARISC_EXT		0x00020000 /* Program uses arch. extensions. */
+#define EF_PARISC_LSB		0x00040000 /* Program expects little endian. */
+#define EF_PARISC_WIDE		0x00080000 /* Program expects wide mode.  */
+#define EF_PARISC_NO_KABP	0x00100000 /* No kernel assisted branch
+					      prediction.  */
+#define EF_PARISC_LAZYSWAP	0x00400000 /* Allow lazy swapping.  */
+#define EF_PARISC_ARCH		0x0000ffff /* Architecture version.  */
+
+/* Defined values for `e_flags & EF_PARISC_ARCH' are:  */
+
+#define EFA_PARISC_1_0		    0x020b /* PA-RISC 1.0 big-endian.  */
+#define EFA_PARISC_1_1		    0x0210 /* PA-RISC 1.1 big-endian.  */
+#define EFA_PARISC_2_0		    0x0214 /* PA-RISC 2.0 big-endian.  */
+
+/* Additional section indeces.  */
+
+#define SHN_PARISC_ANSI_COMMON	0xff00	   /* Section for tenatively declared
+					      symbols in ANSI C.  */
+#define SHN_PARISC_HUGE_COMMON	0xff01	   /* Common blocks in huge model.  */
+
+/* Legal values for sh_type field of Elf32_Shdr.  */
+
+#define SHT_PARISC_EXT		0x70000000 /* Contains product specific ext. */
+#define SHT_PARISC_UNWIND	0x70000001 /* Unwind information.  */
+#define SHT_PARISC_DOC		0x70000002 /* Debug info for optimized code. */
+
+/* Legal values for sh_flags field of Elf32_Shdr.  */
+
+#define SHF_PARISC_SHORT	0x20000000 /* Section with short addressing. */
+#define SHF_PARISC_HUGE		0x40000000 /* Section far from gp.  */
+#define SHF_PARISC_SBP		0x80000000 /* Static branch prediction code. */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_PARISC_MILLICODE	13	/* Millicode function entry point.  */
+
+#define STT_HP_OPAQUE		(STT_LOOS + 0x1)
+#define STT_HP_STUB		(STT_LOOS + 0x2)
+
+/* HPPA relocs.  */
+
+#define R_PARISC_NONE		0	/* No reloc.  */
+#define R_PARISC_DIR32		1	/* Direct 32-bit reference.  */
+#define R_PARISC_DIR21L		2	/* Left 21 bits of eff. address.  */
+#define R_PARISC_DIR17R		3	/* Right 17 bits of eff. address.  */
+#define R_PARISC_DIR17F		4	/* 17 bits of eff. address.  */
+#define R_PARISC_DIR14R		6	/* Right 14 bits of eff. address.  */
+#define R_PARISC_PCREL32	9	/* 32-bit rel. address.  */
+#define R_PARISC_PCREL21L	10	/* Left 21 bits of rel. address.  */
+#define R_PARISC_PCREL17R	11	/* Right 17 bits of rel. address.  */
+#define R_PARISC_PCREL17F	12	/* 17 bits of rel. address.  */
+#define R_PARISC_PCREL14R	14	/* Right 14 bits of rel. address.  */
+#define R_PARISC_DPREL21L	18	/* Left 21 bits of rel. address.  */
+#define R_PARISC_DPREL14R	22	/* Right 14 bits of rel. address.  */
+#define R_PARISC_GPREL21L	26	/* GP-relative, left 21 bits.  */
+#define R_PARISC_GPREL14R	30	/* GP-relative, right 14 bits.  */
+#define R_PARISC_LTOFF21L	34	/* LT-relative, left 21 bits.  */
+#define R_PARISC_LTOFF14R	38	/* LT-relative, right 14 bits.  */
+#define R_PARISC_SECREL32	41	/* 32 bits section rel. address.  */
+#define R_PARISC_SEGBASE	48	/* No relocation, set segment base.  */
+#define R_PARISC_SEGREL32	49	/* 32 bits segment rel. address.  */
+#define R_PARISC_PLTOFF21L	50	/* PLT rel. address, left 21 bits.  */
+#define R_PARISC_PLTOFF14R	54	/* PLT rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF_FPTR32	57	/* 32 bits LT-rel. function pointer. */
+#define R_PARISC_LTOFF_FPTR21L	58	/* LT-rel. fct ptr, left 21 bits. */
+#define R_PARISC_LTOFF_FPTR14R	62	/* LT-rel. fct ptr, right 14 bits. */
+#define R_PARISC_FPTR64		64	/* 64 bits function address.  */
+#define R_PARISC_PLABEL32	65	/* 32 bits function address.  */
+#define R_PARISC_PLABEL21L	66	/* Left 21 bits of fdesc address.  */
+#define R_PARISC_PLABEL14R	70	/* Right 14 bits of fdesc address.  */
+#define R_PARISC_PCREL64	72	/* 64 bits PC-rel. address.  */
+#define R_PARISC_PCREL22F	74	/* 22 bits PC-rel. address.  */
+#define R_PARISC_PCREL14WR	75	/* PC-rel. address, right 14 bits.  */
+#define R_PARISC_PCREL14DR	76	/* PC rel. address, right 14 bits.  */
+#define R_PARISC_PCREL16F	77	/* 16 bits PC-rel. address.  */
+#define R_PARISC_PCREL16WF	78	/* 16 bits PC-rel. address.  */
+#define R_PARISC_PCREL16DF	79	/* 16 bits PC-rel. address.  */
+#define R_PARISC_DIR64		80	/* 64 bits of eff. address.  */
+#define R_PARISC_DIR14WR	83	/* 14 bits of eff. address.  */
+#define R_PARISC_DIR14DR	84	/* 14 bits of eff. address.  */
+#define R_PARISC_DIR16F		85	/* 16 bits of eff. address.  */
+#define R_PARISC_DIR16WF	86	/* 16 bits of eff. address.  */
+#define R_PARISC_DIR16DF	87	/* 16 bits of eff. address.  */
+#define R_PARISC_GPREL64	88	/* 64 bits of GP-rel. address.  */
+#define R_PARISC_GPREL14WR	91	/* GP-rel. address, right 14 bits.  */
+#define R_PARISC_GPREL14DR	92	/* GP-rel. address, right 14 bits.  */
+#define R_PARISC_GPREL16F	93	/* 16 bits GP-rel. address.  */
+#define R_PARISC_GPREL16WF	94	/* 16 bits GP-rel. address.  */
+#define R_PARISC_GPREL16DF	95	/* 16 bits GP-rel. address.  */
+#define R_PARISC_LTOFF64	96	/* 64 bits LT-rel. address.  */
+#define R_PARISC_LTOFF14WR	99	/* LT-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF14DR	100	/* LT-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF16F	101	/* 16 bits LT-rel. address.  */
+#define R_PARISC_LTOFF16WF	102	/* 16 bits LT-rel. address.  */
+#define R_PARISC_LTOFF16DF	103	/* 16 bits LT-rel. address.  */
+#define R_PARISC_SECREL64	104	/* 64 bits section rel. address.  */
+#define R_PARISC_SEGREL64	112	/* 64 bits segment rel. address.  */
+#define R_PARISC_PLTOFF14WR	115	/* PLT-rel. address, right 14 bits.  */
+#define R_PARISC_PLTOFF14DR	116	/* PLT-rel. address, right 14 bits.  */
+#define R_PARISC_PLTOFF16F	117	/* 16 bits LT-rel. address.  */
+#define R_PARISC_PLTOFF16WF	118	/* 16 bits PLT-rel. address.  */
+#define R_PARISC_PLTOFF16DF	119	/* 16 bits PLT-rel. address.  */
+#define R_PARISC_LTOFF_FPTR64	120	/* 64 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR14WR	123	/* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR14DR	124	/* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR16F	125	/* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR16WF	126	/* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR16DF	127	/* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LORESERVE	128
+#define R_PARISC_COPY		128	/* Copy relocation.  */
+#define R_PARISC_IPLT		129	/* Dynamic reloc, imported PLT */
+#define R_PARISC_EPLT		130	/* Dynamic reloc, exported PLT */
+#define R_PARISC_TPREL32	153	/* 32 bits TP-rel. address.  */
+#define R_PARISC_TPREL21L	154	/* TP-rel. address, left 21 bits.  */
+#define R_PARISC_TPREL14R	158	/* TP-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF_TP21L	162	/* LT-TP-rel. address, left 21 bits. */
+#define R_PARISC_LTOFF_TP14R	166	/* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14F	167	/* 14 bits LT-TP-rel. address.  */
+#define R_PARISC_TPREL64	216	/* 64 bits TP-rel. address.  */
+#define R_PARISC_TPREL14WR	219	/* TP-rel. address, right 14 bits.  */
+#define R_PARISC_TPREL14DR	220	/* TP-rel. address, right 14 bits.  */
+#define R_PARISC_TPREL16F	221	/* 16 bits TP-rel. address.  */
+#define R_PARISC_TPREL16WF	222	/* 16 bits TP-rel. address.  */
+#define R_PARISC_TPREL16DF	223	/* 16 bits TP-rel. address.  */
+#define R_PARISC_LTOFF_TP64	224	/* 64 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP14WR	227	/* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14DR	228	/* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP16F	229	/* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP16WF	230	/* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP16DF	231	/* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_GNU_VTENTRY	232
+#define R_PARISC_GNU_VTINHERIT	233
+#define R_PARISC_TLS_GD21L	234	/* GD 21-bit left.  */
+#define R_PARISC_TLS_GD14R	235	/* GD 14-bit right.  */
+#define R_PARISC_TLS_GDCALL	236	/* GD call to __t_g_a.  */
+#define R_PARISC_TLS_LDM21L	237	/* LD module 21-bit left.  */
+#define R_PARISC_TLS_LDM14R	238	/* LD module 14-bit right.  */
+#define R_PARISC_TLS_LDMCALL	239	/* LD module call to __t_g_a.  */
+#define R_PARISC_TLS_LDO21L	240	/* LD offset 21-bit left.  */
+#define R_PARISC_TLS_LDO14R	241	/* LD offset 14-bit right.  */
+#define R_PARISC_TLS_DTPMOD32	242	/* DTP module 32-bit.  */
+#define R_PARISC_TLS_DTPMOD64	243	/* DTP module 64-bit.  */
+#define R_PARISC_TLS_DTPOFF32	244	/* DTP offset 32-bit.  */
+#define R_PARISC_TLS_DTPOFF64	245	/* DTP offset 32-bit.  */
+#define R_PARISC_TLS_LE21L	R_PARISC_TPREL21L
+#define R_PARISC_TLS_LE14R	R_PARISC_TPREL14R
+#define R_PARISC_TLS_IE21L	R_PARISC_LTOFF_TP21L
+#define R_PARISC_TLS_IE14R	R_PARISC_LTOFF_TP14R
+#define R_PARISC_TLS_TPREL32	R_PARISC_TPREL32
+#define R_PARISC_TLS_TPREL64	R_PARISC_TPREL64
+#define R_PARISC_HIRESERVE	255
+
+/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr.  */
+
+#define PT_HP_TLS		(PT_LOOS + 0x0)
+#define PT_HP_CORE_NONE		(PT_LOOS + 0x1)
+#define PT_HP_CORE_VERSION	(PT_LOOS + 0x2)
+#define PT_HP_CORE_KERNEL	(PT_LOOS + 0x3)
+#define PT_HP_CORE_COMM		(PT_LOOS + 0x4)
+#define PT_HP_CORE_PROC		(PT_LOOS + 0x5)
+#define PT_HP_CORE_LOADABLE	(PT_LOOS + 0x6)
+#define PT_HP_CORE_STACK	(PT_LOOS + 0x7)
+#define PT_HP_CORE_SHM		(PT_LOOS + 0x8)
+#define PT_HP_CORE_MMF		(PT_LOOS + 0x9)
+#define PT_HP_PARALLEL		(PT_LOOS + 0x10)
+#define PT_HP_FASTBIND		(PT_LOOS + 0x11)
+#define PT_HP_OPT_ANNOT		(PT_LOOS + 0x12)
+#define PT_HP_HSL_ANNOT		(PT_LOOS + 0x13)
+#define PT_HP_STACK		(PT_LOOS + 0x14)
+
+#define PT_PARISC_ARCHEXT	0x70000000
+#define PT_PARISC_UNWIND	0x70000001
+
+/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr.  */
+
+#define PF_PARISC_SBP		0x08000000
+
+#define PF_HP_PAGE_SIZE		0x00100000
+#define PF_HP_FAR_SHARED	0x00200000
+#define PF_HP_NEAR_SHARED	0x00400000
+#define PF_HP_CODE		0x01000000
+#define PF_HP_MODIFY		0x02000000
+#define PF_HP_LAZYSWAP		0x04000000
+#define PF_HP_SBP		0x08000000
+
+
+/* Alpha specific definitions.  */
+
+/* Legal values for e_flags field of Elf64_Ehdr.  */
+
+#define EF_ALPHA_32BIT		1	/* All addresses must be < 2GB.  */
+#define EF_ALPHA_CANRELAX	2	/* Relocations for relaxing exist.  */
+
+/* Legal values for sh_type field of Elf64_Shdr.  */
+
+/* These two are primerily concerned with ECOFF debugging info.  */
+#define SHT_ALPHA_DEBUG		0x70000001
+#define SHT_ALPHA_REGINFO	0x70000002
+
+/* Legal values for sh_flags field of Elf64_Shdr.  */
+
+#define SHF_ALPHA_GPREL		0x10000000
+
+/* Legal values for st_other field of Elf64_Sym.  */
+#define STO_ALPHA_NOPV		0x80	/* No PV required.  */
+#define STO_ALPHA_STD_GPLOAD	0x88	/* PV only used for initial ldgp.  */
+
+/* Alpha relocs.  */
+
+#define R_ALPHA_NONE		0	/* No reloc */
+#define R_ALPHA_REFLONG		1	/* Direct 32 bit */
+#define R_ALPHA_REFQUAD		2	/* Direct 64 bit */
+#define R_ALPHA_GPREL32		3	/* GP relative 32 bit */
+#define R_ALPHA_LITERAL		4	/* GP relative 16 bit w/optimization */
+#define R_ALPHA_LITUSE		5	/* Optimization hint for LITERAL */
+#define R_ALPHA_GPDISP		6	/* Add displacement to GP */
+#define R_ALPHA_BRADDR		7	/* PC+4 relative 23 bit shifted */
+#define R_ALPHA_HINT		8	/* PC+4 relative 16 bit shifted */
+#define R_ALPHA_SREL16		9	/* PC relative 16 bit */
+#define R_ALPHA_SREL32		10	/* PC relative 32 bit */
+#define R_ALPHA_SREL64		11	/* PC relative 64 bit */
+#define R_ALPHA_GPRELHIGH	17	/* GP relative 32 bit, high 16 bits */
+#define R_ALPHA_GPRELLOW	18	/* GP relative 32 bit, low 16 bits */
+#define R_ALPHA_GPREL16		19	/* GP relative 16 bit */
+#define R_ALPHA_COPY		24	/* Copy symbol at runtime */
+#define R_ALPHA_GLOB_DAT	25	/* Create GOT entry */
+#define R_ALPHA_JMP_SLOT	26	/* Create PLT entry */
+#define R_ALPHA_RELATIVE	27	/* Adjust by program base */
+#define R_ALPHA_TLS_GD_HI	28
+#define R_ALPHA_TLSGD		29
+#define R_ALPHA_TLS_LDM		30
+#define R_ALPHA_DTPMOD64	31
+#define R_ALPHA_GOTDTPREL	32
+#define R_ALPHA_DTPREL64	33
+#define R_ALPHA_DTPRELHI	34
+#define R_ALPHA_DTPRELLO	35
+#define R_ALPHA_DTPREL16	36
+#define R_ALPHA_GOTTPREL	37
+#define R_ALPHA_TPREL64		38
+#define R_ALPHA_TPRELHI		39
+#define R_ALPHA_TPRELLO		40
+#define R_ALPHA_TPREL16		41
+/* Keep this the last entry.  */
+#define R_ALPHA_NUM		46
+
+/* Magic values of the LITUSE relocation addend.  */
+#define LITUSE_ALPHA_ADDR	0
+#define LITUSE_ALPHA_BASE	1
+#define LITUSE_ALPHA_BYTOFF	2
+#define LITUSE_ALPHA_JSR	3
+#define LITUSE_ALPHA_TLS_GD	4
+#define LITUSE_ALPHA_TLS_LDM	5
+
+/* Legal values for d_tag of Elf64_Dyn.  */
+#define DT_ALPHA_PLTRO		(DT_LOPROC + 0)
+#define DT_ALPHA_NUM		1
+
+/* PowerPC specific declarations */
+
+/* Values for Elf32/64_Ehdr.e_flags.  */
+#define EF_PPC_EMB		0x80000000	/* PowerPC embedded flag */
+
+/* Cygnus local bits below */
+#define EF_PPC_RELOCATABLE	0x00010000	/* PowerPC -mrelocatable flag*/
+#define EF_PPC_RELOCATABLE_LIB	0x00008000	/* PowerPC -mrelocatable-lib
+						   flag */
+
+/* PowerPC relocations defined by the ABIs */
+#define R_PPC_NONE		0
+#define R_PPC_ADDR32		1	/* 32bit absolute address */
+#define R_PPC_ADDR24		2	/* 26bit address, 2 bits ignored.  */
+#define R_PPC_ADDR16		3	/* 16bit absolute address */
+#define R_PPC_ADDR16_LO		4	/* lower 16bit of absolute address */
+#define R_PPC_ADDR16_HI		5	/* high 16bit of absolute address */
+#define R_PPC_ADDR16_HA		6	/* adjusted high 16bit */
+#define R_PPC_ADDR14		7	/* 16bit address, 2 bits ignored */
+#define R_PPC_ADDR14_BRTAKEN	8
+#define R_PPC_ADDR14_BRNTAKEN	9
+#define R_PPC_REL24		10	/* PC relative 26 bit */
+#define R_PPC_REL14		11	/* PC relative 16 bit */
+#define R_PPC_REL14_BRTAKEN	12
+#define R_PPC_REL14_BRNTAKEN	13
+#define R_PPC_GOT16		14
+#define R_PPC_GOT16_LO		15
+#define R_PPC_GOT16_HI		16
+#define R_PPC_GOT16_HA		17
+#define R_PPC_PLTREL24		18
+#define R_PPC_COPY		19
+#define R_PPC_GLOB_DAT		20
+#define R_PPC_JMP_SLOT		21
+#define R_PPC_RELATIVE		22
+#define R_PPC_LOCAL24PC		23
+#define R_PPC_UADDR32		24
+#define R_PPC_UADDR16		25
+#define R_PPC_REL32		26
+#define R_PPC_PLT32		27
+#define R_PPC_PLTREL32		28
+#define R_PPC_PLT16_LO		29
+#define R_PPC_PLT16_HI		30
+#define R_PPC_PLT16_HA		31
+#define R_PPC_SDAREL16		32
+#define R_PPC_SECTOFF		33
+#define R_PPC_SECTOFF_LO	34
+#define R_PPC_SECTOFF_HI	35
+#define R_PPC_SECTOFF_HA	36
+
+/* PowerPC relocations defined for the TLS access ABI.  */
+#define R_PPC_TLS		67 /* none	(sym+add)@tls */
+#define R_PPC_DTPMOD32		68 /* word32	(sym+add)@dtpmod */
+#define R_PPC_TPREL16		69 /* half16*	(sym+add)@tprel */
+#define R_PPC_TPREL16_LO	70 /* half16	(sym+add)@tprel@l */
+#define R_PPC_TPREL16_HI	71 /* half16	(sym+add)@tprel@h */
+#define R_PPC_TPREL16_HA	72 /* half16	(sym+add)@tprel@ha */
+#define R_PPC_TPREL32		73 /* word32	(sym+add)@tprel */
+#define R_PPC_DTPREL16		74 /* half16*	(sym+add)@dtprel */
+#define R_PPC_DTPREL16_LO	75 /* half16	(sym+add)@dtprel@l */
+#define R_PPC_DTPREL16_HI	76 /* half16	(sym+add)@dtprel@h */
+#define R_PPC_DTPREL16_HA	77 /* half16	(sym+add)@dtprel@ha */
+#define R_PPC_DTPREL32		78 /* word32	(sym+add)@dtprel */
+#define R_PPC_GOT_TLSGD16	79 /* half16*	(sym+add)@got@tlsgd */
+#define R_PPC_GOT_TLSGD16_LO	80 /* half16	(sym+add)@got@tlsgd@l */
+#define R_PPC_GOT_TLSGD16_HI	81 /* half16	(sym+add)@got@tlsgd@h */
+#define R_PPC_GOT_TLSGD16_HA	82 /* half16	(sym+add)@got@tlsgd@ha */
+#define R_PPC_GOT_TLSLD16	83 /* half16*	(sym+add)@got@tlsld */
+#define R_PPC_GOT_TLSLD16_LO	84 /* half16	(sym+add)@got@tlsld@l */
+#define R_PPC_GOT_TLSLD16_HI	85 /* half16	(sym+add)@got@tlsld@h */
+#define R_PPC_GOT_TLSLD16_HA	86 /* half16	(sym+add)@got@tlsld@ha */
+#define R_PPC_GOT_TPREL16	87 /* half16*	(sym+add)@got@tprel */
+#define R_PPC_GOT_TPREL16_LO	88 /* half16	(sym+add)@got@tprel@l */
+#define R_PPC_GOT_TPREL16_HI	89 /* half16	(sym+add)@got@tprel@h */
+#define R_PPC_GOT_TPREL16_HA	90 /* half16	(sym+add)@got@tprel@ha */
+#define R_PPC_GOT_DTPREL16	91 /* half16*	(sym+add)@got@dtprel */
+#define R_PPC_GOT_DTPREL16_LO	92 /* half16*	(sym+add)@got@dtprel@l */
+#define R_PPC_GOT_DTPREL16_HI	93 /* half16*	(sym+add)@got@dtprel@h */
+#define R_PPC_GOT_DTPREL16_HA	94 /* half16*	(sym+add)@got@dtprel@ha */
+#define R_PPC_TLSGD		95 /* none	(sym+add)@tlsgd */
+#define R_PPC_TLSLD		96 /* none	(sym+add)@tlsld */
+
+/* The remaining relocs are from the Embedded ELF ABI, and are not
+   in the SVR4 ELF ABI.  */
+#define R_PPC_EMB_NADDR32	101
+#define R_PPC_EMB_NADDR16	102
+#define R_PPC_EMB_NADDR16_LO	103
+#define R_PPC_EMB_NADDR16_HI	104
+#define R_PPC_EMB_NADDR16_HA	105
+#define R_PPC_EMB_SDAI16	106
+#define R_PPC_EMB_SDA2I16	107
+#define R_PPC_EMB_SDA2REL	108
+#define R_PPC_EMB_SDA21		109	/* 16 bit offset in SDA */
+#define R_PPC_EMB_MRKREF	110
+#define R_PPC_EMB_RELSEC16	111
+#define R_PPC_EMB_RELST_LO	112
+#define R_PPC_EMB_RELST_HI	113
+#define R_PPC_EMB_RELST_HA	114
+#define R_PPC_EMB_BIT_FLD	115
+#define R_PPC_EMB_RELSDA	116	/* 16 bit relative offset in SDA */
+
+/* Diab tool relocations.  */
+#define R_PPC_DIAB_SDA21_LO	180	/* like EMB_SDA21, but lower 16 bit */
+#define R_PPC_DIAB_SDA21_HI	181	/* like EMB_SDA21, but high 16 bit */
+#define R_PPC_DIAB_SDA21_HA	182	/* like EMB_SDA21, adjusted high 16 */
+#define R_PPC_DIAB_RELSDA_LO	183	/* like EMB_RELSDA, but lower 16 bit */
+#define R_PPC_DIAB_RELSDA_HI	184	/* like EMB_RELSDA, but high 16 bit */
+#define R_PPC_DIAB_RELSDA_HA	185	/* like EMB_RELSDA, adjusted high 16 */
+
+/* GNU extension to support local ifunc.  */
+#define R_PPC_IRELATIVE		248
+
+/* GNU relocs used in PIC code sequences.  */
+#define R_PPC_REL16		249	/* half16   (sym+add-.) */
+#define R_PPC_REL16_LO		250	/* half16   (sym+add-.)@l */
+#define R_PPC_REL16_HI		251	/* half16   (sym+add-.)@h */
+#define R_PPC_REL16_HA		252	/* half16   (sym+add-.)@ha */
+
+/* This is a phony reloc to handle any old fashioned TOC16 references
+   that may still be in object files.  */
+#define R_PPC_TOC16		255
+
+/* PowerPC specific values for the Dyn d_tag field.  */
+#define DT_PPC_GOT		(DT_LOPROC + 0)
+#define DT_PPC_OPT		(DT_LOPROC + 1)
+#define DT_PPC_NUM		2
+
+/* PowerPC specific values for the DT_PPC_OPT Dyn entry.  */
+#define PPC_OPT_TLS		1
+
+/* PowerPC64 relocations defined by the ABIs */
+#define R_PPC64_NONE		R_PPC_NONE
+#define R_PPC64_ADDR32		R_PPC_ADDR32 /* 32bit absolute address */
+#define R_PPC64_ADDR24		R_PPC_ADDR24 /* 26bit address, word aligned */
+#define R_PPC64_ADDR16		R_PPC_ADDR16 /* 16bit absolute address */
+#define R_PPC64_ADDR16_LO	R_PPC_ADDR16_LO	/* lower 16bits of address */
+#define R_PPC64_ADDR16_HI	R_PPC_ADDR16_HI	/* high 16bits of address. */
+#define R_PPC64_ADDR16_HA	R_PPC_ADDR16_HA /* adjusted high 16bits.  */
+#define R_PPC64_ADDR14		R_PPC_ADDR14 /* 16bit address, word aligned */
+#define R_PPC64_ADDR14_BRTAKEN	R_PPC_ADDR14_BRTAKEN
+#define R_PPC64_ADDR14_BRNTAKEN	R_PPC_ADDR14_BRNTAKEN
+#define R_PPC64_REL24		R_PPC_REL24 /* PC-rel. 26 bit, word aligned */
+#define R_PPC64_REL14		R_PPC_REL14 /* PC relative 16 bit */
+#define R_PPC64_REL14_BRTAKEN	R_PPC_REL14_BRTAKEN
+#define R_PPC64_REL14_BRNTAKEN	R_PPC_REL14_BRNTAKEN
+#define R_PPC64_GOT16		R_PPC_GOT16
+#define R_PPC64_GOT16_LO	R_PPC_GOT16_LO
+#define R_PPC64_GOT16_HI	R_PPC_GOT16_HI
+#define R_PPC64_GOT16_HA	R_PPC_GOT16_HA
+
+#define R_PPC64_COPY		R_PPC_COPY
+#define R_PPC64_GLOB_DAT	R_PPC_GLOB_DAT
+#define R_PPC64_JMP_SLOT	R_PPC_JMP_SLOT
+#define R_PPC64_RELATIVE	R_PPC_RELATIVE
+
+#define R_PPC64_UADDR32		R_PPC_UADDR32
+#define R_PPC64_UADDR16		R_PPC_UADDR16
+#define R_PPC64_REL32		R_PPC_REL32
+#define R_PPC64_PLT32		R_PPC_PLT32
+#define R_PPC64_PLTREL32	R_PPC_PLTREL32
+#define R_PPC64_PLT16_LO	R_PPC_PLT16_LO
+#define R_PPC64_PLT16_HI	R_PPC_PLT16_HI
+#define R_PPC64_PLT16_HA	R_PPC_PLT16_HA
+
+#define R_PPC64_SECTOFF		R_PPC_SECTOFF
+#define R_PPC64_SECTOFF_LO	R_PPC_SECTOFF_LO
+#define R_PPC64_SECTOFF_HI	R_PPC_SECTOFF_HI
+#define R_PPC64_SECTOFF_HA	R_PPC_SECTOFF_HA
+#define R_PPC64_ADDR30		37 /* word30 (S + A - P) >> 2 */
+#define R_PPC64_ADDR64		38 /* doubleword64 S + A */
+#define R_PPC64_ADDR16_HIGHER	39 /* half16 #higher(S + A) */
+#define R_PPC64_ADDR16_HIGHERA	40 /* half16 #highera(S + A) */
+#define R_PPC64_ADDR16_HIGHEST	41 /* half16 #highest(S + A) */
+#define R_PPC64_ADDR16_HIGHESTA	42 /* half16 #highesta(S + A) */
+#define R_PPC64_UADDR64		43 /* doubleword64 S + A */
+#define R_PPC64_REL64		44 /* doubleword64 S + A - P */
+#define R_PPC64_PLT64		45 /* doubleword64 L + A */
+#define R_PPC64_PLTREL64	46 /* doubleword64 L + A - P */
+#define R_PPC64_TOC16		47 /* half16* S + A - .TOC */
+#define R_PPC64_TOC16_LO	48 /* half16 #lo(S + A - .TOC.) */
+#define R_PPC64_TOC16_HI	49 /* half16 #hi(S + A - .TOC.) */
+#define R_PPC64_TOC16_HA	50 /* half16 #ha(S + A - .TOC.) */
+#define R_PPC64_TOC		51 /* doubleword64 .TOC */
+#define R_PPC64_PLTGOT16	52 /* half16* M + A */
+#define R_PPC64_PLTGOT16_LO	53 /* half16 #lo(M + A) */
+#define R_PPC64_PLTGOT16_HI	54 /* half16 #hi(M + A) */
+#define R_PPC64_PLTGOT16_HA	55 /* half16 #ha(M + A) */
+
+#define R_PPC64_ADDR16_DS	56 /* half16ds* (S + A) >> 2 */
+#define R_PPC64_ADDR16_LO_DS	57 /* half16ds  #lo(S + A) >> 2 */
+#define R_PPC64_GOT16_DS	58 /* half16ds* (G + A) >> 2 */
+#define R_PPC64_GOT16_LO_DS	59 /* half16ds  #lo(G + A) >> 2 */
+#define R_PPC64_PLT16_LO_DS	60 /* half16ds  #lo(L + A) >> 2 */
+#define R_PPC64_SECTOFF_DS	61 /* half16ds* (R + A) >> 2 */
+#define R_PPC64_SECTOFF_LO_DS	62 /* half16ds  #lo(R + A) >> 2 */
+#define R_PPC64_TOC16_DS	63 /* half16ds* (S + A - .TOC.) >> 2 */
+#define R_PPC64_TOC16_LO_DS	64 /* half16ds  #lo(S + A - .TOC.) >> 2 */
+#define R_PPC64_PLTGOT16_DS	65 /* half16ds* (M + A) >> 2 */
+#define R_PPC64_PLTGOT16_LO_DS	66 /* half16ds  #lo(M + A) >> 2 */
+
+/* PowerPC64 relocations defined for the TLS access ABI.  */
+#define R_PPC64_TLS		67 /* none	(sym+add)@tls */
+#define R_PPC64_DTPMOD64	68 /* doubleword64 (sym+add)@dtpmod */
+#define R_PPC64_TPREL16		69 /* half16*	(sym+add)@tprel */
+#define R_PPC64_TPREL16_LO	70 /* half16	(sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HI	71 /* half16	(sym+add)@tprel@h */
+#define R_PPC64_TPREL16_HA	72 /* half16	(sym+add)@tprel@ha */
+#define R_PPC64_TPREL64		73 /* doubleword64 (sym+add)@tprel */
+#define R_PPC64_DTPREL16	74 /* half16*	(sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO	75 /* half16	(sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HI	76 /* half16	(sym+add)@dtprel@h */
+#define R_PPC64_DTPREL16_HA	77 /* half16	(sym+add)@dtprel@ha */
+#define R_PPC64_DTPREL64	78 /* doubleword64 (sym+add)@dtprel */
+#define R_PPC64_GOT_TLSGD16	79 /* half16*	(sym+add)@got@tlsgd */
+#define R_PPC64_GOT_TLSGD16_LO	80 /* half16	(sym+add)@got@tlsgd@l */
+#define R_PPC64_GOT_TLSGD16_HI	81 /* half16	(sym+add)@got@tlsgd@h */
+#define R_PPC64_GOT_TLSGD16_HA	82 /* half16	(sym+add)@got@tlsgd@ha */
+#define R_PPC64_GOT_TLSLD16	83 /* half16*	(sym+add)@got@tlsld */
+#define R_PPC64_GOT_TLSLD16_LO	84 /* half16	(sym+add)@got@tlsld@l */
+#define R_PPC64_GOT_TLSLD16_HI	85 /* half16	(sym+add)@got@tlsld@h */
+#define R_PPC64_GOT_TLSLD16_HA	86 /* half16	(sym+add)@got@tlsld@ha */
+#define R_PPC64_GOT_TPREL16_DS	87 /* half16ds*	(sym+add)@got@tprel */
+#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */
+#define R_PPC64_GOT_TPREL16_HI	89 /* half16	(sym+add)@got@tprel@h */
+#define R_PPC64_GOT_TPREL16_HA	90 /* half16	(sym+add)@got@tprel@ha */
+#define R_PPC64_GOT_DTPREL16_DS	91 /* half16ds*	(sym+add)@got@dtprel */
+#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */
+#define R_PPC64_GOT_DTPREL16_HI	93 /* half16	(sym+add)@got@dtprel@h */
+#define R_PPC64_GOT_DTPREL16_HA	94 /* half16	(sym+add)@got@dtprel@ha */
+#define R_PPC64_TPREL16_DS	95 /* half16ds*	(sym+add)@tprel */
+#define R_PPC64_TPREL16_LO_DS	96 /* half16ds	(sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HIGHER	97 /* half16	(sym+add)@tprel@higher */
+#define R_PPC64_TPREL16_HIGHERA	98 /* half16	(sym+add)@tprel@highera */
+#define R_PPC64_TPREL16_HIGHEST	99 /* half16	(sym+add)@tprel@highest */
+#define R_PPC64_TPREL16_HIGHESTA 100 /* half16	(sym+add)@tprel@highesta */
+#define R_PPC64_DTPREL16_DS	101 /* half16ds* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO_DS	102 /* half16ds	(sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HIGHER	103 /* half16	(sym+add)@dtprel@higher */
+#define R_PPC64_DTPREL16_HIGHERA 104 /* half16	(sym+add)@dtprel@highera */
+#define R_PPC64_DTPREL16_HIGHEST 105 /* half16	(sym+add)@dtprel@highest */
+#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16	(sym+add)@dtprel@highesta */
+#define R_PPC64_TLSGD		107 /* none	(sym+add)@tlsgd */
+#define R_PPC64_TLSLD		108 /* none	(sym+add)@tlsld */
+#define R_PPC64_TOCSAVE		109 /* none */
+
+/* Added when HA and HI relocs were changed to report overflows.  */
+#define R_PPC64_ADDR16_HIGH	110
+#define R_PPC64_ADDR16_HIGHA	111
+#define R_PPC64_TPREL16_HIGH	112
+#define R_PPC64_TPREL16_HIGHA	113
+#define R_PPC64_DTPREL16_HIGH	114
+#define R_PPC64_DTPREL16_HIGHA	115
+
+/* GNU extension to support local ifunc.  */
+#define R_PPC64_JMP_IREL	247
+#define R_PPC64_IRELATIVE	248
+#define R_PPC64_REL16		249	/* half16   (sym+add-.) */
+#define R_PPC64_REL16_LO	250	/* half16   (sym+add-.)@l */
+#define R_PPC64_REL16_HI	251	/* half16   (sym+add-.)@h */
+#define R_PPC64_REL16_HA	252	/* half16   (sym+add-.)@ha */
+
+/* e_flags bits specifying ABI.
+   1 for original function descriptor using ABI,
+   2 for revised ABI without function descriptors,
+   0 for unspecified or not using any features affected by the differences.  */
+#define EF_PPC64_ABI	3
+
+/* PowerPC64 specific values for the Dyn d_tag field.  */
+#define DT_PPC64_GLINK  (DT_LOPROC + 0)
+#define DT_PPC64_OPD	(DT_LOPROC + 1)
+#define DT_PPC64_OPDSZ	(DT_LOPROC + 2)
+#define DT_PPC64_OPT	(DT_LOPROC + 3)
+#define DT_PPC64_NUM    4
+
+/* PowerPC64 specific bits in the DT_PPC64_OPT Dyn entry.  */
+#define PPC64_OPT_TLS		1
+#define PPC64_OPT_MULTI_TOC	2
+#define PPC64_OPT_LOCALENTRY	4
+
+/* PowerPC64 specific values for the Elf64_Sym st_other field.  */
+#define STO_PPC64_LOCAL_BIT	5
+#define STO_PPC64_LOCAL_MASK	(7 << STO_PPC64_LOCAL_BIT)
+#define PPC64_LOCAL_ENTRY_OFFSET(other)				\
+ (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2)
+
+
+/* ARM specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field.  */
+#define EF_ARM_RELEXEC		0x01
+#define EF_ARM_HASENTRY		0x02
+#define EF_ARM_INTERWORK	0x04
+#define EF_ARM_APCS_26		0x08
+#define EF_ARM_APCS_FLOAT	0x10
+#define EF_ARM_PIC		0x20
+#define EF_ARM_ALIGN8		0x40 /* 8-bit structure alignment is in use */
+#define EF_ARM_NEW_ABI		0x80
+#define EF_ARM_OLD_ABI		0x100
+#define EF_ARM_SOFT_FLOAT	0x200
+#define EF_ARM_VFP_FLOAT	0x400
+#define EF_ARM_MAVERICK_FLOAT	0x800
+
+#define EF_ARM_ABI_FLOAT_SOFT	0x200   /* NB conflicts with EF_ARM_SOFT_FLOAT */
+#define EF_ARM_ABI_FLOAT_HARD	0x400   /* NB conflicts with EF_ARM_VFP_FLOAT */
+
+
+/* Other constants defined in the ARM ELF spec. version B-01.  */
+/* NB. These conflict with values defined above.  */
+#define EF_ARM_SYMSARESORTED	0x04
+#define EF_ARM_DYNSYMSUSESEGIDX	0x08
+#define EF_ARM_MAPSYMSFIRST	0x10
+#define EF_ARM_EABIMASK		0XFF000000
+
+/* Constants defined in AAELF.  */
+#define EF_ARM_BE8	    0x00800000
+#define EF_ARM_LE8	    0x00400000
+
+#define EF_ARM_EABI_VERSION(flags)	((flags) & EF_ARM_EABIMASK)
+#define EF_ARM_EABI_UNKNOWN	0x00000000
+#define EF_ARM_EABI_VER1	0x01000000
+#define EF_ARM_EABI_VER2	0x02000000
+#define EF_ARM_EABI_VER3	0x03000000
+#define EF_ARM_EABI_VER4	0x04000000
+#define EF_ARM_EABI_VER5	0x05000000
+
+/* Additional symbol types for Thumb.  */
+#define STT_ARM_TFUNC		STT_LOPROC /* A Thumb function.  */
+#define STT_ARM_16BIT		STT_HIPROC /* A Thumb label.  */
+
+/* ARM-specific values for sh_flags */
+#define SHF_ARM_ENTRYSECT	0x10000000 /* Section contains an entry point */
+#define SHF_ARM_COMDEF		0x80000000 /* Section may be multiply defined
+					      in the input to a link step.  */
+
+/* ARM-specific program header flags */
+#define PF_ARM_SB		0x10000000 /* Segment contains the location
+					      addressed by the static base. */
+#define PF_ARM_PI		0x20000000 /* Position-independent segment.  */
+#define PF_ARM_ABS		0x40000000 /* Absolute segment.  */
+
+/* Processor specific values for the Phdr p_type field.  */
+#define PT_ARM_EXIDX		(PT_LOPROC + 1)	/* ARM unwind segment.  */
+
+/* Processor specific values for the Shdr sh_type field.  */
+#define SHT_ARM_EXIDX		(SHT_LOPROC + 1) /* ARM unwind section.  */
+#define SHT_ARM_PREEMPTMAP	(SHT_LOPROC + 2) /* Preemption details.  */
+#define SHT_ARM_ATTRIBUTES	(SHT_LOPROC + 3) /* ARM attributes section.  */
+
+
+/* AArch64 relocs.  */
+
+#define R_AARCH64_NONE            0	/* No relocation.  */
+
+/* ILP32 AArch64 relocs.  */
+#define R_AARCH64_P32_ABS32		  1	/* Direct 32 bit.  */
+#define R_AARCH64_P32_COPY		180	/* Copy symbol at runtime.  */
+#define R_AARCH64_P32_GLOB_DAT		181	/* Create GOT entry.  */
+#define R_AARCH64_P32_JUMP_SLOT		182	/* Create PLT entry.  */
+#define R_AARCH64_P32_RELATIVE		183	/* Adjust by program base.  */
+#define R_AARCH64_P32_TLS_DTPMOD	184	/* Module number, 32 bit.  */
+#define R_AARCH64_P32_TLS_DTPREL	185	/* Module-relative offset, 32 bit.  */
+#define R_AARCH64_P32_TLS_TPREL		186	/* TP-relative offset, 32 bit.  */
+#define R_AARCH64_P32_TLSDESC		187	/* TLS Descriptor.  */
+#define R_AARCH64_P32_IRELATIVE		188	/* STT_GNU_IFUNC relocation. */
+
+/* LP64 AArch64 relocs.  */
+#define R_AARCH64_ABS64         257	/* Direct 64 bit. */
+#define R_AARCH64_ABS32         258	/* Direct 32 bit.  */
+#define R_AARCH64_ABS16		259	/* Direct 16-bit.  */
+#define R_AARCH64_PREL64	260	/* PC-relative 64-bit.	*/
+#define R_AARCH64_PREL32	261	/* PC-relative 32-bit.	*/
+#define R_AARCH64_PREL16	262	/* PC-relative 16-bit.	*/
+#define R_AARCH64_MOVW_UABS_G0	263	/* Dir. MOVZ imm. from bits 15:0.  */
+#define R_AARCH64_MOVW_UABS_G0_NC 264	/* Likewise for MOVK; no check.  */
+#define R_AARCH64_MOVW_UABS_G1	265	/* Dir. MOVZ imm. from bits 31:16.  */
+#define R_AARCH64_MOVW_UABS_G1_NC 266	/* Likewise for MOVK; no check.  */
+#define R_AARCH64_MOVW_UABS_G2	267	/* Dir. MOVZ imm. from bits 47:32.  */
+#define R_AARCH64_MOVW_UABS_G2_NC 268	/* Likewise for MOVK; no check.  */
+#define R_AARCH64_MOVW_UABS_G3	269	/* Dir. MOV{K,Z} imm. from 63:48.  */
+#define R_AARCH64_MOVW_SABS_G0	270	/* Dir. MOV{N,Z} imm. from 15:0.  */
+#define R_AARCH64_MOVW_SABS_G1	271	/* Dir. MOV{N,Z} imm. from 31:16.  */
+#define R_AARCH64_MOVW_SABS_G2	272	/* Dir. MOV{N,Z} imm. from 47:32.  */
+#define R_AARCH64_LD_PREL_LO19	273	/* PC-rel. LD imm. from bits 20:2.  */
+#define R_AARCH64_ADR_PREL_LO21	274	/* PC-rel. ADR imm. from bits 20:0.  */
+#define R_AARCH64_ADR_PREL_PG_HI21 275	/* Page-rel. ADRP imm. from 32:12.  */
+#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Likewise; no overflow check.  */
+#define R_AARCH64_ADD_ABS_LO12_NC 277	/* Dir. ADD imm. from bits 11:0.  */
+#define R_AARCH64_LDST8_ABS_LO12_NC 278	/* Likewise for LD/ST; no check. */
+#define R_AARCH64_TSTBR14	279	/* PC-rel. TBZ/TBNZ imm. from 15:2.  */
+#define R_AARCH64_CONDBR19	280	/* PC-rel. cond. br. imm. from 20:2. */
+#define R_AARCH64_JUMP26	282	/* PC-rel. B imm. from bits 27:2.  */
+#define R_AARCH64_CALL26	283	/* Likewise for CALL.  */
+#define R_AARCH64_LDST16_ABS_LO12_NC 284 /* Dir. ADD imm. from bits 11:1.  */
+#define R_AARCH64_LDST32_ABS_LO12_NC 285 /* Likewise for bits 11:2.  */
+#define R_AARCH64_LDST64_ABS_LO12_NC 286 /* Likewise for bits 11:3.  */
+#define R_AARCH64_MOVW_PREL_G0	287	/* PC-rel. MOV{N,Z} imm. from 15:0.  */
+#define R_AARCH64_MOVW_PREL_G0_NC 288	/* Likewise for MOVK; no check.  */
+#define R_AARCH64_MOVW_PREL_G1	289	/* PC-rel. MOV{N,Z} imm. from 31:16. */
+#define R_AARCH64_MOVW_PREL_G1_NC 290	/* Likewise for MOVK; no check.  */
+#define R_AARCH64_MOVW_PREL_G2	291	/* PC-rel. MOV{N,Z} imm. from 47:32. */
+#define R_AARCH64_MOVW_PREL_G2_NC 292	/* Likewise for MOVK; no check.  */
+#define R_AARCH64_MOVW_PREL_G3	293	/* PC-rel. MOV{N,Z} imm. from 63:48. */
+#define R_AARCH64_LDST128_ABS_LO12_NC 299 /* Dir. ADD imm. from bits 11:4.  */
+#define R_AARCH64_MOVW_GOTOFF_G0 300	/* GOT-rel. off. MOV{N,Z} imm. 15:0. */
+#define R_AARCH64_MOVW_GOTOFF_G0_NC 301	/* Likewise for MOVK; no check.  */
+#define R_AARCH64_MOVW_GOTOFF_G1 302	/* GOT-rel. o. MOV{N,Z} imm. 31:16.  */
+#define R_AARCH64_MOVW_GOTOFF_G1_NC 303	/* Likewise for MOVK; no check.  */
+#define R_AARCH64_MOVW_GOTOFF_G2 304	/* GOT-rel. o. MOV{N,Z} imm. 47:32.  */
+#define R_AARCH64_MOVW_GOTOFF_G2_NC 305	/* Likewise for MOVK; no check.  */
+#define R_AARCH64_MOVW_GOTOFF_G3 306	/* GOT-rel. o. MOV{N,Z} imm. 63:48.  */
+#define R_AARCH64_GOTREL64	307	/* GOT-relative 64-bit.  */
+#define R_AARCH64_GOTREL32	308	/* GOT-relative 32-bit.  */
+#define R_AARCH64_GOT_LD_PREL19	309	/* PC-rel. GOT off. load imm. 20:2.  */
+#define R_AARCH64_LD64_GOTOFF_LO15 310	/* GOT-rel. off. LD/ST imm. 14:3.  */
+#define R_AARCH64_ADR_GOT_PAGE	311	/* P-page-rel. GOT off. ADRP 32:12.  */
+#define R_AARCH64_LD64_GOT_LO12_NC 312	/* Dir. GOT off. LD/ST imm. 11:3.  */
+#define R_AARCH64_LD64_GOTPAGE_LO15 313	/* GOT-page-rel. GOT off. LD/ST 14:3 */
+#define R_AARCH64_TLSGD_ADR_PREL21 512	/* PC-relative ADR imm. 20:0.  */
+#define R_AARCH64_TLSGD_ADR_PAGE21 513	/* page-rel. ADRP imm. 32:12.  */
+#define R_AARCH64_TLSGD_ADD_LO12_NC 514	/* direct ADD imm. from 11:0.  */
+#define R_AARCH64_TLSGD_MOVW_G1	515	/* GOT-rel. MOV{N,Z} 31:16.  */
+#define R_AARCH64_TLSGD_MOVW_G0_NC 516	/* GOT-rel. MOVK imm. 15:0.  */
+#define R_AARCH64_TLSLD_ADR_PREL21 517	/* Like 512; local dynamic model.  */
+#define R_AARCH64_TLSLD_ADR_PAGE21 518	/* Like 513; local dynamic model.  */
+#define R_AARCH64_TLSLD_ADD_LO12_NC 519	/* Like 514; local dynamic model.  */
+#define R_AARCH64_TLSLD_MOVW_G1	520	/* Like 515; local dynamic model.  */
+#define R_AARCH64_TLSLD_MOVW_G0_NC 521	/* Like 516; local dynamic model.  */
+#define R_AARCH64_TLSLD_LD_PREL19 522	/* TLS PC-rel. load imm. 20:2.  */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* TLS DTP-rel. MOV{N,Z} 47:32.  */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* TLS DTP-rel. MOV{N,Z} 31:16.  */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* Likewise; MOVK; no check.  */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* TLS DTP-rel. MOV{N,Z} 15:0.  */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 /* Likewise; MOVK; no check.  */
+#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTP-rel. ADD imm. from 23:12. */
+#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTP-rel. ADD imm. from 11:0.  */
+#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* Likewise; no ovfl. check.  */
+#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTP-rel. LD/ST imm. 11:0.  */
+#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* Likewise; no check.  */
+#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTP-rel. LD/ST imm. 11:1.  */
+#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* Likewise; no check.  */
+#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTP-rel. LD/ST imm. 11:2.  */
+#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* Likewise; no check.  */
+#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTP-rel. LD/ST imm. 11:3.  */
+#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* Likewise; no check.  */
+#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* GOT-rel. MOV{N,Z} 31:16.  */
+#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* GOT-rel. MOVK 15:0.  */
+#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page-rel. ADRP 32:12.  */
+#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* Direct LD off. 11:3.  */
+#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* PC-rel. load imm. 20:2.  */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TLS TP-rel. MOV{N,Z} 47:32.  */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 /* TLS TP-rel. MOV{N,Z} 31:16.  */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 /* Likewise; MOVK; no check.  */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 /* TLS TP-rel. MOV{N,Z} 15:0.  */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 /* Likewise; MOVK; no check.  */
+#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 /* TP-rel. ADD imm. 23:12.  */
+#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 /* TP-rel. ADD imm. 11:0.  */
+#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 /* Likewise; no ovfl. check.  */
+#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 /* TP-rel. LD/ST off. 11:0.  */
+#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 /* Likewise; no ovfl. check. */
+#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 /* TP-rel. LD/ST off. 11:1.  */
+#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 /* Likewise; no check.  */
+#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 /* TP-rel. LD/ST off. 11:2.  */
+#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 /* Likewise; no check.  */
+#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 /* TP-rel. LD/ST off. 11:3.  */
+#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 /* Likewise; no check.  */
+#define R_AARCH64_TLSDESC_LD_PREL19 560	/* PC-rel. load immediate 20:2.  */
+#define R_AARCH64_TLSDESC_ADR_PREL21 561 /* PC-rel. ADR immediate 20:0.  */
+#define R_AARCH64_TLSDESC_ADR_PAGE21 562 /* Page-rel. ADRP imm. 32:12.  */
+#define R_AARCH64_TLSDESC_LD64_LO12 563	/* Direct LD off. from 11:3.  */
+#define R_AARCH64_TLSDESC_ADD_LO12 564	/* Direct ADD imm. from 11:0.  */
+#define R_AARCH64_TLSDESC_OFF_G1 565	/* GOT-rel. MOV{N,Z} imm. 31:16.  */
+#define R_AARCH64_TLSDESC_OFF_G0_NC 566	/* GOT-rel. MOVK imm. 15:0; no ck.  */
+#define R_AARCH64_TLSDESC_LDR	567	/* Relax LDR.  */
+#define R_AARCH64_TLSDESC_ADD	568	/* Relax ADD.  */
+#define R_AARCH64_TLSDESC_CALL	569	/* Relax BLR.  */
+#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 /* TP-rel. LD/ST off. 11:4.  */
+#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 /* Likewise; no check.  */
+#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 /* DTP-rel. LD/ST imm. 11:4. */
+#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 /* Likewise; no check.  */
+#define R_AARCH64_COPY         1024	/* Copy symbol at runtime.  */
+#define R_AARCH64_GLOB_DAT     1025	/* Create GOT entry.  */
+#define R_AARCH64_JUMP_SLOT    1026	/* Create PLT entry.  */
+#define R_AARCH64_RELATIVE     1027	/* Adjust by program base.  */
+#define R_AARCH64_TLS_DTPMOD   1028	/* Module number, 64 bit.  */
+#define R_AARCH64_TLS_DTPREL   1029	/* Module-relative offset, 64 bit.  */
+#define R_AARCH64_TLS_TPREL    1030	/* TP-relative offset, 64 bit.  */
+#define R_AARCH64_TLSDESC      1031	/* TLS Descriptor.  */
+#define R_AARCH64_IRELATIVE	1032	/* STT_GNU_IFUNC relocation.  */
+
+/* ARM relocs.  */
+
+#define R_ARM_NONE		0	/* No reloc */
+#define R_ARM_PC24		1	/* Deprecated PC relative 26
+					   bit branch.  */
+#define R_ARM_ABS32		2	/* Direct 32 bit  */
+#define R_ARM_REL32		3	/* PC relative 32 bit */
+#define R_ARM_PC13		4
+#define R_ARM_ABS16		5	/* Direct 16 bit */
+#define R_ARM_ABS12		6	/* Direct 12 bit */
+#define R_ARM_THM_ABS5		7	/* Direct & 0x7C (LDR, STR).  */
+#define R_ARM_ABS8		8	/* Direct 8 bit */
+#define R_ARM_SBREL32		9
+#define R_ARM_THM_PC22		10	/* PC relative 24 bit (Thumb32 BL).  */
+#define R_ARM_THM_PC8		11	/* PC relative & 0x3FC
+					   (Thumb16 LDR, ADD, ADR).  */
+#define R_ARM_AMP_VCALL9	12
+#define R_ARM_SWI24		13	/* Obsolete static relocation.  */
+#define R_ARM_TLS_DESC		13      /* Dynamic relocation.  */
+#define R_ARM_THM_SWI8		14	/* Reserved.  */
+#define R_ARM_XPC25		15	/* Reserved.  */
+#define R_ARM_THM_XPC22		16	/* Reserved.  */
+#define R_ARM_TLS_DTPMOD32	17	/* ID of module containing symbol */
+#define R_ARM_TLS_DTPOFF32	18	/* Offset in TLS block */
+#define R_ARM_TLS_TPOFF32	19	/* Offset in static TLS block */
+#define R_ARM_COPY		20	/* Copy symbol at runtime */
+#define R_ARM_GLOB_DAT		21	/* Create GOT entry */
+#define R_ARM_JUMP_SLOT		22	/* Create PLT entry */
+#define R_ARM_RELATIVE		23	/* Adjust by program base */
+#define R_ARM_GOTOFF		24	/* 32 bit offset to GOT */
+#define R_ARM_GOTPC		25	/* 32 bit PC relative offset to GOT */
+#define R_ARM_GOT32		26	/* 32 bit GOT entry */
+#define R_ARM_PLT32		27	/* Deprecated, 32 bit PLT address.  */
+#define R_ARM_CALL		28	/* PC relative 24 bit (BL, BLX).  */
+#define R_ARM_JUMP24		29	/* PC relative 24 bit
+					   (B, BL<cond>).  */
+#define R_ARM_THM_JUMP24	30	/* PC relative 24 bit (Thumb32 B.W).  */
+#define R_ARM_BASE_ABS		31	/* Adjust by program base.  */
+#define R_ARM_ALU_PCREL_7_0	32	/* Obsolete.  */
+#define R_ARM_ALU_PCREL_15_8	33	/* Obsolete.  */
+#define R_ARM_ALU_PCREL_23_15	34	/* Obsolete.  */
+#define R_ARM_LDR_SBREL_11_0	35	/* Deprecated, prog. base relative.  */
+#define R_ARM_ALU_SBREL_19_12	36	/* Deprecated, prog. base relative.  */
+#define R_ARM_ALU_SBREL_27_20	37	/* Deprecated, prog. base relative.  */
+#define R_ARM_TARGET1		38
+#define R_ARM_SBREL31		39	/* Program base relative.  */
+#define R_ARM_V4BX		40
+#define R_ARM_TARGET2		41
+#define R_ARM_PREL31		42	/* 32 bit PC relative.  */
+#define R_ARM_MOVW_ABS_NC	43	/* Direct 16-bit (MOVW).  */
+#define R_ARM_MOVT_ABS		44	/* Direct high 16-bit (MOVT).  */
+#define R_ARM_MOVW_PREL_NC	45	/* PC relative 16-bit (MOVW).  */
+#define R_ARM_MOVT_PREL		46	/* PC relative (MOVT).  */
+#define R_ARM_THM_MOVW_ABS_NC	47	/* Direct 16 bit (Thumb32 MOVW).  */
+#define R_ARM_THM_MOVT_ABS	48	/* Direct high 16 bit
+					   (Thumb32 MOVT).  */
+#define R_ARM_THM_MOVW_PREL_NC	49	/* PC relative 16 bit
+					   (Thumb32 MOVW).  */
+#define R_ARM_THM_MOVT_PREL	50	/* PC relative high 16 bit
+					   (Thumb32 MOVT).  */
+#define R_ARM_THM_JUMP19	51	/* PC relative 20 bit
+					   (Thumb32 B<cond>.W).  */
+#define R_ARM_THM_JUMP6		52	/* PC relative X & 0x7E
+					   (Thumb16 CBZ, CBNZ).  */
+#define R_ARM_THM_ALU_PREL_11_0	53	/* PC relative 12 bit
+					   (Thumb32 ADR.W).  */
+#define R_ARM_THM_PC12		54	/* PC relative 12 bit
+					   (Thumb32 LDR{D,SB,H,SH}).  */
+#define R_ARM_ABS32_NOI		55	/* Direct 32-bit.  */
+#define R_ARM_REL32_NOI		56	/* PC relative 32-bit.  */
+#define R_ARM_ALU_PC_G0_NC	57	/* PC relative (ADD, SUB).  */
+#define R_ARM_ALU_PC_G0		58	/* PC relative (ADD, SUB).  */
+#define R_ARM_ALU_PC_G1_NC	59	/* PC relative (ADD, SUB).  */
+#define R_ARM_ALU_PC_G1		60	/* PC relative (ADD, SUB).  */
+#define R_ARM_ALU_PC_G2		61	/* PC relative (ADD, SUB).  */
+#define R_ARM_LDR_PC_G1		62	/* PC relative (LDR,STR,LDRB,STRB).  */
+#define R_ARM_LDR_PC_G2		63	/* PC relative (LDR,STR,LDRB,STRB).  */
+#define R_ARM_LDRS_PC_G0	64	/* PC relative (STR{D,H},
+					   LDR{D,SB,H,SH}).  */
+#define R_ARM_LDRS_PC_G1	65	/* PC relative (STR{D,H},
+					   LDR{D,SB,H,SH}).  */
+#define R_ARM_LDRS_PC_G2	66	/* PC relative (STR{D,H},
+					   LDR{D,SB,H,SH}).  */
+#define R_ARM_LDC_PC_G0		67	/* PC relative (LDC, STC).  */
+#define R_ARM_LDC_PC_G1		68	/* PC relative (LDC, STC).  */
+#define R_ARM_LDC_PC_G2		69	/* PC relative (LDC, STC).  */
+#define R_ARM_ALU_SB_G0_NC	70	/* Program base relative (ADD,SUB).  */
+#define R_ARM_ALU_SB_G0		71	/* Program base relative (ADD,SUB).  */
+#define R_ARM_ALU_SB_G1_NC	72	/* Program base relative (ADD,SUB).  */
+#define R_ARM_ALU_SB_G1		73	/* Program base relative (ADD,SUB).  */
+#define R_ARM_ALU_SB_G2		74	/* Program base relative (ADD,SUB).  */
+#define R_ARM_LDR_SB_G0		75	/* Program base relative (LDR,
+					   STR, LDRB, STRB).  */
+#define R_ARM_LDR_SB_G1		76	/* Program base relative
+					   (LDR, STR, LDRB, STRB).  */
+#define R_ARM_LDR_SB_G2		77	/* Program base relative
+					   (LDR, STR, LDRB, STRB).  */
+#define R_ARM_LDRS_SB_G0	78	/* Program base relative
+					   (LDR, STR, LDRB, STRB).  */
+#define R_ARM_LDRS_SB_G1	79	/* Program base relative
+					   (LDR, STR, LDRB, STRB).  */
+#define R_ARM_LDRS_SB_G2	80	/* Program base relative
+					   (LDR, STR, LDRB, STRB).  */
+#define R_ARM_LDC_SB_G0		81	/* Program base relative (LDC,STC).  */
+#define R_ARM_LDC_SB_G1		82	/* Program base relative (LDC,STC).  */
+#define R_ARM_LDC_SB_G2		83	/* Program base relative (LDC,STC).  */
+#define R_ARM_MOVW_BREL_NC	84	/* Program base relative 16
+					   bit (MOVW).  */
+#define R_ARM_MOVT_BREL		85	/* Program base relative high
+					   16 bit (MOVT).  */
+#define R_ARM_MOVW_BREL		86	/* Program base relative 16
+					   bit (MOVW).  */
+#define R_ARM_THM_MOVW_BREL_NC	87	/* Program base relative 16
+					   bit (Thumb32 MOVW).  */
+#define R_ARM_THM_MOVT_BREL	88	/* Program base relative high
+					   16 bit (Thumb32 MOVT).  */
+#define R_ARM_THM_MOVW_BREL	89	/* Program base relative 16
+					   bit (Thumb32 MOVW).  */
+#define R_ARM_TLS_GOTDESC	90
+#define R_ARM_TLS_CALL		91
+#define R_ARM_TLS_DESCSEQ	92	/* TLS relaxation.  */
+#define R_ARM_THM_TLS_CALL	93
+#define R_ARM_PLT32_ABS		94
+#define R_ARM_GOT_ABS		95	/* GOT entry.  */
+#define R_ARM_GOT_PREL		96	/* PC relative GOT entry.  */
+#define R_ARM_GOT_BREL12	97	/* GOT entry relative to GOT
+					   origin (LDR).  */
+#define R_ARM_GOTOFF12		98	/* 12 bit, GOT entry relative
+					   to GOT origin (LDR, STR).  */
+#define R_ARM_GOTRELAX		99
+#define R_ARM_GNU_VTENTRY	100
+#define R_ARM_GNU_VTINHERIT	101
+#define R_ARM_THM_PC11		102	/* PC relative & 0xFFE (Thumb16 B).  */
+#define R_ARM_THM_PC9		103	/* PC relative & 0x1FE
+					   (Thumb16 B/B<cond>).  */
+#define R_ARM_TLS_GD32		104	/* PC-rel 32 bit for global dynamic
+					   thread local data */
+#define R_ARM_TLS_LDM32		105	/* PC-rel 32 bit for local dynamic
+					   thread local data */
+#define R_ARM_TLS_LDO32		106	/* 32 bit offset relative to TLS
+					   block */
+#define R_ARM_TLS_IE32		107	/* PC-rel 32 bit for GOT entry of
+					   static TLS block offset */
+#define R_ARM_TLS_LE32		108	/* 32 bit offset relative to static
+					   TLS block */
+#define R_ARM_TLS_LDO12		109	/* 12 bit relative to TLS
+					   block (LDR, STR).  */
+#define R_ARM_TLS_LE12		110	/* 12 bit relative to static
+					   TLS block (LDR, STR).  */
+#define R_ARM_TLS_IE12GP	111	/* 12 bit GOT entry relative
+					   to GOT origin (LDR).  */
+#define R_ARM_ME_TOO		128	/* Obsolete.  */
+#define R_ARM_THM_TLS_DESCSEQ	129
+#define R_ARM_THM_TLS_DESCSEQ16	129
+#define R_ARM_THM_TLS_DESCSEQ32	130
+#define R_ARM_THM_GOT_BREL12	131	/* GOT entry relative to GOT
+					   origin, 12 bit (Thumb32 LDR).  */
+#define R_ARM_IRELATIVE		160
+#define R_ARM_RXPC25		249
+#define R_ARM_RSBREL32		250
+#define R_ARM_THM_RPC22		251
+#define R_ARM_RREL32		252
+#define R_ARM_RABS22		253
+#define R_ARM_RPC24		254
+#define R_ARM_RBASE		255
+/* Keep this the last entry.  */
+#define R_ARM_NUM		256
+
+/* csky */
+#define R_CKCORE_NONE               0	/* no reloc */
+#define R_CKCORE_ADDR32             1	/* direct 32 bit (S + A) */
+#define R_CKCORE_PCRELIMM8BY4       2	/* disp ((S + A - P) >> 2) & 0xff   */
+#define R_CKCORE_PCRELIMM11BY2      3	/* disp ((S + A - P) >> 1) & 0x7ff  */
+#define R_CKCORE_PCREL32            5	/* 32-bit rel (S + A - P)           */
+#define R_CKCORE_PCRELJSR_IMM11BY2  6	/* disp ((S + A - P) >>1) & 0x7ff   */
+#define R_CKCORE_RELATIVE           9	/* 32 bit adjust program base(B + A)*/
+#define R_CKCORE_COPY               10	/* 32 bit adjust by program base    */
+#define R_CKCORE_GLOB_DAT           11	/* off between got and sym (S)      */
+#define R_CKCORE_JUMP_SLOT          12	/* PLT entry (S) */
+#define R_CKCORE_GOTOFF             13	/* offset to GOT (S + A - GOT)      */
+#define R_CKCORE_GOTPC              14	/* PC offset to GOT (GOT + A - P)   */
+#define R_CKCORE_GOT32              15	/* 32 bit GOT entry (G) */
+#define R_CKCORE_PLT32              16	/* 32 bit PLT entry (G) */
+#define R_CKCORE_ADDRGOT            17	/* GOT entry in GLOB_DAT (GOT + G)  */
+#define R_CKCORE_ADDRPLT            18	/* PLT entry in GLOB_DAT (GOT + G)  */
+#define R_CKCORE_PCREL_IMM26BY2     19	/* ((S + A - P) >> 1) & 0x3ffffff   */
+#define R_CKCORE_PCREL_IMM16BY2     20	/* disp ((S + A - P) >> 1) & 0xffff */
+#define R_CKCORE_PCREL_IMM16BY4     21	/* disp ((S + A - P) >> 2) & 0xffff */
+#define R_CKCORE_PCREL_IMM10BY2     22	/* disp ((S + A - P) >> 1) & 0x3ff  */
+#define R_CKCORE_PCREL_IMM10BY4     23	/* disp ((S + A - P) >> 2) & 0x3ff  */
+#define R_CKCORE_ADDR_HI16          24	/* high & low 16 bit ADDR */
+                                        /* ((S + A) >> 16) & 0xffff */
+#define R_CKCORE_ADDR_LO16          25	/* (S + A) & 0xffff */
+#define R_CKCORE_GOTPC_HI16         26	/* high & low 16 bit GOTPC */
+                                        /* ((GOT + A - P) >> 16) & 0xffff */
+#define R_CKCORE_GOTPC_LO16         27	/* (GOT + A - P) & 0xffff */
+#define R_CKCORE_GOTOFF_HI16        28	/* high & low 16 bit GOTOFF */
+                                        /* ((S + A - GOT) >> 16) & 0xffff */
+#define R_CKCORE_GOTOFF_LO16        29	/* (S + A - GOT) & 0xffff */
+#define R_CKCORE_GOT12              30	/* 12 bit disp GOT entry (G) */
+#define R_CKCORE_GOT_HI16           31	/* high & low 16 bit GOT */
+                                        /* (G >> 16) & 0xffff */
+#define R_CKCORE_GOT_LO16           32	/* (G & 0xffff) */
+#define R_CKCORE_PLT12              33	/* 12 bit disp PLT entry (G) */
+#define R_CKCORE_PLT_HI16           34	/* high & low 16 bit PLT */
+                                        /* (G >> 16) & 0xffff */
+#define R_CKCORE_PLT_LO16           35	/* G & 0xffff */
+#define R_CKCORE_ADDRGOT_HI16       36	/* high & low 16 bit ADDRGOT */
+                                        /* (GOT + G * 4) & 0xffff */
+#define R_CKCORE_ADDRGOT_LO16       37	/* (GOT + G * 4) & 0xffff */
+#define R_CKCORE_ADDRPLT_HI16       38	/* high & low 16 bit ADDRPLT */
+                                        /* ((GOT + G * 4) >> 16) & 0xFFFF */
+#define R_CKCORE_ADDRPLT_LO16       39	/* (GOT+G*4) & 0xffff */
+#define R_CKCORE_PCREL_JSR_IMM26BY2 40	/* disp ((S+A-P) >>1) & x3ffffff */
+#define R_CKCORE_TOFFSET_LO16       41	/* (S+A-BTEXT) & 0xffff */
+#define R_CKCORE_DOFFSET_LO16       42	/* (S+A-BTEXT) & 0xffff */
+#define R_CKCORE_PCREL_IMM18BY2     43	/* disp ((S+A-P) >>1) & 0x3ffff */
+#define R_CKCORE_DOFFSET_IMM18      44	/* disp (S+A-BDATA) & 0x3ffff */
+#define R_CKCORE_DOFFSET_IMM18BY2   45	/* disp ((S+A-BDATA)>>1) & 0x3ffff */
+#define R_CKCORE_DOFFSET_IMM18BY4   46	/* disp ((S+A-BDATA)>>2) & 0x3ffff */
+#define R_CKCORE_GOT_IMM18BY4       48	/* disp (G >> 2) */
+#define R_CKCORE_PLT_IMM18BY4       49	/* disp (G >> 2) */
+#define R_CKCORE_PCREL_IMM7BY4      50	/* disp ((S+A-P) >>2) & 0x7f */
+#define R_CKCORE_TLS_LE32           51	/* 32 bit offset to TLS block */
+#define R_CKCORE_TLS_IE32           52
+#define R_CKCORE_TLS_GD32           53
+#define R_CKCORE_TLS_LDM32          54
+#define R_CKCORE_TLS_LDO32          55
+#define R_CKCORE_TLS_DTPMOD32       56
+#define R_CKCORE_TLS_DTPOFF32       57
+#define R_CKCORE_TLS_TPOFF32        58
+
+/* IA-64 specific declarations.  */
+
+/* Processor specific flags for the Ehdr e_flags field.  */
+#define EF_IA_64_MASKOS		0x0000000f	/* os-specific flags */
+#define EF_IA_64_ABI64		0x00000010	/* 64-bit ABI */
+#define EF_IA_64_ARCH		0xff000000	/* arch. version mask */
+
+/* Processor specific values for the Phdr p_type field.  */
+#define PT_IA_64_ARCHEXT	(PT_LOPROC + 0)	/* arch extension bits */
+#define PT_IA_64_UNWIND		(PT_LOPROC + 1)	/* ia64 unwind bits */
+#define PT_IA_64_HP_OPT_ANOT	(PT_LOOS + 0x12)
+#define PT_IA_64_HP_HSL_ANOT	(PT_LOOS + 0x13)
+#define PT_IA_64_HP_STACK	(PT_LOOS + 0x14)
+
+/* Processor specific flags for the Phdr p_flags field.  */
+#define PF_IA_64_NORECOV	0x80000000	/* spec insns w/o recovery */
+
+/* Processor specific values for the Shdr sh_type field.  */
+#define SHT_IA_64_EXT		(SHT_LOPROC + 0) /* extension bits */
+#define SHT_IA_64_UNWIND	(SHT_LOPROC + 1) /* unwind bits */
+
+/* Processor specific flags for the Shdr sh_flags field.  */
+#define SHF_IA_64_SHORT		0x10000000	/* section near gp */
+#define SHF_IA_64_NORECOV	0x20000000	/* spec insns w/o recovery */
+
+/* Processor specific values for the Dyn d_tag field.  */
+#define DT_IA_64_PLT_RESERVE	(DT_LOPROC + 0)
+#define DT_IA_64_NUM		1
+
+/* IA-64 relocations.  */
+#define R_IA64_NONE		0x00	/* none */
+#define R_IA64_IMM14		0x21	/* symbol + addend, add imm14 */
+#define R_IA64_IMM22		0x22	/* symbol + addend, add imm22 */
+#define R_IA64_IMM64		0x23	/* symbol + addend, mov imm64 */
+#define R_IA64_DIR32MSB		0x24	/* symbol + addend, data4 MSB */
+#define R_IA64_DIR32LSB		0x25	/* symbol + addend, data4 LSB */
+#define R_IA64_DIR64MSB		0x26	/* symbol + addend, data8 MSB */
+#define R_IA64_DIR64LSB		0x27	/* symbol + addend, data8 LSB */
+#define R_IA64_GPREL22		0x2a	/* @gprel(sym + add), add imm22 */
+#define R_IA64_GPREL64I		0x2b	/* @gprel(sym + add), mov imm64 */
+#define R_IA64_GPREL32MSB	0x2c	/* @gprel(sym + add), data4 MSB */
+#define R_IA64_GPREL32LSB	0x2d	/* @gprel(sym + add), data4 LSB */
+#define R_IA64_GPREL64MSB	0x2e	/* @gprel(sym + add), data8 MSB */
+#define R_IA64_GPREL64LSB	0x2f	/* @gprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF22		0x32	/* @ltoff(sym + add), add imm22 */
+#define R_IA64_LTOFF64I		0x33	/* @ltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF22		0x3a	/* @pltoff(sym + add), add imm22 */
+#define R_IA64_PLTOFF64I	0x3b	/* @pltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF64MSB	0x3e	/* @pltoff(sym + add), data8 MSB */
+#define R_IA64_PLTOFF64LSB	0x3f	/* @pltoff(sym + add), data8 LSB */
+#define R_IA64_FPTR64I		0x43	/* @fptr(sym + add), mov imm64 */
+#define R_IA64_FPTR32MSB	0x44	/* @fptr(sym + add), data4 MSB */
+#define R_IA64_FPTR32LSB	0x45	/* @fptr(sym + add), data4 LSB */
+#define R_IA64_FPTR64MSB	0x46	/* @fptr(sym + add), data8 MSB */
+#define R_IA64_FPTR64LSB	0x47	/* @fptr(sym + add), data8 LSB */
+#define R_IA64_PCREL60B		0x48	/* @pcrel(sym + add), brl */
+#define R_IA64_PCREL21B		0x49	/* @pcrel(sym + add), ptb, call */
+#define R_IA64_PCREL21M		0x4a	/* @pcrel(sym + add), chk.s */
+#define R_IA64_PCREL21F		0x4b	/* @pcrel(sym + add), fchkf */
+#define R_IA64_PCREL32MSB	0x4c	/* @pcrel(sym + add), data4 MSB */
+#define R_IA64_PCREL32LSB	0x4d	/* @pcrel(sym + add), data4 LSB */
+#define R_IA64_PCREL64MSB	0x4e	/* @pcrel(sym + add), data8 MSB */
+#define R_IA64_PCREL64LSB	0x4f	/* @pcrel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_FPTR22	0x52	/* @ltoff(@fptr(s+a)), imm22 */
+#define R_IA64_LTOFF_FPTR64I	0x53	/* @ltoff(@fptr(s+a)), imm64 */
+#define R_IA64_LTOFF_FPTR32MSB	0x54	/* @ltoff(@fptr(s+a)), data4 MSB */
+#define R_IA64_LTOFF_FPTR32LSB	0x55	/* @ltoff(@fptr(s+a)), data4 LSB */
+#define R_IA64_LTOFF_FPTR64MSB	0x56	/* @ltoff(@fptr(s+a)), data8 MSB */
+#define R_IA64_LTOFF_FPTR64LSB	0x57	/* @ltoff(@fptr(s+a)), data8 LSB */
+#define R_IA64_SEGREL32MSB	0x5c	/* @segrel(sym + add), data4 MSB */
+#define R_IA64_SEGREL32LSB	0x5d	/* @segrel(sym + add), data4 LSB */
+#define R_IA64_SEGREL64MSB	0x5e	/* @segrel(sym + add), data8 MSB */
+#define R_IA64_SEGREL64LSB	0x5f	/* @segrel(sym + add), data8 LSB */
+#define R_IA64_SECREL32MSB	0x64	/* @secrel(sym + add), data4 MSB */
+#define R_IA64_SECREL32LSB	0x65	/* @secrel(sym + add), data4 LSB */
+#define R_IA64_SECREL64MSB	0x66	/* @secrel(sym + add), data8 MSB */
+#define R_IA64_SECREL64LSB	0x67	/* @secrel(sym + add), data8 LSB */
+#define R_IA64_REL32MSB		0x6c	/* data 4 + REL */
+#define R_IA64_REL32LSB		0x6d	/* data 4 + REL */
+#define R_IA64_REL64MSB		0x6e	/* data 8 + REL */
+#define R_IA64_REL64LSB		0x6f	/* data 8 + REL */
+#define R_IA64_LTV32MSB		0x74	/* symbol + addend, data4 MSB */
+#define R_IA64_LTV32LSB		0x75	/* symbol + addend, data4 LSB */
+#define R_IA64_LTV64MSB		0x76	/* symbol + addend, data8 MSB */
+#define R_IA64_LTV64LSB		0x77	/* symbol + addend, data8 LSB */
+#define R_IA64_PCREL21BI	0x79	/* @pcrel(sym + add), 21bit inst */
+#define R_IA64_PCREL22		0x7a	/* @pcrel(sym + add), 22bit inst */
+#define R_IA64_PCREL64I		0x7b	/* @pcrel(sym + add), 64bit inst */
+#define R_IA64_IPLTMSB		0x80	/* dynamic reloc, imported PLT, MSB */
+#define R_IA64_IPLTLSB		0x81	/* dynamic reloc, imported PLT, LSB */
+#define R_IA64_COPY		0x84	/* copy relocation */
+#define R_IA64_SUB		0x85	/* Addend and symbol difference */
+#define R_IA64_LTOFF22X		0x86	/* LTOFF22, relaxable.  */
+#define R_IA64_LDXMOV		0x87	/* Use of LTOFF22X.  */
+#define R_IA64_TPREL14		0x91	/* @tprel(sym + add), imm14 */
+#define R_IA64_TPREL22		0x92	/* @tprel(sym + add), imm22 */
+#define R_IA64_TPREL64I		0x93	/* @tprel(sym + add), imm64 */
+#define R_IA64_TPREL64MSB	0x96	/* @tprel(sym + add), data8 MSB */
+#define R_IA64_TPREL64LSB	0x97	/* @tprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_TPREL22	0x9a	/* @ltoff(@tprel(s+a)), imm2 */
+#define R_IA64_DTPMOD64MSB	0xa6	/* @dtpmod(sym + add), data8 MSB */
+#define R_IA64_DTPMOD64LSB	0xa7	/* @dtpmod(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPMOD22	0xaa	/* @ltoff(@dtpmod(sym + add)), imm22 */
+#define R_IA64_DTPREL14		0xb1	/* @dtprel(sym + add), imm14 */
+#define R_IA64_DTPREL22		0xb2	/* @dtprel(sym + add), imm22 */
+#define R_IA64_DTPREL64I	0xb3	/* @dtprel(sym + add), imm64 */
+#define R_IA64_DTPREL32MSB	0xb4	/* @dtprel(sym + add), data4 MSB */
+#define R_IA64_DTPREL32LSB	0xb5	/* @dtprel(sym + add), data4 LSB */
+#define R_IA64_DTPREL64MSB	0xb6	/* @dtprel(sym + add), data8 MSB */
+#define R_IA64_DTPREL64LSB	0xb7	/* @dtprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPREL22	0xba	/* @ltoff(@dtprel(s+a)), imm22 */
+
+/* SH specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field.  */
+#define EF_SH_MACH_MASK		0x1f
+#define EF_SH_UNKNOWN		0x0
+#define EF_SH1			0x1
+#define EF_SH2			0x2
+#define EF_SH3			0x3
+#define EF_SH_DSP		0x4
+#define EF_SH3_DSP		0x5
+#define EF_SH4AL_DSP		0x6
+#define EF_SH3E			0x8
+#define EF_SH4			0x9
+#define EF_SH2E			0xb
+#define EF_SH4A			0xc
+#define EF_SH2A			0xd
+#define EF_SH4_NOFPU		0x10
+#define EF_SH4A_NOFPU		0x11
+#define EF_SH4_NOMMU_NOFPU	0x12
+#define EF_SH2A_NOFPU		0x13
+#define EF_SH3_NOMMU		0x14
+#define EF_SH2A_SH4_NOFPU	0x15
+#define EF_SH2A_SH3_NOFPU	0x16
+#define EF_SH2A_SH4		0x17
+#define EF_SH2A_SH3E		0x18
+
+/* SH relocs.  */
+#define	R_SH_NONE		0
+#define	R_SH_DIR32		1
+#define	R_SH_REL32		2
+#define	R_SH_DIR8WPN		3
+#define	R_SH_IND12W		4
+#define	R_SH_DIR8WPL		5
+#define	R_SH_DIR8WPZ		6
+#define	R_SH_DIR8BP		7
+#define	R_SH_DIR8W		8
+#define	R_SH_DIR8L		9
+#define	R_SH_SWITCH16		25
+#define	R_SH_SWITCH32		26
+#define	R_SH_USES		27
+#define	R_SH_COUNT		28
+#define	R_SH_ALIGN		29
+#define	R_SH_CODE		30
+#define	R_SH_DATA		31
+#define	R_SH_LABEL		32
+#define	R_SH_SWITCH8		33
+#define	R_SH_GNU_VTINHERIT	34
+#define	R_SH_GNU_VTENTRY	35
+#define	R_SH_TLS_GD_32		144
+#define	R_SH_TLS_LD_32		145
+#define	R_SH_TLS_LDO_32		146
+#define	R_SH_TLS_IE_32		147
+#define	R_SH_TLS_LE_32		148
+#define	R_SH_TLS_DTPMOD32	149
+#define	R_SH_TLS_DTPOFF32	150
+#define	R_SH_TLS_TPOFF32	151
+#define	R_SH_GOT32		160
+#define	R_SH_PLT32		161
+#define	R_SH_COPY		162
+#define	R_SH_GLOB_DAT		163
+#define	R_SH_JMP_SLOT		164
+#define	R_SH_RELATIVE		165
+#define	R_SH_GOTOFF		166
+#define	R_SH_GOTPC		167
+/* Keep this the last entry.  */
+#define	R_SH_NUM		256
+
+/* S/390 specific definitions.  */
+
+/* Valid values for the e_flags field.  */
+
+#define EF_S390_HIGH_GPRS    0x00000001  /* High GPRs kernel facility needed.  */
+
+/* Additional s390 relocs */
+
+#define R_390_NONE		0	/* No reloc.  */
+#define R_390_8			1	/* Direct 8 bit.  */
+#define R_390_12		2	/* Direct 12 bit.  */
+#define R_390_16		3	/* Direct 16 bit.  */
+#define R_390_32		4	/* Direct 32 bit.  */
+#define R_390_PC32		5	/* PC relative 32 bit.	*/
+#define R_390_GOT12		6	/* 12 bit GOT offset.  */
+#define R_390_GOT32		7	/* 32 bit GOT offset.  */
+#define R_390_PLT32		8	/* 32 bit PC relative PLT address.  */
+#define R_390_COPY		9	/* Copy symbol at runtime.  */
+#define R_390_GLOB_DAT		10	/* Create GOT entry.  */
+#define R_390_JMP_SLOT		11	/* Create PLT entry.  */
+#define R_390_RELATIVE		12	/* Adjust by program base.  */
+#define R_390_GOTOFF32		13	/* 32 bit offset to GOT.	 */
+#define R_390_GOTPC		14	/* 32 bit PC relative offset to GOT.  */
+#define R_390_GOT16		15	/* 16 bit GOT offset.  */
+#define R_390_PC16		16	/* PC relative 16 bit.	*/
+#define R_390_PC16DBL		17	/* PC relative 16 bit shifted by 1.  */
+#define R_390_PLT16DBL		18	/* 16 bit PC rel. PLT shifted by 1.  */
+#define R_390_PC32DBL		19	/* PC relative 32 bit shifted by 1.  */
+#define R_390_PLT32DBL		20	/* 32 bit PC rel. PLT shifted by 1.  */
+#define R_390_GOTPCDBL		21	/* 32 bit PC rel. GOT shifted by 1.  */
+#define R_390_64		22	/* Direct 64 bit.  */
+#define R_390_PC64		23	/* PC relative 64 bit.	*/
+#define R_390_GOT64		24	/* 64 bit GOT offset.  */
+#define R_390_PLT64		25	/* 64 bit PC relative PLT address.  */
+#define R_390_GOTENT		26	/* 32 bit PC rel. to GOT entry >> 1. */
+#define R_390_GOTOFF16		27	/* 16 bit offset to GOT. */
+#define R_390_GOTOFF64		28	/* 64 bit offset to GOT. */
+#define R_390_GOTPLT12		29	/* 12 bit offset to jump slot.	*/
+#define R_390_GOTPLT16		30	/* 16 bit offset to jump slot.	*/
+#define R_390_GOTPLT32		31	/* 32 bit offset to jump slot.	*/
+#define R_390_GOTPLT64		32	/* 64 bit offset to jump slot.	*/
+#define R_390_GOTPLTENT		33	/* 32 bit rel. offset to jump slot.  */
+#define R_390_PLTOFF16		34	/* 16 bit offset from GOT to PLT. */
+#define R_390_PLTOFF32		35	/* 32 bit offset from GOT to PLT. */
+#define R_390_PLTOFF64		36	/* 16 bit offset from GOT to PLT. */
+#define R_390_TLS_LOAD		37	/* Tag for load insn in TLS code.  */
+#define R_390_TLS_GDCALL	38	/* Tag for function call in general
+					   dynamic TLS code. */
+#define R_390_TLS_LDCALL	39	/* Tag for function call in local
+					   dynamic TLS code. */
+#define R_390_TLS_GD32		40	/* Direct 32 bit for general dynamic
+					   thread local data.  */
+#define R_390_TLS_GD64		41	/* Direct 64 bit for general dynamic
+					  thread local data.  */
+#define R_390_TLS_GOTIE12	42	/* 12 bit GOT offset for static TLS
+					   block offset.  */
+#define R_390_TLS_GOTIE32	43	/* 32 bit GOT offset for static TLS
+					   block offset.  */
+#define R_390_TLS_GOTIE64	44	/* 64 bit GOT offset for static TLS
+					   block offset. */
+#define R_390_TLS_LDM32		45	/* Direct 32 bit for local dynamic
+					   thread local data in LE code.  */
+#define R_390_TLS_LDM64		46	/* Direct 64 bit for local dynamic
+					   thread local data in LE code.  */
+#define R_390_TLS_IE32		47	/* 32 bit address of GOT entry for
+					   negated static TLS block offset.  */
+#define R_390_TLS_IE64		48	/* 64 bit address of GOT entry for
+					   negated static TLS block offset.  */
+#define R_390_TLS_IEENT		49	/* 32 bit rel. offset to GOT entry for
+					   negated static TLS block offset.  */
+#define R_390_TLS_LE32		50	/* 32 bit negated offset relative to
+					   static TLS block.  */
+#define R_390_TLS_LE64		51	/* 64 bit negated offset relative to
+					   static TLS block.  */
+#define R_390_TLS_LDO32		52	/* 32 bit offset relative to TLS
+					   block.  */
+#define R_390_TLS_LDO64		53	/* 64 bit offset relative to TLS
+					   block.  */
+#define R_390_TLS_DTPMOD	54	/* ID of module containing symbol.  */
+#define R_390_TLS_DTPOFF	55	/* Offset in TLS block.	 */
+#define R_390_TLS_TPOFF		56	/* Negated offset in static TLS
+					   block.  */
+#define R_390_20		57	/* Direct 20 bit.  */
+#define R_390_GOT20		58	/* 20 bit GOT offset.  */
+#define R_390_GOTPLT20		59	/* 20 bit offset to jump slot.  */
+#define R_390_TLS_GOTIE20	60	/* 20 bit GOT offset for static TLS
+					   block offset.  */
+#define R_390_IRELATIVE         61      /* STT_GNU_IFUNC relocation.  */
+/* Keep this the last entry.  */
+#define R_390_NUM		62
+
+
+/* CRIS relocations.  */
+#define R_CRIS_NONE		0
+#define R_CRIS_8		1
+#define R_CRIS_16		2
+#define R_CRIS_32		3
+#define R_CRIS_8_PCREL		4
+#define R_CRIS_16_PCREL		5
+#define R_CRIS_32_PCREL		6
+#define R_CRIS_GNU_VTINHERIT	7
+#define R_CRIS_GNU_VTENTRY	8
+#define R_CRIS_COPY		9
+#define R_CRIS_GLOB_DAT		10
+#define R_CRIS_JUMP_SLOT	11
+#define R_CRIS_RELATIVE		12
+#define R_CRIS_16_GOT		13
+#define R_CRIS_32_GOT		14
+#define R_CRIS_16_GOTPLT	15
+#define R_CRIS_32_GOTPLT	16
+#define R_CRIS_32_GOTREL	17
+#define R_CRIS_32_PLT_GOTREL	18
+#define R_CRIS_32_PLT_PCREL	19
+
+#define R_CRIS_NUM		20
+
+
+/* AMD x86-64 relocations.  */
+#define R_X86_64_NONE		0	/* No reloc */
+#define R_X86_64_64		1	/* Direct 64 bit  */
+#define R_X86_64_PC32		2	/* PC relative 32 bit signed */
+#define R_X86_64_GOT32		3	/* 32 bit GOT entry */
+#define R_X86_64_PLT32		4	/* 32 bit PLT address */
+#define R_X86_64_COPY		5	/* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT	6	/* Create GOT entry */
+#define R_X86_64_JUMP_SLOT	7	/* Create PLT entry */
+#define R_X86_64_RELATIVE	8	/* Adjust by program base */
+#define R_X86_64_GOTPCREL	9	/* 32 bit signed PC relative
+					   offset to GOT */
+#define R_X86_64_32		10	/* Direct 32 bit zero extended */
+#define R_X86_64_32S		11	/* Direct 32 bit sign extended */
+#define R_X86_64_16		12	/* Direct 16 bit zero extended */
+#define R_X86_64_PC16		13	/* 16 bit sign extended pc relative */
+#define R_X86_64_8		14	/* Direct 8 bit sign extended  */
+#define R_X86_64_PC8		15	/* 8 bit sign extended pc relative */
+#define R_X86_64_DTPMOD64	16	/* ID of module containing symbol */
+#define R_X86_64_DTPOFF64	17	/* Offset in module's TLS block */
+#define R_X86_64_TPOFF64	18	/* Offset in initial TLS block */
+#define R_X86_64_TLSGD		19	/* 32 bit signed PC relative offset
+					   to two GOT entries for GD symbol */
+#define R_X86_64_TLSLD		20	/* 32 bit signed PC relative offset
+					   to two GOT entries for LD symbol */
+#define R_X86_64_DTPOFF32	21	/* Offset in TLS block */
+#define R_X86_64_GOTTPOFF	22	/* 32 bit signed PC relative offset
+					   to GOT entry for IE symbol */
+#define R_X86_64_TPOFF32	23	/* Offset in initial TLS block */
+#define R_X86_64_PC64		24	/* PC relative 64 bit */
+#define R_X86_64_GOTOFF64	25	/* 64 bit offset to GOT */
+#define R_X86_64_GOTPC32	26	/* 32 bit signed pc relative
+					   offset to GOT */
+#define R_X86_64_GOT64		27	/* 64-bit GOT entry offset */
+#define R_X86_64_GOTPCREL64	28	/* 64-bit PC relative offset
+					   to GOT entry */
+#define R_X86_64_GOTPC64	29	/* 64-bit PC relative offset to GOT */
+#define R_X86_64_GOTPLT64	30 	/* like GOT64, says PLT entry needed */
+#define R_X86_64_PLTOFF64	31	/* 64-bit GOT relative offset
+					   to PLT entry */
+#define R_X86_64_SIZE32		32	/* Size of symbol plus 32-bit addend */
+#define R_X86_64_SIZE64		33	/* Size of symbol plus 64-bit addend */
+#define R_X86_64_GOTPC32_TLSDESC 34	/* GOT offset for TLS descriptor.  */
+#define R_X86_64_TLSDESC_CALL   35	/* Marker for call through TLS
+					   descriptor.  */
+#define R_X86_64_TLSDESC        36	/* TLS descriptor.  */
+#define R_X86_64_IRELATIVE	37	/* Adjust indirectly by program base */
+#define R_X86_64_RELATIVE64	38	/* 64-bit adjust by program base */
+					/* 39 Reserved was R_X86_64_PC32_BND */
+					/* 40 Reserved was R_X86_64_PLT32_BND */
+#define R_X86_64_GOTPCRELX	41	/* Load from 32 bit signed pc relative
+					   offset to GOT entry without REX
+					   prefix, relaxable.  */
+#define R_X86_64_REX_GOTPCRELX	42	/* Load from 32 bit signed pc relative
+					   offset to GOT entry with REX prefix,
+					   relaxable.  */
+#define R_X86_64_NUM		43
+
+/* x86-64 sh_type values.  */
+#define SHT_X86_64_UNWIND	0x70000001 /* Unwind information.  */
+
+
+/* AM33 relocations.  */
+#define R_MN10300_NONE		0	/* No reloc.  */
+#define R_MN10300_32		1	/* Direct 32 bit.  */
+#define R_MN10300_16		2	/* Direct 16 bit.  */
+#define R_MN10300_8		3	/* Direct 8 bit.  */
+#define R_MN10300_PCREL32	4	/* PC-relative 32-bit.  */
+#define R_MN10300_PCREL16	5	/* PC-relative 16-bit signed.  */
+#define R_MN10300_PCREL8	6	/* PC-relative 8-bit signed.  */
+#define R_MN10300_GNU_VTINHERIT	7	/* Ancient C++ vtable garbage... */
+#define R_MN10300_GNU_VTENTRY	8	/* ... collection annotation.  */
+#define R_MN10300_24		9	/* Direct 24 bit.  */
+#define R_MN10300_GOTPC32	10	/* 32-bit PCrel offset to GOT.  */
+#define R_MN10300_GOTPC16	11	/* 16-bit PCrel offset to GOT.  */
+#define R_MN10300_GOTOFF32	12	/* 32-bit offset from GOT.  */
+#define R_MN10300_GOTOFF24	13	/* 24-bit offset from GOT.  */
+#define R_MN10300_GOTOFF16	14	/* 16-bit offset from GOT.  */
+#define R_MN10300_PLT32		15	/* 32-bit PCrel to PLT entry.  */
+#define R_MN10300_PLT16		16	/* 16-bit PCrel to PLT entry.  */
+#define R_MN10300_GOT32		17	/* 32-bit offset to GOT entry.  */
+#define R_MN10300_GOT24		18	/* 24-bit offset to GOT entry.  */
+#define R_MN10300_GOT16		19	/* 16-bit offset to GOT entry.  */
+#define R_MN10300_COPY		20	/* Copy symbol at runtime.  */
+#define R_MN10300_GLOB_DAT	21	/* Create GOT entry.  */
+#define R_MN10300_JMP_SLOT	22	/* Create PLT entry.  */
+#define R_MN10300_RELATIVE	23	/* Adjust by program base.  */
+#define R_MN10300_TLS_GD	24	/* 32-bit offset for global dynamic.  */
+#define R_MN10300_TLS_LD	25	/* 32-bit offset for local dynamic.  */
+#define R_MN10300_TLS_LDO	26	/* Module-relative offset.  */
+#define R_MN10300_TLS_GOTIE	27	/* GOT offset for static TLS block
+					   offset.  */
+#define R_MN10300_TLS_IE	28	/* GOT address for static TLS block
+					   offset.  */
+#define R_MN10300_TLS_LE	29	/* Offset relative to static TLS
+					   block.  */
+#define R_MN10300_TLS_DTPMOD	30	/* ID of module containing symbol.  */
+#define R_MN10300_TLS_DTPOFF	31	/* Offset in module TLS block.  */
+#define R_MN10300_TLS_TPOFF	32	/* Offset in static TLS block.  */
+#define R_MN10300_SYM_DIFF	33	/* Adjustment for next reloc as needed
+					   by linker relaxation.  */
+#define R_MN10300_ALIGN		34	/* Alignment requirement for linker
+					   relaxation.  */
+#define R_MN10300_NUM		35
+
+
+/* M32R relocs.  */
+#define R_M32R_NONE		0	/* No reloc. */
+#define R_M32R_16		1	/* Direct 16 bit. */
+#define R_M32R_32		2	/* Direct 32 bit. */
+#define R_M32R_24		3	/* Direct 24 bit. */
+#define R_M32R_10_PCREL		4	/* PC relative 10 bit shifted. */
+#define R_M32R_18_PCREL		5	/* PC relative 18 bit shifted. */
+#define R_M32R_26_PCREL		6	/* PC relative 26 bit shifted. */
+#define R_M32R_HI16_ULO		7	/* High 16 bit with unsigned low. */
+#define R_M32R_HI16_SLO		8	/* High 16 bit with signed low. */
+#define R_M32R_LO16		9	/* Low 16 bit. */
+#define R_M32R_SDA16		10	/* 16 bit offset in SDA. */
+#define R_M32R_GNU_VTINHERIT	11
+#define R_M32R_GNU_VTENTRY	12
+/* M32R relocs use SHT_RELA.  */
+#define R_M32R_16_RELA		33	/* Direct 16 bit. */
+#define R_M32R_32_RELA		34	/* Direct 32 bit. */
+#define R_M32R_24_RELA		35	/* Direct 24 bit. */
+#define R_M32R_10_PCREL_RELA	36	/* PC relative 10 bit shifted. */
+#define R_M32R_18_PCREL_RELA	37	/* PC relative 18 bit shifted. */
+#define R_M32R_26_PCREL_RELA	38	/* PC relative 26 bit shifted. */
+#define R_M32R_HI16_ULO_RELA	39	/* High 16 bit with unsigned low */
+#define R_M32R_HI16_SLO_RELA	40	/* High 16 bit with signed low */
+#define R_M32R_LO16_RELA	41	/* Low 16 bit */
+#define R_M32R_SDA16_RELA	42	/* 16 bit offset in SDA */
+#define R_M32R_RELA_GNU_VTINHERIT	43
+#define R_M32R_RELA_GNU_VTENTRY	44
+#define R_M32R_REL32		45	/* PC relative 32 bit.  */
+
+#define R_M32R_GOT24		48	/* 24 bit GOT entry */
+#define R_M32R_26_PLTREL	49	/* 26 bit PC relative to PLT shifted */
+#define R_M32R_COPY		50	/* Copy symbol at runtime */
+#define R_M32R_GLOB_DAT		51	/* Create GOT entry */
+#define R_M32R_JMP_SLOT		52	/* Create PLT entry */
+#define R_M32R_RELATIVE		53	/* Adjust by program base */
+#define R_M32R_GOTOFF		54	/* 24 bit offset to GOT */
+#define R_M32R_GOTPC24		55	/* 24 bit PC relative offset to GOT */
+#define R_M32R_GOT16_HI_ULO	56	/* High 16 bit GOT entry with unsigned
+					   low */
+#define R_M32R_GOT16_HI_SLO	57	/* High 16 bit GOT entry with signed
+					   low */
+#define R_M32R_GOT16_LO		58	/* Low 16 bit GOT entry */
+#define R_M32R_GOTPC_HI_ULO	59	/* High 16 bit PC relative offset to
+					   GOT with unsigned low */
+#define R_M32R_GOTPC_HI_SLO	60	/* High 16 bit PC relative offset to
+					   GOT with signed low */
+#define R_M32R_GOTPC_LO		61	/* Low 16 bit PC relative offset to
+					   GOT */
+#define R_M32R_GOTOFF_HI_ULO	62	/* High 16 bit offset to GOT
+					   with unsigned low */
+#define R_M32R_GOTOFF_HI_SLO	63	/* High 16 bit offset to GOT
+					   with signed low */
+#define R_M32R_GOTOFF_LO	64	/* Low 16 bit offset to GOT */
+#define R_M32R_NUM		256	/* Keep this the last entry. */
+
+/* MicroBlaze relocations */
+#define R_MICROBLAZE_NONE		0	/* No reloc. */
+#define R_MICROBLAZE_32 		1	/* Direct 32 bit. */
+#define R_MICROBLAZE_32_PCREL		2	/* PC relative 32 bit. */
+#define R_MICROBLAZE_64_PCREL		3	/* PC relative 64 bit. */
+#define R_MICROBLAZE_32_PCREL_LO	4	/* Low 16 bits of PCREL32. */
+#define R_MICROBLAZE_64 		5	/* Direct 64 bit. */
+#define R_MICROBLAZE_32_LO		6	/* Low 16 bit. */
+#define R_MICROBLAZE_SRO32		7	/* Read-only small data area. */
+#define R_MICROBLAZE_SRW32		8	/* Read-write small data area. */
+#define R_MICROBLAZE_64_NONE		9	/* No reloc. */
+#define R_MICROBLAZE_32_SYM_OP_SYM	10	/* Symbol Op Symbol relocation. */
+#define R_MICROBLAZE_GNU_VTINHERIT	11	/* GNU C++ vtable hierarchy. */
+#define R_MICROBLAZE_GNU_VTENTRY	12	/* GNU C++ vtable member usage. */
+#define R_MICROBLAZE_GOTPC_64		13	/* PC-relative GOT offset.  */
+#define R_MICROBLAZE_GOT_64		14	/* GOT entry offset.  */
+#define R_MICROBLAZE_PLT_64		15	/* PLT offset (PC-relative).  */
+#define R_MICROBLAZE_REL		16	/* Adjust by program base.  */
+#define R_MICROBLAZE_JUMP_SLOT		17	/* Create PLT entry.  */
+#define R_MICROBLAZE_GLOB_DAT		18	/* Create GOT entry.  */
+#define R_MICROBLAZE_GOTOFF_64		19	/* 64 bit offset to GOT. */
+#define R_MICROBLAZE_GOTOFF_32		20	/* 32 bit offset to GOT. */
+#define R_MICROBLAZE_COPY		21	/* Runtime copy.  */
+#define R_MICROBLAZE_TLS		22	/* TLS Reloc. */
+#define R_MICROBLAZE_TLSGD		23	/* TLS General Dynamic. */
+#define R_MICROBLAZE_TLSLD		24	/* TLS Local Dynamic. */
+#define R_MICROBLAZE_TLSDTPMOD32	25	/* TLS Module ID. */
+#define R_MICROBLAZE_TLSDTPREL32	26	/* TLS Offset Within TLS Block. */
+#define R_MICROBLAZE_TLSDTPREL64	27	/* TLS Offset Within TLS Block. */
+#define R_MICROBLAZE_TLSGOTTPREL32	28	/* TLS Offset From Thread Pointer. */
+#define R_MICROBLAZE_TLSTPREL32 	29	/* TLS Offset From Thread Pointer. */
+
+/* Legal values for d_tag (dynamic entry type).  */
+#define DT_NIOS2_GP             0x70000002 /* Address of _gp.  */
+
+/* Nios II relocations.  */
+#define R_NIOS2_NONE		0	/* No reloc.  */
+#define R_NIOS2_S16		1	/* Direct signed 16 bit.  */
+#define R_NIOS2_U16		2	/* Direct unsigned 16 bit.  */
+#define R_NIOS2_PCREL16		3	/* PC relative 16 bit.  */
+#define R_NIOS2_CALL26		4	/* Direct call.  */
+#define R_NIOS2_IMM5		5	/* 5 bit constant expression.  */
+#define R_NIOS2_CACHE_OPX	6	/* 5 bit expression, shift 22.  */
+#define R_NIOS2_IMM6		7	/* 6 bit constant expression.  */
+#define R_NIOS2_IMM8		8	/* 8 bit constant expression.  */
+#define R_NIOS2_HI16		9	/* High 16 bit.  */
+#define R_NIOS2_LO16		10	/* Low 16 bit.  */
+#define R_NIOS2_HIADJ16		11	/* High 16 bit, adjusted.  */
+#define R_NIOS2_BFD_RELOC_32	12	/* 32 bit symbol value + addend.  */
+#define R_NIOS2_BFD_RELOC_16	13	/* 16 bit symbol value + addend.  */
+#define R_NIOS2_BFD_RELOC_8	14	/* 8 bit symbol value + addend.  */
+#define R_NIOS2_GPREL		15	/* 16 bit GP pointer offset.  */
+#define R_NIOS2_GNU_VTINHERIT	16	/* GNU C++ vtable hierarchy.  */
+#define R_NIOS2_GNU_VTENTRY	17	/* GNU C++ vtable member usage.  */
+#define R_NIOS2_UJMP		18	/* Unconditional branch.  */
+#define R_NIOS2_CJMP		19	/* Conditional branch.  */
+#define R_NIOS2_CALLR		20	/* Indirect call through register.  */
+#define R_NIOS2_ALIGN		21	/* Alignment requirement for
+					   linker relaxation.  */
+#define R_NIOS2_GOT16		22	/* 16 bit GOT entry.  */
+#define R_NIOS2_CALL16		23	/* 16 bit GOT entry for function.  */
+#define R_NIOS2_GOTOFF_LO	24	/* %lo of offset to GOT pointer.  */
+#define R_NIOS2_GOTOFF_HA	25	/* %hiadj of offset to GOT pointer.  */
+#define R_NIOS2_PCREL_LO	26	/* %lo of PC relative offset.  */
+#define R_NIOS2_PCREL_HA	27	/* %hiadj of PC relative offset.  */
+#define R_NIOS2_TLS_GD16	28	/* 16 bit GOT offset for TLS GD.  */
+#define R_NIOS2_TLS_LDM16	29	/* 16 bit GOT offset for TLS LDM.  */
+#define R_NIOS2_TLS_LDO16	30	/* 16 bit module relative offset.  */
+#define R_NIOS2_TLS_IE16	31	/* 16 bit GOT offset for TLS IE.  */
+#define R_NIOS2_TLS_LE16	32	/* 16 bit LE TP-relative offset.  */
+#define R_NIOS2_TLS_DTPMOD	33	/* Module number.  */
+#define R_NIOS2_TLS_DTPREL	34	/* Module-relative offset.  */
+#define R_NIOS2_TLS_TPREL	35	/* TP-relative offset.  */
+#define R_NIOS2_COPY		36	/* Copy symbol at runtime.  */
+#define R_NIOS2_GLOB_DAT	37	/* Create GOT entry.  */
+#define R_NIOS2_JUMP_SLOT	38	/* Create PLT entry.  */
+#define R_NIOS2_RELATIVE	39	/* Adjust by program base.  */
+#define R_NIOS2_GOTOFF		40	/* 16 bit offset to GOT pointer.  */
+#define R_NIOS2_CALL26_NOAT	41	/* Direct call in .noat section.  */
+#define R_NIOS2_GOT_LO		42	/* %lo() of GOT entry.  */
+#define R_NIOS2_GOT_HA		43	/* %hiadj() of GOT entry.  */
+#define R_NIOS2_CALL_LO		44	/* %lo() of function GOT entry.  */
+#define R_NIOS2_CALL_HA		45	/* %hiadj() of function GOT entry.  */
+
+/* TILEPro relocations.  */
+#define R_TILEPRO_NONE		0	/* No reloc */
+#define R_TILEPRO_32		1	/* Direct 32 bit */
+#define R_TILEPRO_16		2	/* Direct 16 bit */
+#define R_TILEPRO_8		3	/* Direct 8 bit */
+#define R_TILEPRO_32_PCREL	4	/* PC relative 32 bit */
+#define R_TILEPRO_16_PCREL	5	/* PC relative 16 bit */
+#define R_TILEPRO_8_PCREL	6	/* PC relative 8 bit */
+#define R_TILEPRO_LO16		7	/* Low 16 bit */
+#define R_TILEPRO_HI16		8	/* High 16 bit */
+#define R_TILEPRO_HA16		9	/* High 16 bit, adjusted */
+#define R_TILEPRO_COPY		10	/* Copy relocation */
+#define R_TILEPRO_GLOB_DAT	11	/* Create GOT entry */
+#define R_TILEPRO_JMP_SLOT	12	/* Create PLT entry */
+#define R_TILEPRO_RELATIVE	13	/* Adjust by program base */
+#define R_TILEPRO_BROFF_X1	14	/* X1 pipe branch offset */
+#define R_TILEPRO_JOFFLONG_X1	15	/* X1 pipe jump offset */
+#define R_TILEPRO_JOFFLONG_X1_PLT 16	/* X1 pipe jump offset to PLT */
+#define R_TILEPRO_IMM8_X0	17	/* X0 pipe 8-bit */
+#define R_TILEPRO_IMM8_Y0	18	/* Y0 pipe 8-bit */
+#define R_TILEPRO_IMM8_X1	19	/* X1 pipe 8-bit */
+#define R_TILEPRO_IMM8_Y1	20	/* Y1 pipe 8-bit */
+#define R_TILEPRO_MT_IMM15_X1	21	/* X1 pipe mtspr */
+#define R_TILEPRO_MF_IMM15_X1	22	/* X1 pipe mfspr */
+#define R_TILEPRO_IMM16_X0	23	/* X0 pipe 16-bit */
+#define R_TILEPRO_IMM16_X1	24	/* X1 pipe 16-bit */
+#define R_TILEPRO_IMM16_X0_LO	25	/* X0 pipe low 16-bit */
+#define R_TILEPRO_IMM16_X1_LO	26	/* X1 pipe low 16-bit */
+#define R_TILEPRO_IMM16_X0_HI	27	/* X0 pipe high 16-bit */
+#define R_TILEPRO_IMM16_X1_HI	28	/* X1 pipe high 16-bit */
+#define R_TILEPRO_IMM16_X0_HA	29	/* X0 pipe high 16-bit, adjusted */
+#define R_TILEPRO_IMM16_X1_HA	30	/* X1 pipe high 16-bit, adjusted */
+#define R_TILEPRO_IMM16_X0_PCREL 31	/* X0 pipe PC relative 16 bit */
+#define R_TILEPRO_IMM16_X1_PCREL 32	/* X1 pipe PC relative 16 bit */
+#define R_TILEPRO_IMM16_X0_LO_PCREL 33	/* X0 pipe PC relative low 16 bit */
+#define R_TILEPRO_IMM16_X1_LO_PCREL 34	/* X1 pipe PC relative low 16 bit */
+#define R_TILEPRO_IMM16_X0_HI_PCREL 35	/* X0 pipe PC relative high 16 bit */
+#define R_TILEPRO_IMM16_X1_HI_PCREL 36	/* X1 pipe PC relative high 16 bit */
+#define R_TILEPRO_IMM16_X0_HA_PCREL 37	/* X0 pipe PC relative ha() 16 bit */
+#define R_TILEPRO_IMM16_X1_HA_PCREL 38	/* X1 pipe PC relative ha() 16 bit */
+#define R_TILEPRO_IMM16_X0_GOT	39	/* X0 pipe 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT	40	/* X1 pipe 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X0_GOT_LO 41	/* X0 pipe low 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT_LO 42	/* X1 pipe low 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X0_GOT_HI 43	/* X0 pipe high 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT_HI 44	/* X1 pipe high 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X0_GOT_HA 45	/* X0 pipe ha() 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT_HA 46	/* X1 pipe ha() 16-bit GOT offset */
+#define R_TILEPRO_MMSTART_X0	47	/* X0 pipe mm "start" */
+#define R_TILEPRO_MMEND_X0	48	/* X0 pipe mm "end" */
+#define R_TILEPRO_MMSTART_X1	49	/* X1 pipe mm "start" */
+#define R_TILEPRO_MMEND_X1	50	/* X1 pipe mm "end" */
+#define R_TILEPRO_SHAMT_X0	51	/* X0 pipe shift amount */
+#define R_TILEPRO_SHAMT_X1	52	/* X1 pipe shift amount */
+#define R_TILEPRO_SHAMT_Y0	53	/* Y0 pipe shift amount */
+#define R_TILEPRO_SHAMT_Y1	54	/* Y1 pipe shift amount */
+#define R_TILEPRO_DEST_IMM8_X1	55	/* X1 pipe destination 8-bit */
+/* Relocs 56-59 are currently not defined.  */
+#define R_TILEPRO_TLS_GD_CALL	60	/* "jal" for TLS GD */
+#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61	/* X0 pipe "addi" for TLS GD */
+#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62	/* X1 pipe "addi" for TLS GD */
+#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63	/* Y0 pipe "addi" for TLS GD */
+#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64	/* Y1 pipe "addi" for TLS GD */
+#define R_TILEPRO_TLS_IE_LOAD	65	/* "lw_tls" for TLS IE */
+#define R_TILEPRO_IMM16_X0_TLS_GD 66	/* X0 pipe 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD 67	/* X1 pipe 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68	/* X0 pipe low 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69	/* X1 pipe low 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70	/* X0 pipe high 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71	/* X1 pipe high 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72	/* X0 pipe ha() 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73	/* X1 pipe ha() 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE 74	/* X0 pipe 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE 75	/* X1 pipe 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76	/* X0 pipe low 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77	/* X1 pipe low 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78	/* X0 pipe high 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79	/* X1 pipe high 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80	/* X0 pipe ha() 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81	/* X1 pipe ha() 16-bit TLS IE offset */
+#define R_TILEPRO_TLS_DTPMOD32	82	/* ID of module containing symbol */
+#define R_TILEPRO_TLS_DTPOFF32	83	/* Offset in TLS block */
+#define R_TILEPRO_TLS_TPOFF32	84	/* Offset in static TLS block */
+#define R_TILEPRO_IMM16_X0_TLS_LE 85	/* X0 pipe 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE 86	/* X1 pipe 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87	/* X0 pipe low 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88	/* X1 pipe low 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89	/* X0 pipe high 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90	/* X1 pipe high 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91	/* X0 pipe ha() 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92	/* X1 pipe ha() 16-bit TLS LE offset */
+
+#define R_TILEPRO_GNU_VTINHERIT	128	/* GNU C++ vtable hierarchy */
+#define R_TILEPRO_GNU_VTENTRY	129	/* GNU C++ vtable member usage */
+
+#define R_TILEPRO_NUM		130
+
+
+/* TILE-Gx relocations.  */
+#define R_TILEGX_NONE		0	/* No reloc */
+#define R_TILEGX_64		1	/* Direct 64 bit */
+#define R_TILEGX_32		2	/* Direct 32 bit */
+#define R_TILEGX_16		3	/* Direct 16 bit */
+#define R_TILEGX_8		4	/* Direct 8 bit */
+#define R_TILEGX_64_PCREL	5	/* PC relative 64 bit */
+#define R_TILEGX_32_PCREL	6	/* PC relative 32 bit */
+#define R_TILEGX_16_PCREL	7	/* PC relative 16 bit */
+#define R_TILEGX_8_PCREL	8	/* PC relative 8 bit */
+#define R_TILEGX_HW0		9	/* hword 0 16-bit */
+#define R_TILEGX_HW1		10	/* hword 1 16-bit */
+#define R_TILEGX_HW2		11	/* hword 2 16-bit */
+#define R_TILEGX_HW3		12	/* hword 3 16-bit */
+#define R_TILEGX_HW0_LAST	13	/* last hword 0 16-bit */
+#define R_TILEGX_HW1_LAST	14	/* last hword 1 16-bit */
+#define R_TILEGX_HW2_LAST	15	/* last hword 2 16-bit */
+#define R_TILEGX_COPY		16	/* Copy relocation */
+#define R_TILEGX_GLOB_DAT	17	/* Create GOT entry */
+#define R_TILEGX_JMP_SLOT	18	/* Create PLT entry */
+#define R_TILEGX_RELATIVE	19	/* Adjust by program base */
+#define R_TILEGX_BROFF_X1	20	/* X1 pipe branch offset */
+#define R_TILEGX_JUMPOFF_X1	21	/* X1 pipe jump offset */
+#define R_TILEGX_JUMPOFF_X1_PLT	22	/* X1 pipe jump offset to PLT */
+#define R_TILEGX_IMM8_X0	23	/* X0 pipe 8-bit */
+#define R_TILEGX_IMM8_Y0	24	/* Y0 pipe 8-bit */
+#define R_TILEGX_IMM8_X1	25	/* X1 pipe 8-bit */
+#define R_TILEGX_IMM8_Y1	26	/* Y1 pipe 8-bit */
+#define R_TILEGX_DEST_IMM8_X1	27	/* X1 pipe destination 8-bit */
+#define R_TILEGX_MT_IMM14_X1	28	/* X1 pipe mtspr */
+#define R_TILEGX_MF_IMM14_X1	29	/* X1 pipe mfspr */
+#define R_TILEGX_MMSTART_X0	30	/* X0 pipe mm "start" */
+#define R_TILEGX_MMEND_X0	31	/* X0 pipe mm "end" */
+#define R_TILEGX_SHAMT_X0	32	/* X0 pipe shift amount */
+#define R_TILEGX_SHAMT_X1	33	/* X1 pipe shift amount */
+#define R_TILEGX_SHAMT_Y0	34	/* Y0 pipe shift amount */
+#define R_TILEGX_SHAMT_Y1	35	/* Y1 pipe shift amount */
+#define R_TILEGX_IMM16_X0_HW0	36	/* X0 pipe hword 0 */
+#define R_TILEGX_IMM16_X1_HW0	37	/* X1 pipe hword 0 */
+#define R_TILEGX_IMM16_X0_HW1	38	/* X0 pipe hword 1 */
+#define R_TILEGX_IMM16_X1_HW1	39	/* X1 pipe hword 1 */
+#define R_TILEGX_IMM16_X0_HW2	40	/* X0 pipe hword 2 */
+#define R_TILEGX_IMM16_X1_HW2	41	/* X1 pipe hword 2 */
+#define R_TILEGX_IMM16_X0_HW3	42	/* X0 pipe hword 3 */
+#define R_TILEGX_IMM16_X1_HW3	43	/* X1 pipe hword 3 */
+#define R_TILEGX_IMM16_X0_HW0_LAST 44	/* X0 pipe last hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_LAST 45	/* X1 pipe last hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_LAST 46	/* X0 pipe last hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_LAST 47	/* X1 pipe last hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_LAST 48	/* X0 pipe last hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_LAST 49	/* X1 pipe last hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_PCREL 50	/* X0 pipe PC relative hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_PCREL 51	/* X1 pipe PC relative hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_PCREL 52	/* X0 pipe PC relative hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_PCREL 53	/* X1 pipe PC relative hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_PCREL 54	/* X0 pipe PC relative hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_PCREL 55	/* X1 pipe PC relative hword 2 */
+#define R_TILEGX_IMM16_X0_HW3_PCREL 56	/* X0 pipe PC relative hword 3 */
+#define R_TILEGX_IMM16_X1_HW3_PCREL 57	/* X1 pipe PC relative hword 3 */
+#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_GOT 64	/* X0 pipe hword 0 GOT offset */
+#define R_TILEGX_IMM16_X1_HW0_GOT 65	/* X1 pipe hword 0 GOT offset */
+#define R_TILEGX_IMM16_X0_HW0_PLT_PCREL 66 /* X0 pipe PC-rel PLT hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_PLT_PCREL 67 /* X1 pipe PC-rel PLT hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_PLT_PCREL 68 /* X0 pipe PC-rel PLT hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_PLT_PCREL 69 /* X1 pipe PC-rel PLT hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_PLT_PCREL 70 /* X0 pipe PC-rel PLT hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_PLT_PCREL 71 /* X1 pipe PC-rel PLT hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */
+#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */
+#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */
+#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */
+#define R_TILEGX_IMM16_X0_HW3_PLT_PCREL 76 /* X0 pipe PC-rel PLT hword 3 */
+#define R_TILEGX_IMM16_X1_HW3_PLT_PCREL 77 /* X1 pipe PC-rel PLT hword 3 */
+#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78	/* X0 pipe hword 0 TLS GD offset */
+#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79	/* X1 pipe hword 0 TLS GD offset */
+#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80	/* X0 pipe hword 0 TLS LE offset */
+#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81	/* X1 pipe hword 0 TLS LE offset */
+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */
+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */
+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */
+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */
+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */
+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */
+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */
+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */
+/* Relocs 90-91 are currently not defined.  */
+#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92	/* X0 pipe hword 0 TLS IE offset */
+#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93	/* X1 pipe hword 0 TLS IE offset */
+#define R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL 94 /* X0 pipe PC-rel PLT last hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL 95 /* X1 pipe PC-rel PLT last hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL 96 /* X0 pipe PC-rel PLT last hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL 97 /* X1 pipe PC-rel PLT last hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL 98 /* X0 pipe PC-rel PLT last hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL 99 /* X1 pipe PC-rel PLT last hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */
+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */
+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */
+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */
+/* Relocs 104-105 are currently not defined.  */
+#define R_TILEGX_TLS_DTPMOD64	106	/* 64-bit ID of symbol's module */
+#define R_TILEGX_TLS_DTPOFF64	107	/* 64-bit offset in TLS block */
+#define R_TILEGX_TLS_TPOFF64	108	/* 64-bit offset in static TLS block */
+#define R_TILEGX_TLS_DTPMOD32	109	/* 32-bit ID of symbol's module */
+#define R_TILEGX_TLS_DTPOFF32	110	/* 32-bit offset in TLS block */
+#define R_TILEGX_TLS_TPOFF32	111	/* 32-bit offset in static TLS block */
+#define R_TILEGX_TLS_GD_CALL	112	/* "jal" for TLS GD */
+#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113	/* X0 pipe "addi" for TLS GD */
+#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114	/* X1 pipe "addi" for TLS GD */
+#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115	/* Y0 pipe "addi" for TLS GD */
+#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116	/* Y1 pipe "addi" for TLS GD */
+#define R_TILEGX_TLS_IE_LOAD	117	/* "ld_tls" for TLS IE */
+#define R_TILEGX_IMM8_X0_TLS_ADD 118	/* X0 pipe "addi" for TLS GD/IE */
+#define R_TILEGX_IMM8_X1_TLS_ADD 119	/* X1 pipe "addi" for TLS GD/IE */
+#define R_TILEGX_IMM8_Y0_TLS_ADD 120	/* Y0 pipe "addi" for TLS GD/IE */
+#define R_TILEGX_IMM8_Y1_TLS_ADD 121	/* Y1 pipe "addi" for TLS GD/IE */
+
+#define R_TILEGX_GNU_VTINHERIT	128	/* GNU C++ vtable hierarchy */
+#define R_TILEGX_GNU_VTENTRY	129	/* GNU C++ vtable member usage */
+
+#define R_TILEGX_NUM		130
+
+/* RISC-V ELF Flags */
+#define EF_RISCV_RVC 			0x0001
+#define EF_RISCV_FLOAT_ABI 		0x0006
+#define EF_RISCV_FLOAT_ABI_SOFT 	0x0000
+#define EF_RISCV_FLOAT_ABI_SINGLE 	0x0002
+#define EF_RISCV_FLOAT_ABI_DOUBLE 	0x0004
+#define EF_RISCV_FLOAT_ABI_QUAD 	0x0006
+
+/* RISC-V relocations.  */
+#define R_RISCV_NONE		 0
+#define R_RISCV_32		 1
+#define R_RISCV_64		 2
+#define R_RISCV_RELATIVE	 3
+#define R_RISCV_COPY		 4
+#define R_RISCV_JUMP_SLOT	 5
+#define R_RISCV_TLS_DTPMOD32	 6
+#define R_RISCV_TLS_DTPMOD64	 7
+#define R_RISCV_TLS_DTPREL32	 8
+#define R_RISCV_TLS_DTPREL64	 9
+#define R_RISCV_TLS_TPREL32	10
+#define R_RISCV_TLS_TPREL64	11
+#define R_RISCV_BRANCH		16
+#define R_RISCV_JAL		17
+#define R_RISCV_CALL		18
+#define R_RISCV_CALL_PLT	19
+#define R_RISCV_GOT_HI20	20
+#define R_RISCV_TLS_GOT_HI20	21
+#define R_RISCV_TLS_GD_HI20	22
+#define R_RISCV_PCREL_HI20	23
+#define R_RISCV_PCREL_LO12_I	24
+#define R_RISCV_PCREL_LO12_S	25
+#define R_RISCV_HI20		26
+#define R_RISCV_LO12_I		27
+#define R_RISCV_LO12_S		28
+#define R_RISCV_TPREL_HI20	29
+#define R_RISCV_TPREL_LO12_I	30
+#define R_RISCV_TPREL_LO12_S	31
+#define R_RISCV_TPREL_ADD	32
+#define R_RISCV_ADD8		33
+#define R_RISCV_ADD16		34
+#define R_RISCV_ADD32		35
+#define R_RISCV_ADD64		36
+#define R_RISCV_SUB8		37
+#define R_RISCV_SUB16		38
+#define R_RISCV_SUB32		39
+#define R_RISCV_SUB64		40
+#define R_RISCV_GNU_VTINHERIT	41
+#define R_RISCV_GNU_VTENTRY	42
+#define R_RISCV_ALIGN		43
+#define R_RISCV_RVC_BRANCH	44
+#define R_RISCV_RVC_JUMP	45
+#define R_RISCV_RVC_LUI		46
+#define R_RISCV_GPREL_I		47
+#define R_RISCV_GPREL_S		48
+#define R_RISCV_TPREL_I		49
+#define R_RISCV_TPREL_S		50
+#define R_RISCV_RELAX		51
+#define R_RISCV_SUB6		52
+#define R_RISCV_SET6		53
+#define R_RISCV_SET8		54
+#define R_RISCV_SET16		55
+#define R_RISCV_SET32		56
+#define R_RISCV_32_PCREL	57
+
+#define R_RISCV_NUM		58
+
+/* BPF specific declarations.  */
+
+#define R_BPF_NONE		0	/* No reloc */
+#define R_BPF_64_64		1
+#define R_BPF_64_32		10
+
+/* Imagination Meta specific relocations. */
+
+#define R_METAG_HIADDR16	0
+#define R_METAG_LOADDR16	1
+#define R_METAG_ADDR32		2	/* 32bit absolute address */
+#define R_METAG_NONE		3	/* No reloc */
+#define R_METAG_RELBRANCH	4
+#define R_METAG_GETSETOFF	5
+
+/* Backward compatability */
+#define R_METAG_REG32OP1	6
+#define R_METAG_REG32OP2	7
+#define R_METAG_REG32OP3	8
+#define R_METAG_REG16OP1	9
+#define R_METAG_REG16OP2	10
+#define R_METAG_REG16OP3	11
+#define R_METAG_REG32OP4	12
+
+#define R_METAG_HIOG		13
+#define R_METAG_LOOG		14
+
+#define R_METAG_REL8		15
+#define R_METAG_REL16		16
+
+/* GNU */
+#define R_METAG_GNU_VTINHERIT	30
+#define R_METAG_GNU_VTENTRY	31
+
+/* PIC relocations */
+#define R_METAG_HI16_GOTOFF	32
+#define R_METAG_LO16_GOTOFF	33
+#define R_METAG_GETSET_GOTOFF	34
+#define R_METAG_GETSET_GOT	35
+#define R_METAG_HI16_GOTPC	36
+#define R_METAG_LO16_GOTPC	37
+#define R_METAG_HI16_PLT	38
+#define R_METAG_LO16_PLT	39
+#define R_METAG_RELBRANCH_PLT	40
+#define R_METAG_GOTOFF		41
+#define R_METAG_PLT		42
+#define R_METAG_COPY		43
+#define R_METAG_JMP_SLOT	44
+#define R_METAG_RELATIVE	45
+#define R_METAG_GLOB_DAT	46
+
+/* TLS relocations */
+#define R_METAG_TLS_GD		47
+#define R_METAG_TLS_LDM		48
+#define R_METAG_TLS_LDO_HI16	49
+#define R_METAG_TLS_LDO_LO16	50
+#define R_METAG_TLS_LDO		51
+#define R_METAG_TLS_IE		52
+#define R_METAG_TLS_IENONPIC	53
+#define R_METAG_TLS_IENONPIC_HI16 54
+#define R_METAG_TLS_IENONPIC_LO16 55
+#define R_METAG_TLS_TPOFF	56
+#define R_METAG_TLS_DTPMOD	57
+#define R_METAG_TLS_DTPOFF	58
+#define R_METAG_TLS_LE		59
+#define R_METAG_TLS_LE_HI16	60
+#define R_METAG_TLS_LE_LO16	61
+
+/* NDS32 relocations.  */
+#define R_NDS32_NONE		0
+#define R_NDS32_32_RELA 	20
+#define R_NDS32_COPY		39
+#define R_NDS32_GLOB_DAT	40
+#define R_NDS32_JMP_SLOT	41
+#define R_NDS32_RELATIVE	42
+#define R_NDS32_TLS_TPOFF	102
+#define R_NDS32_TLS_DESC	119
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif	/* elf.h */
diff --git a/third_party/crashpad/crashpad/third_party/xnu/APPLE_LICENSE b/third_party/crashpad/crashpad/third_party/xnu/APPLE_LICENSE
new file mode 100644
index 0000000..fe81a60
--- /dev/null
+++ b/third_party/crashpad/crashpad/third_party/xnu/APPLE_LICENSE
@@ -0,0 +1,367 @@
+APPLE PUBLIC SOURCE LICENSE
+Version 2.0 - August 6, 2003
+
+Please read this License carefully before downloading this software.
+By downloading or using this software, you are agreeing to be bound by
+the terms of this License. If you do not or cannot agree to the terms
+of this License, please do not download or use the software.
+
+1. General; Definitions. This License applies to any program or other
+work which Apple Computer, Inc. ("Apple") makes publicly available and
+which contains a notice placed by Apple identifying such program or
+work as "Original Code" and stating that it is subject to the terms of
+this Apple Public Source License version 2.0 ("License"). As used in
+this License:
+
+1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is
+the grantor of rights, (i) claims of patents that are now or hereafter
+acquired, owned by or assigned to Apple and (ii) that cover subject
+matter contained in the Original Code, but only to the extent
+necessary to use, reproduce and/or distribute the Original Code
+without infringement; and (b) in the case where You are the grantor of
+rights, (i) claims of patents that are now or hereafter acquired,
+owned by or assigned to You and (ii) that cover subject matter in Your
+Modifications, taken alone or in combination with Original Code.
+
+1.2 "Contributor" means any person or entity that creates or
+contributes to the creation of Modifications.
+
+1.3 "Covered Code" means the Original Code, Modifications, the
+combination of Original Code and any Modifications, and/or any
+respective portions thereof.
+
+1.4 "Externally Deploy" means: (a) to sublicense, distribute or
+otherwise make Covered Code available, directly or indirectly, to
+anyone other than You; and/or (b) to use Covered Code, alone or as
+part of a Larger Work, in any way to provide a service, including but
+not limited to delivery of content, through electronic communication
+with a client other than You.
+
+1.5 "Larger Work" means a work which combines Covered Code or portions
+thereof with code not governed by the terms of this License.
+
+1.6 "Modifications" mean any addition to, deletion from, and/or change
+to, the substance and/or structure of the Original Code, any previous
+Modifications, the combination of Original Code and any previous
+Modifications, and/or any respective portions thereof. When code is
+released as a series of files, a Modification is: (a) any addition to
+or deletion from the contents of a file containing Covered Code;
+and/or (b) any new file or other representation of computer program
+statements that contains any part of Covered Code.
+
+1.7 "Original Code" means (a) the Source Code of a program or other
+work as originally made available by Apple under this License,
+including the Source Code of any updates or upgrades to such programs
+or works made available by Apple under this License, and that has been
+expressly identified by Apple as such in the header file(s) of such
+work; and (b) the object code compiled from such Source Code and
+originally made available by Apple under this License.
+
+1.8 "Source Code" means the human readable form of a program or other
+work that is suitable for making modifications to it, including all
+modules it contains, plus any associated interface definition files,
+scripts used to control compilation and installation of an executable
+(object code).
+
+1.9 "You" or "Your" means an individual or a legal entity exercising
+rights under this License. For legal entities, "You" or "Your"
+includes any entity which controls, is controlled by, or is under
+common control with, You, where "control" means (a) the power, direct
+or indirect, to cause the direction or management of such entity,
+whether by contract or otherwise, or (b) ownership of fifty percent
+(50%) or more of the outstanding shares or beneficial ownership of
+such entity.
+
+2. Permitted Uses; Conditions & Restrictions. Subject to the terms
+and conditions of this License, Apple hereby grants You, effective on
+the date You accept this License and download the Original Code, a
+world-wide, royalty-free, non-exclusive license, to the extent of
+Apple's Applicable Patent Rights and copyrights covering the Original
+Code, to do the following:
+
+2.1 Unmodified Code. You may use, reproduce, display, perform,
+internally distribute within Your organization, and Externally Deploy
+verbatim, unmodified copies of the Original Code, for commercial or
+non-commercial purposes, provided that in each instance:
+
+(a) You must retain and reproduce in all copies of Original Code the
+copyright and other proprietary notices and disclaimers of Apple as
+they appear in the Original Code, and keep intact all notices in the
+Original Code that refer to this License; and
+
+(b) You must include a copy of this License with every copy of Source
+Code of Covered Code and documentation You distribute or Externally
+Deploy, and You may not offer or impose any terms on such Source Code
+that alter or restrict this License or the recipients' rights
+hereunder, except as permitted under Section 6.
+
+2.2 Modified Code. You may modify Covered Code and use, reproduce,
+display, perform, internally distribute within Your organization, and
+Externally Deploy Your Modifications and Covered Code, for commercial
+or non-commercial purposes, provided that in each instance You also
+meet all of these conditions:
+
+(a) You must satisfy all the conditions of Section 2.1 with respect to
+the Source Code of the Covered Code;
+
+(b) You must duplicate, to the extent it does not already exist, the
+notice in Exhibit A in each file of the Source Code of all Your
+Modifications, and cause the modified files to carry prominent notices
+stating that You changed the files and the date of any change; and
+
+(c) If You Externally Deploy Your Modifications, You must make
+Source Code of all Your Externally Deployed Modifications either
+available to those to whom You have Externally Deployed Your
+Modifications, or publicly available. Source Code of Your Externally
+Deployed Modifications must be released under the terms set forth in
+this License, including the license grants set forth in Section 3
+below, for as long as you Externally Deploy the Covered Code or twelve
+(12) months from the date of initial External Deployment, whichever is
+longer. You should preferably distribute the Source Code of Your
+Externally Deployed Modifications electronically (e.g. download from a
+web site).
+
+2.3 Distribution of Executable Versions. In addition, if You
+Externally Deploy Covered Code (Original Code and/or Modifications) in
+object code, executable form only, You must include a prominent
+notice, in the code itself as well as in related documentation,
+stating that Source Code of the Covered Code is available under the
+terms of this License with information on how and where to obtain such
+Source Code.
+
+2.4 Third Party Rights. You expressly acknowledge and agree that
+although Apple and each Contributor grants the licenses to their
+respective portions of the Covered Code set forth herein, no
+assurances are provided by Apple or any Contributor that the Covered
+Code does not infringe the patent or other intellectual property
+rights of any other entity. Apple and each Contributor disclaim any
+liability to You for claims brought by any other entity based on
+infringement of intellectual property rights or otherwise. As a
+condition to exercising the rights and licenses granted hereunder, You
+hereby assume sole responsibility to secure any other intellectual
+property rights needed, if any. For example, if a third party patent
+license is required to allow You to distribute the Covered Code, it is
+Your responsibility to acquire that license before distributing the
+Covered Code.
+
+3. Your Grants. In consideration of, and as a condition to, the
+licenses granted to You under this License, You hereby grant to any
+person or entity receiving or distributing Covered Code under this
+License a non-exclusive, royalty-free, perpetual, irrevocable license,
+under Your Applicable Patent Rights and other intellectual property
+rights (other than patent) owned or controlled by You, to use,
+reproduce, display, perform, modify, sublicense, distribute and
+Externally Deploy Your Modifications of the same scope and extent as
+Apple's licenses under Sections 2.1 and 2.2 above.
+
+4. Larger Works. You may create a Larger Work by combining Covered
+Code with other code not governed by the terms of this License and
+distribute the Larger Work as a single product. In each such instance,
+You must make sure the requirements of this License are fulfilled for
+the Covered Code or any portion thereof.
+
+5. Limitations on Patent License. Except as expressly stated in
+Section 2, no other patent rights, express or implied, are granted by
+Apple herein. Modifications and/or Larger Works may require additional
+patent licenses from Apple which Apple may grant in its sole
+discretion.
+
+6. Additional Terms. You may choose to offer, and to charge a fee for,
+warranty, support, indemnity or liability obligations and/or other
+rights consistent with the scope of the license granted herein
+("Additional Terms") to one or more recipients of Covered Code.
+However, You may do so only on Your own behalf and as Your sole
+responsibility, and not on behalf of Apple or any Contributor. You
+must obtain the recipient's agreement that any such Additional Terms
+are offered by You alone, and You hereby agree to indemnify, defend
+and hold Apple and every Contributor harmless for any liability
+incurred by or claims asserted against Apple or such Contributor by
+reason of any such Additional Terms.
+
+7. Versions of the License. Apple may publish revised and/or new
+versions of this License from time to time. Each version will be given
+a distinguishing version number. Once Original Code has been published
+under a particular version of this License, You may continue to use it
+under the terms of that version. You may also choose to use such
+Original Code under the terms of any subsequent version of this
+License published by Apple. No one other than Apple has the right to
+modify the terms applicable to Covered Code created under this
+License.
+
+8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in
+part pre-release, untested, or not fully tested works. The Covered
+Code may contain errors that could cause failures or loss of data, and
+may be incomplete or contain inaccuracies. You expressly acknowledge
+and agree that use of the Covered Code, or any portion thereof, is at
+Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND
+WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND
+APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE
+PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM
+ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF
+MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR
+PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD
+PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST
+INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE
+FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS,
+THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR
+ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO
+ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE
+AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY.
+You acknowledge that the Covered Code is not intended for use in the
+operation of nuclear facilities, aircraft navigation, communication
+systems, or air traffic control machines in which case the failure of
+the Covered Code could lead to death, personal injury, or severe
+physical or environmental damage.
+
+9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
+EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL,
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING
+TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR
+ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY,
+TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF
+APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY
+REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF
+INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY
+TO YOU. In no event shall Apple's total liability to You for all
+damages (other than as may be required by applicable law) under this
+License exceed the amount of fifty dollars ($50.00).
+
+10. Trademarks. This License does not grant any rights to use the
+trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS",
+"QuickTime", "QuickTime Streaming Server" or any other trademarks,
+service marks, logos or trade names belonging to Apple (collectively
+"Apple Marks") or to any trademark, service mark, logo or trade name
+belonging to any Contributor. You agree not to use any Apple Marks in
+or as part of the name of products derived from the Original Code or
+to endorse or promote products derived from the Original Code other
+than as expressly permitted by and in strict compliance at all times
+with Apple's third party trademark usage guidelines which are posted
+at http://www.apple.com/legal/guidelinesfor3rdparties.html.
+
+11. Ownership. Subject to the licenses granted under this License,
+each Contributor retains all rights, title and interest in and to any
+Modifications made by such Contributor. Apple retains all rights,
+title and interest in and to the Original Code and any Modifications
+made by or on behalf of Apple ("Apple Modifications"), and such Apple
+Modifications will not be automatically subject to this License. Apple
+may, at its sole discretion, choose to license such Apple
+Modifications under this License, or on different terms from those
+contained in this License or may choose not to license them at all.
+
+12. Termination.
+
+12.1 Termination. This License and the rights granted hereunder will
+terminate:
+
+(a) automatically without notice from Apple if You fail to comply with
+any term(s) of this License and fail to cure such breach within 30
+days of becoming aware of such breach;
+
+(b) immediately in the event of the circumstances described in Section
+13.5(b); or
+
+(c) automatically without notice from Apple if You, at any time during
+the term of this License, commence an action for patent infringement
+against Apple; provided that Apple did not first commence
+an action for patent infringement against You in that instance.
+
+12.2 Effect of Termination. Upon termination, You agree to immediately
+stop any further use, reproduction, modification, sublicensing and
+distribution of the Covered Code. All sublicenses to the Covered Code
+which have been properly granted prior to termination shall survive
+any termination of this License. Provisions which, by their nature,
+should remain in effect beyond the termination of this License shall
+survive, including but not limited to Sections 3, 5, 8, 9, 10, 11,
+12.2 and 13. No party will be liable to any other for compensation,
+indemnity or damages of any sort solely as a result of terminating
+this License in accordance with its terms, and termination of this
+License will be without prejudice to any other right or remedy of
+any party.
+
+13. Miscellaneous.
+
+13.1 Government End Users. The Covered Code is a "commercial item" as
+defined in FAR 2.101. Government software and technical data rights in
+the Covered Code include only those rights customarily provided to the
+public as defined in this License. This customary commercial license
+in technical data and software is provided in accordance with FAR
+12.211 (Technical Data) and 12.212 (Computer Software) and, for
+Department of Defense purchases, DFAR 252.227-7015 (Technical Data --
+Commercial Items) and 227.7202-3 (Rights in Commercial Computer
+Software or Computer Software Documentation). Accordingly, all U.S.
+Government End Users acquire Covered Code with only those rights set
+forth herein.
+
+13.2 Relationship of Parties. This License will not be construed as
+creating an agency, partnership, joint venture or any other form of
+legal association between or among You, Apple or any Contributor, and
+You will not represent to the contrary, whether expressly, by
+implication, appearance or otherwise.
+
+13.3 Independent Development. Nothing in this License will impair
+Apple's right to acquire, license, develop, have others develop for
+it, market and/or distribute technology or products that perform the
+same or similar functions as, or otherwise compete with,
+Modifications, Larger Works, technology or products that You may
+develop, produce, market or distribute.
+
+13.4 Waiver; Construction. Failure by Apple or any Contributor to
+enforce any provision of this License will not be deemed a waiver of
+future enforcement of that or any other provision. Any law or
+regulation which provides that the language of a contract shall be
+construed against the drafter will not apply to this License.
+
+13.5 Severability. (a) If for any reason a court of competent
+jurisdiction finds any provision of this License, or portion thereof,
+to be unenforceable, that provision of the License will be enforced to
+the maximum extent permissible so as to effect the economic benefits
+and intent of the parties, and the remainder of this License will
+continue in full force and effect. (b) Notwithstanding the foregoing,
+if applicable law prohibits or restricts You from fully and/or
+specifically complying with Sections 2 and/or 3 or prevents the
+enforceability of either of those Sections, this License will
+immediately terminate and You must immediately discontinue any use of
+the Covered Code and destroy all copies of it that are in your
+possession or control.
+
+13.6 Dispute Resolution. Any litigation or other dispute resolution
+between You and Apple relating to this License shall take place in the
+Northern District of California, and You and Apple hereby consent to
+the personal jurisdiction of, and venue in, the state and federal
+courts within that District with respect to this License. The
+application of the United Nations Convention on Contracts for the
+International Sale of Goods is expressly excluded.
+
+13.7 Entire Agreement; Governing Law. This License constitutes the
+entire agreement between the parties with respect to the subject
+matter hereof. This License shall be governed by the laws of the
+United States and the State of California, except that body of
+California law concerning conflicts of law.
+
+Where You are located in the province of Quebec, Canada, the following
+clause applies: The parties hereby confirm that they have requested
+that this License and all related documents be drafted in English. Les
+parties ont exige que le present contrat et tous les documents
+connexes soient rediges en anglais.
+
+EXHIBIT A.
+
+"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
+Reserved.
+
+This file contains Original Code and/or Modifications of Original Code
+as defined in and that are subject to the Apple Public Source License
+Version 2.0 (the 'License'). You may not use this file except in
+compliance with the License. Please obtain a copy of the License at
+http://www.opensource.apple.com/apsl/ and read it before using this
+file.
+
+The Original Code and all software distributed under the License are
+distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+Please see the License for the specific language governing rights and
+limitations under the License."
diff --git a/third_party/crashpad/crashpad/third_party/xnu/BUILD.gn b/third_party/crashpad/crashpad/third_party/xnu/BUILD.gn
new file mode 100644
index 0000000..b6a9404
--- /dev/null
+++ b/third_party/crashpad/crashpad/third_party/xnu/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2019 The Crashpad Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+source_set("xnu") {
+  sources = [
+    "EXTERNAL_HEADERS/mach-o/loader.h",
+  ]
+}
diff --git a/third_party/crashpad/crashpad/third_party/xnu/EXTERNAL_HEADERS/mach-o/loader.h b/third_party/crashpad/crashpad/third_party/xnu/EXTERNAL_HEADERS/mach-o/loader.h
new file mode 100644
index 0000000..3b7f0ee
--- /dev/null
+++ b/third_party/crashpad/crashpad/third_party/xnu/EXTERNAL_HEADERS/mach-o/loader.h
@@ -0,0 +1,1531 @@
+/*
+ * Copyright (c) 1999-2010 Apple Inc.  All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#ifndef _MACHO_LOADER_H_
+#define _MACHO_LOADER_H_
+
+/*
+ * This file describes the format of mach object files.
+ */
+#include <stdint.h>
+
+/*
+ * <mach/machine.h> is needed here for the cpu_type_t and cpu_subtype_t types
+ * and contains the constants for the possible values of these types.
+ */
+#include <mach/machine.h>
+
+/*
+ * <mach/vm_prot.h> is needed here for the vm_prot_t type and contains the 
+ * constants that are or'ed together for the possible values of this type.
+ */
+#include <mach/vm_prot.h>
+
+/*
+ * The 32-bit mach header appears at the very beginning of the object file for
+ * 32-bit architectures.
+ */
+struct mach_header {
+	uint32_t	magic;		/* mach magic number identifier */
+	cpu_type_t	cputype;	/* cpu specifier */
+	cpu_subtype_t	cpusubtype;	/* machine specifier */
+	uint32_t	filetype;	/* type of file */
+	uint32_t	ncmds;		/* number of load commands */
+	uint32_t	sizeofcmds;	/* the size of all the load commands */
+	uint32_t	flags;		/* flags */
+};
+
+/* Constant for the magic field of the mach_header (32-bit architectures) */
+#define	MH_MAGIC	0xfeedface	/* the mach magic number */
+#define MH_CIGAM	0xcefaedfe	/* NXSwapInt(MH_MAGIC) */
+
+/*
+ * The 64-bit mach header appears at the very beginning of object files for
+ * 64-bit architectures.
+ */
+struct mach_header_64 {
+	uint32_t	magic;		/* mach magic number identifier */
+	cpu_type_t	cputype;	/* cpu specifier */
+	cpu_subtype_t	cpusubtype;	/* machine specifier */
+	uint32_t	filetype;	/* type of file */
+	uint32_t	ncmds;		/* number of load commands */
+	uint32_t	sizeofcmds;	/* the size of all the load commands */
+	uint32_t	flags;		/* flags */
+	uint32_t	reserved;	/* reserved */
+};
+
+/* Constant for the magic field of the mach_header_64 (64-bit architectures) */
+#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */
+#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */
+
+/*
+ * The layout of the file depends on the filetype.  For all but the MH_OBJECT
+ * file type the segments are padded out and aligned on a segment alignment
+ * boundary for efficient demand pageing.  The MH_EXECUTE, MH_FVMLIB, MH_DYLIB,
+ * MH_DYLINKER and MH_BUNDLE file types also have the headers included as part
+ * of their first segment.
+ * 
+ * The file type MH_OBJECT is a compact format intended as output of the
+ * assembler and input (and possibly output) of the link editor (the .o
+ * format).  All sections are in one unnamed segment with no segment padding. 
+ * This format is used as an executable format when the file is so small the
+ * segment padding greatly increases its size.
+ *
+ * The file type MH_PRELOAD is an executable format intended for things that
+ * are not executed under the kernel (proms, stand alones, kernels, etc).  The
+ * format can be executed under the kernel but may demand paged it and not
+ * preload it before execution.
+ *
+ * A core file is in MH_CORE format and can be any in an arbritray legal
+ * Mach-O file.
+ *
+ * Constants for the filetype field of the mach_header
+ */
+#define	MH_OBJECT	0x1		/* relocatable object file */
+#define	MH_EXECUTE	0x2		/* demand paged executable file */
+#define	MH_FVMLIB	0x3		/* fixed VM shared library file */
+#define	MH_CORE		0x4		/* core file */
+#define	MH_PRELOAD	0x5		/* preloaded executable file */
+#define	MH_DYLIB	0x6		/* dynamically bound shared library */
+#define	MH_DYLINKER	0x7		/* dynamic link editor */
+#define	MH_BUNDLE	0x8		/* dynamically bound bundle file */
+#define	MH_DYLIB_STUB	0x9		/* shared library stub for static */
+					/*  linking only, no section contents */
+#define	MH_DSYM		0xa		/* companion file with only debug */
+					/*  sections */
+#define	MH_KEXT_BUNDLE	0xb		/* x86_64 kexts */
+
+/* Constants for the flags field of the mach_header */
+#define	MH_NOUNDEFS	0x1		/* the object file has no undefined
+					   references */
+#define	MH_INCRLINK	0x2		/* the object file is the output of an
+					   incremental link against a base file
+					   and can't be link edited again */
+#define MH_DYLDLINK	0x4		/* the object file is input for the
+					   dynamic linker and can't be staticly
+					   link edited again */
+#define MH_BINDATLOAD	0x8		/* the object file's undefined
+					   references are bound by the dynamic
+					   linker when loaded. */
+#define MH_PREBOUND	0x10		/* the file has its dynamic undefined
+					   references prebound. */
+#define MH_SPLIT_SEGS	0x20		/* the file has its read-only and
+					   read-write segments split */
+#define MH_LAZY_INIT	0x40		/* the shared library init routine is
+					   to be run lazily via catching memory
+					   faults to its writeable segments
+					   (obsolete) */
+#define MH_TWOLEVEL	0x80		/* the image is using two-level name
+					   space bindings */
+#define MH_FORCE_FLAT	0x100		/* the executable is forcing all images
+					   to use flat name space bindings */
+#define MH_NOMULTIDEFS	0x200		/* this umbrella guarantees no multiple
+					   defintions of symbols in its
+					   sub-images so the two-level namespace
+					   hints can always be used. */
+#define MH_NOFIXPREBINDING 0x400	/* do not have dyld notify the
+					   prebinding agent about this
+					   executable */
+#define MH_PREBINDABLE  0x800           /* the binary is not prebound but can
+					   have its prebinding redone. only used
+                                           when MH_PREBOUND is not set. */
+#define MH_ALLMODSBOUND 0x1000		/* indicates that this binary binds to
+                                           all two-level namespace modules of
+					   its dependent libraries. only used
+					   when MH_PREBINDABLE and MH_TWOLEVEL
+					   are both set. */ 
+#define MH_SUBSECTIONS_VIA_SYMBOLS 0x2000/* safe to divide up the sections into
+					    sub-sections via symbols for dead
+					    code stripping */
+#define MH_CANONICAL    0x4000		/* the binary has been canonicalized
+					   via the unprebind operation */
+#define MH_WEAK_DEFINES	0x8000		/* the final linked image contains
+					   external weak symbols */
+#define MH_BINDS_TO_WEAK 0x10000	/* the final linked image uses
+					   weak symbols */
+
+#define MH_ALLOW_STACK_EXECUTION 0x20000/* When this bit is set, all stacks 
+					   in the task will be given stack
+					   execution privilege.  Only used in
+					   MH_EXECUTE filetypes. */
+#define MH_ROOT_SAFE 0x40000           /* When this bit is set, the binary 
+					  declares it is safe for use in
+					  processes with uid zero */
+                                         
+#define MH_SETUID_SAFE 0x80000         /* When this bit is set, the binary 
+					  declares it is safe for use in
+					  processes when issetugid() is true */
+
+#define MH_NO_REEXPORTED_DYLIBS 0x100000 /* When this bit is set on a dylib, 
+					  the static linker does not need to
+					  examine dependent dylibs to see
+					  if any are re-exported */
+#define	MH_PIE 0x200000			/* When this bit is set, the OS will
+					   load the main executable at a
+					   random address.  Only used in
+					   MH_EXECUTE filetypes. */
+#define	MH_DEAD_STRIPPABLE_DYLIB 0x400000 /* Only for use on dylibs.  When
+					     linking against a dylib that
+					     has this bit set, the static linker
+					     will automatically not create a
+					     LC_LOAD_DYLIB load command to the
+					     dylib if no symbols are being
+					     referenced from the dylib. */
+#define MH_HAS_TLV_DESCRIPTORS 0x800000 /* Contains a section of type 
+					    S_THREAD_LOCAL_VARIABLES */
+
+#define MH_NO_HEAP_EXECUTION 0x1000000	/* When this bit is set, the OS will
+					   run the main executable with
+					   a non-executable heap even on
+					   platforms (e.g. i386) that don't
+					   require it. Only used in MH_EXECUTE
+					   filetypes. */
+
+#define MH_APP_EXTENSION_SAFE 0x02000000 /* The code was linked for use in an
+					    application extension. */
+
+/*
+ * The load commands directly follow the mach_header.  The total size of all
+ * of the commands is given by the sizeofcmds field in the mach_header.  All
+ * load commands must have as their first two fields cmd and cmdsize.  The cmd
+ * field is filled in with a constant for that command type.  Each command type
+ * has a structure specifically for it.  The cmdsize field is the size in bytes
+ * of the particular load command structure plus anything that follows it that
+ * is a part of the load command (i.e. section structures, strings, etc.).  To
+ * advance to the next load command the cmdsize can be added to the offset or
+ * pointer of the current load command.  The cmdsize for 32-bit architectures
+ * MUST be a multiple of 4 bytes and for 64-bit architectures MUST be a multiple
+ * of 8 bytes (these are forever the maximum alignment of any load commands).
+ * The padded bytes must be zero.  All tables in the object file must also
+ * follow these rules so the file can be memory mapped.  Otherwise the pointers
+ * to these tables will not work well or at all on some machines.  With all
+ * padding zeroed like objects will compare byte for byte.
+ */
+struct load_command {
+	uint32_t cmd;		/* type of load command */
+	uint32_t cmdsize;	/* total size of command in bytes */
+};
+
+/*
+ * After MacOS X 10.1 when a new load command is added that is required to be
+ * understood by the dynamic linker for the image to execute properly the
+ * LC_REQ_DYLD bit will be or'ed into the load command constant.  If the dynamic
+ * linker sees such a load command it it does not understand will issue a
+ * "unknown load command required for execution" error and refuse to use the
+ * image.  Other load commands without this bit that are not understood will
+ * simply be ignored.
+ */
+#define LC_REQ_DYLD 0x80000000
+
+/* Constants for the cmd field of all load commands, the type */
+#define	LC_SEGMENT	0x1	/* segment of this file to be mapped */
+#define	LC_SYMTAB	0x2	/* link-edit stab symbol table info */
+#define	LC_SYMSEG	0x3	/* link-edit gdb symbol table info (obsolete) */
+#define	LC_THREAD	0x4	/* thread */
+#define	LC_UNIXTHREAD	0x5	/* unix thread (includes a stack) */
+#define	LC_LOADFVMLIB	0x6	/* load a specified fixed VM shared library */
+#define	LC_IDFVMLIB	0x7	/* fixed VM shared library identification */
+#define	LC_IDENT	0x8	/* object identification info (obsolete) */
+#define LC_FVMFILE	0x9	/* fixed VM file inclusion (internal use) */
+#define LC_PREPAGE      0xa     /* prepage command (internal use) */
+#define	LC_DYSYMTAB	0xb	/* dynamic link-edit symbol table info */
+#define	LC_LOAD_DYLIB	0xc	/* load a dynamically linked shared library */
+#define	LC_ID_DYLIB	0xd	/* dynamically linked shared lib ident */
+#define LC_LOAD_DYLINKER 0xe	/* load a dynamic linker */
+#define LC_ID_DYLINKER	0xf	/* dynamic linker identification */
+#define	LC_PREBOUND_DYLIB 0x10	/* modules prebound for a dynamically */
+				/*  linked shared library */
+#define	LC_ROUTINES	0x11	/* image routines */
+#define	LC_SUB_FRAMEWORK 0x12	/* sub framework */
+#define	LC_SUB_UMBRELLA 0x13	/* sub umbrella */
+#define	LC_SUB_CLIENT	0x14	/* sub client */
+#define	LC_SUB_LIBRARY  0x15	/* sub library */
+#define	LC_TWOLEVEL_HINTS 0x16	/* two-level namespace lookup hints */
+#define	LC_PREBIND_CKSUM  0x17	/* prebind checksum */
+
+/*
+ * load a dynamically linked shared library that is allowed to be missing
+ * (all symbols are weak imported).
+ */
+#define	LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
+
+#define	LC_SEGMENT_64	0x19	/* 64-bit segment of this file to be
+				   mapped */
+#define	LC_ROUTINES_64	0x1a	/* 64-bit image routines */
+#define LC_UUID		0x1b	/* the uuid */
+#define LC_RPATH       (0x1c | LC_REQ_DYLD)    /* runpath additions */
+#define LC_CODE_SIGNATURE 0x1d	/* local of code signature */
+#define LC_SEGMENT_SPLIT_INFO 0x1e /* local of info to split segments */
+#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) /* load and re-export dylib */
+#define	LC_LAZY_LOAD_DYLIB 0x20	/* delay load of dylib until first use */
+#define	LC_ENCRYPTION_INFO 0x21	/* encrypted segment information */
+#define	LC_DYLD_INFO 	0x22	/* compressed dyld information */
+#define	LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD)	/* compressed dyld information only */
+#define	LC_LOAD_UPWARD_DYLIB (0x23 | LC_REQ_DYLD) /* load upward dylib */
+#define LC_VERSION_MIN_MACOSX 0x24   /* build for MacOSX min OS version */
+#define LC_VERSION_MIN_IPHONEOS 0x25 /* build for iPhoneOS min OS version */
+#define LC_FUNCTION_STARTS 0x26 /* compressed table of function start addresses */
+#define LC_DYLD_ENVIRONMENT 0x27 /* string for dyld to treat
+				    like environment variable */
+#define LC_MAIN (0x28|LC_REQ_DYLD) /* replacement for LC_UNIXTHREAD */
+#define LC_DATA_IN_CODE 0x29 /* table of non-instructions in __text */
+#define LC_SOURCE_VERSION 0x2A /* source version used to build binary */
+#define LC_DYLIB_CODE_SIGN_DRS 0x2B /* Code signing DRs copied from linked dylibs */
+#define	LC_ENCRYPTION_INFO_64 0x2C /* 64-bit encrypted segment information */
+#define LC_LINKER_OPTION 0x2D /* linker options in MH_OBJECT files */
+#define LC_LINKER_OPTIMIZATION_HINT 0x2E /* optimization hints in MH_OBJECT files */
+#define LC_VERSION_MIN_TVOS 0x2F /* build for AppleTV min OS version */
+#define LC_VERSION_MIN_WATCHOS 0x30 /* build for Watch min OS version */
+#define LC_NOTE 0x31 /* arbitrary data included within a Mach-O file */
+#define LC_BUILD_VERSION 0x32 /* build for platform min OS version */
+
+/*
+ * A variable length string in a load command is represented by an lc_str
+ * union.  The strings are stored just after the load command structure and
+ * the offset is from the start of the load command structure.  The size
+ * of the string is reflected in the cmdsize field of the load command.
+ * Once again any padded bytes to bring the cmdsize field to a multiple
+ * of 4 bytes must be zero.
+ */
+union lc_str {
+	uint32_t	offset;	/* offset to the string */
+#ifndef __LP64__
+	char		*ptr;	/* pointer to the string */
+#endif 
+};
+
+/*
+ * The segment load command indicates that a part of this file is to be
+ * mapped into the task's address space.  The size of this segment in memory,
+ * vmsize, maybe equal to or larger than the amount to map from this file,
+ * filesize.  The file is mapped starting at fileoff to the beginning of
+ * the segment in memory, vmaddr.  The rest of the memory of the segment,
+ * if any, is allocated zero fill on demand.  The segment's maximum virtual
+ * memory protection and initial virtual memory protection are specified
+ * by the maxprot and initprot fields.  If the segment has sections then the
+ * section structures directly follow the segment command and their size is
+ * reflected in cmdsize.
+ */
+struct segment_command { /* for 32-bit architectures */
+	uint32_t	cmd;		/* LC_SEGMENT */
+	uint32_t	cmdsize;	/* includes sizeof section structs */
+	char		segname[16];	/* segment name */
+	uint32_t	vmaddr;		/* memory address of this segment */
+	uint32_t	vmsize;		/* memory size of this segment */
+	uint32_t	fileoff;	/* file offset of this segment */
+	uint32_t	filesize;	/* amount to map from the file */
+	vm_prot_t	maxprot;	/* maximum VM protection */
+	vm_prot_t	initprot;	/* initial VM protection */
+	uint32_t	nsects;		/* number of sections in segment */
+	uint32_t	flags;		/* flags */
+};
+
+/*
+ * The 64-bit segment load command indicates that a part of this file is to be
+ * mapped into a 64-bit task's address space.  If the 64-bit segment has
+ * sections then section_64 structures directly follow the 64-bit segment
+ * command and their size is reflected in cmdsize.
+ */
+struct segment_command_64 { /* for 64-bit architectures */
+	uint32_t	cmd;		/* LC_SEGMENT_64 */
+	uint32_t	cmdsize;	/* includes sizeof section_64 structs */
+	char		segname[16];	/* segment name */
+	uint64_t	vmaddr;		/* memory address of this segment */
+	uint64_t	vmsize;		/* memory size of this segment */
+	uint64_t	fileoff;	/* file offset of this segment */
+	uint64_t	filesize;	/* amount to map from the file */
+	vm_prot_t	maxprot;	/* maximum VM protection */
+	vm_prot_t	initprot;	/* initial VM protection */
+	uint32_t	nsects;		/* number of sections in segment */
+	uint32_t	flags;		/* flags */
+};
+
+/* Constants for the flags field of the segment_command */
+#define	SG_HIGHVM	0x1	/* the file contents for this segment is for
+				   the high part of the VM space, the low part
+				   is zero filled (for stacks in core files) */
+#define	SG_FVMLIB	0x2	/* this segment is the VM that is allocated by
+				   a fixed VM library, for overlap checking in
+				   the link editor */
+#define	SG_NORELOC	0x4	/* this segment has nothing that was relocated
+				   in it and nothing relocated to it, that is
+				   it maybe safely replaced without relocation*/
+#define SG_PROTECTED_VERSION_1	0x8 /* This segment is protected.  If the
+				       segment starts at file offset 0, the
+				       first page of the segment is not
+				       protected.  All other pages of the
+				       segment are protected. */
+
+/*
+ * A segment is made up of zero or more sections.  Non-MH_OBJECT files have
+ * all of their segments with the proper sections in each, and padded to the
+ * specified segment alignment when produced by the link editor.  The first
+ * segment of a MH_EXECUTE and MH_FVMLIB format file contains the mach_header
+ * and load commands of the object file before its first section.  The zero
+ * fill sections are always last in their segment (in all formats).  This
+ * allows the zeroed segment padding to be mapped into memory where zero fill
+ * sections might be. The gigabyte zero fill sections, those with the section
+ * type S_GB_ZEROFILL, can only be in a segment with sections of this type.
+ * These segments are then placed after all other segments.
+ *
+ * The MH_OBJECT format has all of its sections in one segment for
+ * compactness.  There is no padding to a specified segment boundary and the
+ * mach_header and load commands are not part of the segment.
+ *
+ * Sections with the same section name, sectname, going into the same segment,
+ * segname, are combined by the link editor.  The resulting section is aligned
+ * to the maximum alignment of the combined sections and is the new section's
+ * alignment.  The combined sections are aligned to their original alignment in
+ * the combined section.  Any padded bytes to get the specified alignment are
+ * zeroed.
+ *
+ * The format of the relocation entries referenced by the reloff and nreloc
+ * fields of the section structure for mach object files is described in the
+ * header file <reloc.h>.
+ */
+struct section { /* for 32-bit architectures */
+	char		sectname[16];	/* name of this section */
+	char		segname[16];	/* segment this section goes in */
+	uint32_t	addr;		/* memory address of this section */
+	uint32_t	size;		/* size in bytes of this section */
+	uint32_t	offset;		/* file offset of this section */
+	uint32_t	align;		/* section alignment (power of 2) */
+	uint32_t	reloff;		/* file offset of relocation entries */
+	uint32_t	nreloc;		/* number of relocation entries */
+	uint32_t	flags;		/* flags (section type and attributes)*/
+	uint32_t	reserved1;	/* reserved (for offset or index) */
+	uint32_t	reserved2;	/* reserved (for count or sizeof) */
+};
+
+struct section_64 { /* for 64-bit architectures */
+	char		sectname[16];	/* name of this section */
+	char		segname[16];	/* segment this section goes in */
+	uint64_t	addr;		/* memory address of this section */
+	uint64_t	size;		/* size in bytes of this section */
+	uint32_t	offset;		/* file offset of this section */
+	uint32_t	align;		/* section alignment (power of 2) */
+	uint32_t	reloff;		/* file offset of relocation entries */
+	uint32_t	nreloc;		/* number of relocation entries */
+	uint32_t	flags;		/* flags (section type and attributes)*/
+	uint32_t	reserved1;	/* reserved (for offset or index) */
+	uint32_t	reserved2;	/* reserved (for count or sizeof) */
+	uint32_t	reserved3;	/* reserved */
+};
+
+/*
+ * The flags field of a section structure is separated into two parts a section
+ * type and section attributes.  The section types are mutually exclusive (it
+ * can only have one type) but the section attributes are not (it may have more
+ * than one attribute).
+ */
+#define SECTION_TYPE		 0x000000ff	/* 256 section types */
+#define SECTION_ATTRIBUTES	 0xffffff00	/*  24 section attributes */
+
+/* Constants for the type of a section */
+#define	S_REGULAR		0x0	/* regular section */
+#define	S_ZEROFILL		0x1	/* zero fill on demand section */
+#define	S_CSTRING_LITERALS	0x2	/* section with only literal C strings*/
+#define	S_4BYTE_LITERALS	0x3	/* section with only 4 byte literals */
+#define	S_8BYTE_LITERALS	0x4	/* section with only 8 byte literals */
+#define	S_LITERAL_POINTERS	0x5	/* section with only pointers to */
+					/*  literals */
+/*
+ * For the two types of symbol pointers sections and the symbol stubs section
+ * they have indirect symbol table entries.  For each of the entries in the
+ * section the indirect symbol table entries, in corresponding order in the
+ * indirect symbol table, start at the index stored in the reserved1 field
+ * of the section structure.  Since the indirect symbol table entries
+ * correspond to the entries in the section the number of indirect symbol table
+ * entries is inferred from the size of the section divided by the size of the
+ * entries in the section.  For symbol pointers sections the size of the entries
+ * in the section is 4 bytes and for symbol stubs sections the byte size of the
+ * stubs is stored in the reserved2 field of the section structure.
+ */
+#define	S_NON_LAZY_SYMBOL_POINTERS	0x6	/* section with only non-lazy
+						   symbol pointers */
+#define	S_LAZY_SYMBOL_POINTERS		0x7	/* section with only lazy symbol
+						   pointers */
+#define	S_SYMBOL_STUBS			0x8	/* section with only symbol
+						   stubs, byte size of stub in
+						   the reserved2 field */
+#define	S_MOD_INIT_FUNC_POINTERS	0x9	/* section with only function
+						   pointers for initialization*/
+#define	S_MOD_TERM_FUNC_POINTERS	0xa	/* section with only function
+						   pointers for termination */
+#define	S_COALESCED			0xb	/* section contains symbols that
+						   are to be coalesced */
+#define	S_GB_ZEROFILL			0xc	/* zero fill on demand section
+						   (that can be larger than 4
+						   gigabytes) */
+#define	S_INTERPOSING			0xd	/* section with only pairs of
+						   function pointers for
+						   interposing */
+#define	S_16BYTE_LITERALS		0xe	/* section with only 16 byte
+						   literals */
+#define	S_DTRACE_DOF			0xf	/* section contains 
+						   DTrace Object Format */
+#define	S_LAZY_DYLIB_SYMBOL_POINTERS	0x10	/* section with only lazy
+						   symbol pointers to lazy
+						   loaded dylibs */
+/*
+ * Section types to support thread local variables
+ */
+#define S_THREAD_LOCAL_REGULAR                   0x11  /* template of initial 
+							  values for TLVs */
+#define S_THREAD_LOCAL_ZEROFILL                  0x12  /* template of initial 
+							  values for TLVs */
+#define S_THREAD_LOCAL_VARIABLES                 0x13  /* TLV descriptors */
+#define S_THREAD_LOCAL_VARIABLE_POINTERS         0x14  /* pointers to TLV 
+                                                          descriptors */
+#define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS    0x15  /* functions to call
+							  to initialize TLV
+							  values */
+
+/*
+ * Constants for the section attributes part of the flags field of a section
+ * structure.
+ */
+#define SECTION_ATTRIBUTES_USR	 0xff000000	/* User setable attributes */
+#define S_ATTR_PURE_INSTRUCTIONS 0x80000000	/* section contains only true
+						   machine instructions */
+#define S_ATTR_NO_TOC 		 0x40000000	/* section contains coalesced
+						   symbols that are not to be
+						   in a ranlib table of
+						   contents */
+#define S_ATTR_STRIP_STATIC_SYMS 0x20000000	/* ok to strip static symbols
+						   in this section in files
+						   with the MH_DYLDLINK flag */
+#define S_ATTR_NO_DEAD_STRIP	 0x10000000	/* no dead stripping */
+#define S_ATTR_LIVE_SUPPORT	 0x08000000	/* blocks are live if they
+						   reference live blocks */
+#define S_ATTR_SELF_MODIFYING_CODE 0x04000000	/* Used with i386 code stubs
+						   written on by dyld */
+/*
+ * If a segment contains any sections marked with S_ATTR_DEBUG then all
+ * sections in that segment must have this attribute.  No section other than
+ * a section marked with this attribute may reference the contents of this
+ * section.  A section with this attribute may contain no symbols and must have
+ * a section type S_REGULAR.  The static linker will not copy section contents
+ * from sections with this attribute into its output file.  These sections
+ * generally contain DWARF debugging info.
+ */ 
+#define	S_ATTR_DEBUG		 0x02000000	/* a debug section */
+#define SECTION_ATTRIBUTES_SYS	 0x00ffff00	/* system setable attributes */
+#define S_ATTR_SOME_INSTRUCTIONS 0x00000400	/* section contains some
+						   machine instructions */
+#define S_ATTR_EXT_RELOC	 0x00000200	/* section has external
+						   relocation entries */
+#define S_ATTR_LOC_RELOC	 0x00000100	/* section has local
+						   relocation entries */
+
+
+/*
+ * The names of segments and sections in them are mostly meaningless to the
+ * link-editor.  But there are few things to support traditional UNIX
+ * executables that require the link-editor and assembler to use some names
+ * agreed upon by convention.
+ *
+ * The initial protection of the "__TEXT" segment has write protection turned
+ * off (not writeable).
+ *
+ * The link-editor will allocate common symbols at the end of the "__common"
+ * section in the "__DATA" segment.  It will create the section and segment
+ * if needed.
+ */
+
+/* The currently known segment names and the section names in those segments */
+
+#define	SEG_PAGEZERO	"__PAGEZERO"	/* the pagezero segment which has no */
+					/* protections and catches NULL */
+					/* references for MH_EXECUTE files */
+
+
+#define	SEG_TEXT	"__TEXT"	/* the tradition UNIX text segment */
+#define	SECT_TEXT	"__text"	/* the real text part of the text */
+					/* section no headers, and no padding */
+#define SECT_FVMLIB_INIT0 "__fvmlib_init0"	/* the fvmlib initialization */
+						/*  section */
+#define SECT_FVMLIB_INIT1 "__fvmlib_init1"	/* the section following the */
+					        /*  fvmlib initialization */
+						/*  section */
+
+#define	SEG_DATA	"__DATA"	/* the tradition UNIX data segment */
+#define	SECT_DATA	"__data"	/* the real initialized data section */
+					/* no padding, no bss overlap */
+#define	SECT_BSS	"__bss"		/* the real uninitialized data section*/
+					/* no padding */
+#define SECT_COMMON	"__common"	/* the section common symbols are */
+					/* allocated in by the link editor */
+
+#define	SEG_OBJC	"__OBJC"	/* objective-C runtime segment */
+#define SECT_OBJC_SYMBOLS "__symbol_table"	/* symbol table */
+#define SECT_OBJC_MODULES "__module_info"	/* module information */
+#define SECT_OBJC_STRINGS "__selector_strs"	/* string table */
+#define SECT_OBJC_REFS "__selector_refs"	/* string table */
+
+#define	SEG_ICON	 "__ICON"	/* the icon segment */
+#define	SECT_ICON_HEADER "__header"	/* the icon headers */
+#define	SECT_ICON_TIFF   "__tiff"	/* the icons in tiff format */
+
+#define	SEG_LINKEDIT	"__LINKEDIT"	/* the segment containing all structs */
+					/* created and maintained by the link */
+					/* editor.  Created with -seglinkedit */
+					/* option to ld(1) for MH_EXECUTE and */
+					/* FVMLIB file types only */
+
+#define SEG_UNIXSTACK	"__UNIXSTACK"	/* the unix stack segment */
+
+#define SEG_IMPORT	"__IMPORT"	/* the segment for the self (dyld) */
+					/* modifing code stubs that has read, */
+					/* write and execute permissions */
+
+/*
+ * Fixed virtual memory shared libraries are identified by two things.  The
+ * target pathname (the name of the library as found for execution), and the
+ * minor version number.  The address of where the headers are loaded is in
+ * header_addr. (THIS IS OBSOLETE and no longer supported).
+ */
+struct fvmlib {
+	union lc_str	name;		/* library's target pathname */
+	uint32_t	minor_version;	/* library's minor version number */
+	uint32_t	header_addr;	/* library's header address */
+};
+
+/*
+ * A fixed virtual shared library (filetype == MH_FVMLIB in the mach header)
+ * contains a fvmlib_command (cmd == LC_IDFVMLIB) to identify the library.
+ * An object that uses a fixed virtual shared library also contains a
+ * fvmlib_command (cmd == LC_LOADFVMLIB) for each library it uses.
+ * (THIS IS OBSOLETE and no longer supported).
+ */
+struct fvmlib_command {
+	uint32_t	cmd;		/* LC_IDFVMLIB or LC_LOADFVMLIB */
+	uint32_t	cmdsize;	/* includes pathname string */
+	struct fvmlib	fvmlib;		/* the library identification */
+};
+
+/*
+ * Dynamicly linked shared libraries are identified by two things.  The
+ * pathname (the name of the library as found for execution), and the
+ * compatibility version number.  The pathname must match and the compatibility
+ * number in the user of the library must be greater than or equal to the
+ * library being used.  The time stamp is used to record the time a library was
+ * built and copied into user so it can be use to determined if the library used
+ * at runtime is exactly the same as used to built the program.
+ */
+struct dylib {
+    union lc_str  name;			/* library's path name */
+    uint32_t timestamp;			/* library's build time stamp */
+    uint32_t current_version;		/* library's current version number */
+    uint32_t compatibility_version;	/* library's compatibility vers number*/
+};
+
+/*
+ * A dynamically linked shared library (filetype == MH_DYLIB in the mach header)
+ * contains a dylib_command (cmd == LC_ID_DYLIB) to identify the library.
+ * An object that uses a dynamically linked shared library also contains a
+ * dylib_command (cmd == LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, or
+ * LC_REEXPORT_DYLIB) for each library it uses.
+ */
+struct dylib_command {
+	uint32_t	cmd;		/* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB,
+					   LC_REEXPORT_DYLIB */
+	uint32_t	cmdsize;	/* includes pathname string */
+	struct dylib	dylib;		/* the library identification */
+};
+
+/*
+ * A dynamically linked shared library may be a subframework of an umbrella
+ * framework.  If so it will be linked with "-umbrella umbrella_name" where
+ * Where "umbrella_name" is the name of the umbrella framework. A subframework
+ * can only be linked against by its umbrella framework or other subframeworks
+ * that are part of the same umbrella framework.  Otherwise the static link
+ * editor produces an error and states to link against the umbrella framework.
+ * The name of the umbrella framework for subframeworks is recorded in the
+ * following structure.
+ */
+struct sub_framework_command {
+	uint32_t	cmd;		/* LC_SUB_FRAMEWORK */
+	uint32_t	cmdsize;	/* includes umbrella string */
+	union lc_str 	umbrella;	/* the umbrella framework name */
+};
+
+/*
+ * For dynamically linked shared libraries that are subframework of an umbrella
+ * framework they can allow clients other than the umbrella framework or other
+ * subframeworks in the same umbrella framework.  To do this the subframework
+ * is built with "-allowable_client client_name" and an LC_SUB_CLIENT load
+ * command is created for each -allowable_client flag.  The client_name is
+ * usually a framework name.  It can also be a name used for bundles clients
+ * where the bundle is built with "-client_name client_name".
+ */
+struct sub_client_command {
+	uint32_t	cmd;		/* LC_SUB_CLIENT */
+	uint32_t	cmdsize;	/* includes client string */
+	union lc_str 	client;		/* the client name */
+};
+
+/*
+ * A dynamically linked shared library may be a sub_umbrella of an umbrella
+ * framework.  If so it will be linked with "-sub_umbrella umbrella_name" where
+ * Where "umbrella_name" is the name of the sub_umbrella framework.  When
+ * staticly linking when -twolevel_namespace is in effect a twolevel namespace 
+ * umbrella framework will only cause its subframeworks and those frameworks
+ * listed as sub_umbrella frameworks to be implicited linked in.  Any other
+ * dependent dynamic libraries will not be linked it when -twolevel_namespace
+ * is in effect.  The primary library recorded by the static linker when
+ * resolving a symbol in these libraries will be the umbrella framework.
+ * Zero or more sub_umbrella frameworks may be use by an umbrella framework.
+ * The name of a sub_umbrella framework is recorded in the following structure.
+ */
+struct sub_umbrella_command {
+	uint32_t	cmd;		/* LC_SUB_UMBRELLA */
+	uint32_t	cmdsize;	/* includes sub_umbrella string */
+	union lc_str 	sub_umbrella;	/* the sub_umbrella framework name */
+};
+
+/*
+ * A dynamically linked shared library may be a sub_library of another shared
+ * library.  If so it will be linked with "-sub_library library_name" where
+ * Where "library_name" is the name of the sub_library shared library.  When
+ * staticly linking when -twolevel_namespace is in effect a twolevel namespace 
+ * shared library will only cause its subframeworks and those frameworks
+ * listed as sub_umbrella frameworks and libraries listed as sub_libraries to
+ * be implicited linked in.  Any other dependent dynamic libraries will not be
+ * linked it when -twolevel_namespace is in effect.  The primary library
+ * recorded by the static linker when resolving a symbol in these libraries
+ * will be the umbrella framework (or dynamic library). Zero or more sub_library
+ * shared libraries may be use by an umbrella framework or (or dynamic library).
+ * The name of a sub_library framework is recorded in the following structure.
+ * For example /usr/lib/libobjc_profile.A.dylib would be recorded as "libobjc".
+ */
+struct sub_library_command {
+	uint32_t	cmd;		/* LC_SUB_LIBRARY */
+	uint32_t	cmdsize;	/* includes sub_library string */
+	union lc_str 	sub_library;	/* the sub_library name */
+};
+
+/*
+ * A program (filetype == MH_EXECUTE) that is
+ * prebound to its dynamic libraries has one of these for each library that
+ * the static linker used in prebinding.  It contains a bit vector for the
+ * modules in the library.  The bits indicate which modules are bound (1) and
+ * which are not (0) from the library.  The bit for module 0 is the low bit
+ * of the first byte.  So the bit for the Nth module is:
+ * (linked_modules[N/8] >> N%8) & 1
+ */
+struct prebound_dylib_command {
+	uint32_t	cmd;		/* LC_PREBOUND_DYLIB */
+	uint32_t	cmdsize;	/* includes strings */
+	union lc_str	name;		/* library's path name */
+	uint32_t	nmodules;	/* number of modules in library */
+	union lc_str	linked_modules;	/* bit vector of linked modules */
+};
+
+/*
+ * A program that uses a dynamic linker contains a dylinker_command to identify
+ * the name of the dynamic linker (LC_LOAD_DYLINKER).  And a dynamic linker
+ * contains a dylinker_command to identify the dynamic linker (LC_ID_DYLINKER).
+ * A file can have at most one of these.
+ * This struct is also used for the LC_DYLD_ENVIRONMENT load command and
+ * contains string for dyld to treat like environment variable.
+ */
+struct dylinker_command {
+	uint32_t	cmd;		/* LC_ID_DYLINKER, LC_LOAD_DYLINKER or
+					   LC_DYLD_ENVIRONMENT */
+	uint32_t	cmdsize;	/* includes pathname string */
+	union lc_str    name;		/* dynamic linker's path name */
+};
+
+/*
+ * Thread commands contain machine-specific data structures suitable for
+ * use in the thread state primitives.  The machine specific data structures
+ * follow the struct thread_command as follows.
+ * Each flavor of machine specific data structure is preceded by an unsigned
+ * long constant for the flavor of that data structure, an uint32_t
+ * that is the count of longs of the size of the state data structure and then
+ * the state data structure follows.  This triple may be repeated for many
+ * flavors.  The constants for the flavors, counts and state data structure
+ * definitions are expected to be in the header file <machine/thread_status.h>.
+ * These machine specific data structures sizes must be multiples of
+ * 4 bytes  The cmdsize reflects the total size of the thread_command
+ * and all of the sizes of the constants for the flavors, counts and state
+ * data structures.
+ *
+ * For executable objects that are unix processes there will be one
+ * thread_command (cmd == LC_UNIXTHREAD) created for it by the link-editor.
+ * This is the same as a LC_THREAD, except that a stack is automatically
+ * created (based on the shell's limit for the stack size).  Command arguments
+ * and environment variables are copied onto that stack.
+ */
+struct thread_command {
+	uint32_t	cmd;		/* LC_THREAD or  LC_UNIXTHREAD */
+	uint32_t	cmdsize;	/* total size of this command */
+	/* uint32_t flavor		   flavor of thread state */
+	/* uint32_t count		   count of longs in thread state */
+	/* struct XXX_thread_state state   thread state for this flavor */
+	/* ... */
+};
+
+/*
+ * The routines command contains the address of the dynamic shared library 
+ * initialization routine and an index into the module table for the module
+ * that defines the routine.  Before any modules are used from the library the
+ * dynamic linker fully binds the module that defines the initialization routine
+ * and then calls it.  This gets called before any module initialization
+ * routines (used for C++ static constructors) in the library.
+ */
+struct routines_command { /* for 32-bit architectures */
+	uint32_t	cmd;		/* LC_ROUTINES */
+	uint32_t	cmdsize;	/* total size of this command */
+	uint32_t	init_address;	/* address of initialization routine */
+	uint32_t	init_module;	/* index into the module table that */
+				        /*  the init routine is defined in */
+	uint32_t	reserved1;
+	uint32_t	reserved2;
+	uint32_t	reserved3;
+	uint32_t	reserved4;
+	uint32_t	reserved5;
+	uint32_t	reserved6;
+};
+
+/*
+ * The 64-bit routines command.  Same use as above.
+ */
+struct routines_command_64 { /* for 64-bit architectures */
+	uint32_t	cmd;		/* LC_ROUTINES_64 */
+	uint32_t	cmdsize;	/* total size of this command */
+	uint64_t	init_address;	/* address of initialization routine */
+	uint64_t	init_module;	/* index into the module table that */
+					/*  the init routine is defined in */
+	uint64_t	reserved1;
+	uint64_t	reserved2;
+	uint64_t	reserved3;
+	uint64_t	reserved4;
+	uint64_t	reserved5;
+	uint64_t	reserved6;
+};
+
+/*
+ * The symtab_command contains the offsets and sizes of the link-edit 4.3BSD
+ * "stab" style symbol table information as described in the header files
+ * <nlist.h> and <stab.h>.
+ */
+struct symtab_command {
+	uint32_t	cmd;		/* LC_SYMTAB */
+	uint32_t	cmdsize;	/* sizeof(struct symtab_command) */
+	uint32_t	symoff;		/* symbol table offset */
+	uint32_t	nsyms;		/* number of symbol table entries */
+	uint32_t	stroff;		/* string table offset */
+	uint32_t	strsize;	/* string table size in bytes */
+};
+
+/*
+ * This is the second set of the symbolic information which is used to support
+ * the data structures for the dynamically link editor.
+ *
+ * The original set of symbolic information in the symtab_command which contains
+ * the symbol and string tables must also be present when this load command is
+ * present.  When this load command is present the symbol table is organized
+ * into three groups of symbols:
+ *	local symbols (static and debugging symbols) - grouped by module
+ *	defined external symbols - grouped by module (sorted by name if not lib)
+ *	undefined external symbols (sorted by name if MH_BINDATLOAD is not set,
+ *	     			    and in order the were seen by the static
+ *				    linker if MH_BINDATLOAD is set)
+ * In this load command there are offsets and counts to each of the three groups
+ * of symbols.
+ *
+ * This load command contains a the offsets and sizes of the following new
+ * symbolic information tables:
+ *	table of contents
+ *	module table
+ *	reference symbol table
+ *	indirect symbol table
+ * The first three tables above (the table of contents, module table and
+ * reference symbol table) are only present if the file is a dynamically linked
+ * shared library.  For executable and object modules, which are files
+ * containing only one module, the information that would be in these three
+ * tables is determined as follows:
+ * 	table of contents - the defined external symbols are sorted by name
+ *	module table - the file contains only one module so everything in the
+ *		       file is part of the module.
+ *	reference symbol table - is the defined and undefined external symbols
+ *
+ * For dynamically linked shared library files this load command also contains
+ * offsets and sizes to the pool of relocation entries for all sections
+ * separated into two groups:
+ *	external relocation entries
+ *	local relocation entries
+ * For executable and object modules the relocation entries continue to hang
+ * off the section structures.
+ */
+struct dysymtab_command {
+    uint32_t cmd;	/* LC_DYSYMTAB */
+    uint32_t cmdsize;	/* sizeof(struct dysymtab_command) */
+
+    /*
+     * The symbols indicated by symoff and nsyms of the LC_SYMTAB load command
+     * are grouped into the following three groups:
+     *    local symbols (further grouped by the module they are from)
+     *    defined external symbols (further grouped by the module they are from)
+     *    undefined symbols
+     *
+     * The local symbols are used only for debugging.  The dynamic binding
+     * process may have to use them to indicate to the debugger the local
+     * symbols for a module that is being bound.
+     *
+     * The last two groups are used by the dynamic binding process to do the
+     * binding (indirectly through the module table and the reference symbol
+     * table when this is a dynamically linked shared library file).
+     */
+    uint32_t ilocalsym;	/* index to local symbols */
+    uint32_t nlocalsym;	/* number of local symbols */
+
+    uint32_t iextdefsym;/* index to externally defined symbols */
+    uint32_t nextdefsym;/* number of externally defined symbols */
+
+    uint32_t iundefsym;	/* index to undefined symbols */
+    uint32_t nundefsym;	/* number of undefined symbols */
+
+    /*
+     * For the for the dynamic binding process to find which module a symbol
+     * is defined in the table of contents is used (analogous to the ranlib
+     * structure in an archive) which maps defined external symbols to modules
+     * they are defined in.  This exists only in a dynamically linked shared
+     * library file.  For executable and object modules the defined external
+     * symbols are sorted by name and is use as the table of contents.
+     */
+    uint32_t tocoff;	/* file offset to table of contents */
+    uint32_t ntoc;	/* number of entries in table of contents */
+
+    /*
+     * To support dynamic binding of "modules" (whole object files) the symbol
+     * table must reflect the modules that the file was created from.  This is
+     * done by having a module table that has indexes and counts into the merged
+     * tables for each module.  The module structure that these two entries
+     * refer to is described below.  This exists only in a dynamically linked
+     * shared library file.  For executable and object modules the file only
+     * contains one module so everything in the file belongs to the module.
+     */
+    uint32_t modtaboff;	/* file offset to module table */
+    uint32_t nmodtab;	/* number of module table entries */
+
+    /*
+     * To support dynamic module binding the module structure for each module
+     * indicates the external references (defined and undefined) each module
+     * makes.  For each module there is an offset and a count into the
+     * reference symbol table for the symbols that the module references.
+     * This exists only in a dynamically linked shared library file.  For
+     * executable and object modules the defined external symbols and the
+     * undefined external symbols indicates the external references.
+     */
+    uint32_t extrefsymoff;	/* offset to referenced symbol table */
+    uint32_t nextrefsyms;	/* number of referenced symbol table entries */
+
+    /*
+     * The sections that contain "symbol pointers" and "routine stubs" have
+     * indexes and (implied counts based on the size of the section and fixed
+     * size of the entry) into the "indirect symbol" table for each pointer
+     * and stub.  For every section of these two types the index into the
+     * indirect symbol table is stored in the section header in the field
+     * reserved1.  An indirect symbol table entry is simply a 32bit index into
+     * the symbol table to the symbol that the pointer or stub is referring to.
+     * The indirect symbol table is ordered to match the entries in the section.
+     */
+    uint32_t indirectsymoff; /* file offset to the indirect symbol table */
+    uint32_t nindirectsyms;  /* number of indirect symbol table entries */
+
+    /*
+     * To support relocating an individual module in a library file quickly the
+     * external relocation entries for each module in the library need to be
+     * accessed efficiently.  Since the relocation entries can't be accessed
+     * through the section headers for a library file they are separated into
+     * groups of local and external entries further grouped by module.  In this
+     * case the presents of this load command who's extreloff, nextrel,
+     * locreloff and nlocrel fields are non-zero indicates that the relocation
+     * entries of non-merged sections are not referenced through the section
+     * structures (and the reloff and nreloc fields in the section headers are
+     * set to zero).
+     *
+     * Since the relocation entries are not accessed through the section headers
+     * this requires the r_address field to be something other than a section
+     * offset to identify the item to be relocated.  In this case r_address is
+     * set to the offset from the vmaddr of the first LC_SEGMENT command.
+     * For MH_SPLIT_SEGS images r_address is set to the the offset from the
+     * vmaddr of the first read-write LC_SEGMENT command.
+     *
+     * The relocation entries are grouped by module and the module table
+     * entries have indexes and counts into them for the group of external
+     * relocation entries for that the module.
+     *
+     * For sections that are merged across modules there must not be any
+     * remaining external relocation entries for them (for merged sections
+     * remaining relocation entries must be local).
+     */
+    uint32_t extreloff;	/* offset to external relocation entries */
+    uint32_t nextrel;	/* number of external relocation entries */
+
+    /*
+     * All the local relocation entries are grouped together (they are not
+     * grouped by their module since they are only used if the object is moved
+     * from it staticly link edited address).
+     */
+    uint32_t locreloff;	/* offset to local relocation entries */
+    uint32_t nlocrel;	/* number of local relocation entries */
+
+};	
+
+/*
+ * An indirect symbol table entry is simply a 32bit index into the symbol table 
+ * to the symbol that the pointer or stub is refering to.  Unless it is for a
+ * non-lazy symbol pointer section for a defined symbol which strip(1) as 
+ * removed.  In which case it has the value INDIRECT_SYMBOL_LOCAL.  If the
+ * symbol was also absolute INDIRECT_SYMBOL_ABS is or'ed with that.
+ */
+#define INDIRECT_SYMBOL_LOCAL	0x80000000
+#define INDIRECT_SYMBOL_ABS	0x40000000
+
+
+/* a table of contents entry */
+struct dylib_table_of_contents {
+    uint32_t symbol_index;	/* the defined external symbol
+				   (index into the symbol table) */
+    uint32_t module_index;	/* index into the module table this symbol
+				   is defined in */
+};	
+
+/* a module table entry */
+struct dylib_module {
+    uint32_t module_name;	/* the module name (index into string table) */
+
+    uint32_t iextdefsym;	/* index into externally defined symbols */
+    uint32_t nextdefsym;	/* number of externally defined symbols */
+    uint32_t irefsym;		/* index into reference symbol table */
+    uint32_t nrefsym;		/* number of reference symbol table entries */
+    uint32_t ilocalsym;		/* index into symbols for local symbols */
+    uint32_t nlocalsym;		/* number of local symbols */
+
+    uint32_t iextrel;		/* index into external relocation entries */
+    uint32_t nextrel;		/* number of external relocation entries */
+
+    uint32_t iinit_iterm;	/* low 16 bits are the index into the init
+				   section, high 16 bits are the index into
+			           the term section */
+    uint32_t ninit_nterm;	/* low 16 bits are the number of init section
+				   entries, high 16 bits are the number of
+				   term section entries */
+
+    uint32_t			/* for this module address of the start of */
+	objc_module_info_addr;  /*  the (__OBJC,__module_info) section */
+    uint32_t			/* for this module size of */
+	objc_module_info_size;	/*  the (__OBJC,__module_info) section */
+};	
+
+/* a 64-bit module table entry */
+struct dylib_module_64 {
+    uint32_t module_name;	/* the module name (index into string table) */
+
+    uint32_t iextdefsym;	/* index into externally defined symbols */
+    uint32_t nextdefsym;	/* number of externally defined symbols */
+    uint32_t irefsym;		/* index into reference symbol table */
+    uint32_t nrefsym;		/* number of reference symbol table entries */
+    uint32_t ilocalsym;		/* index into symbols for local symbols */
+    uint32_t nlocalsym;		/* number of local symbols */
+
+    uint32_t iextrel;		/* index into external relocation entries */
+    uint32_t nextrel;		/* number of external relocation entries */
+
+    uint32_t iinit_iterm;	/* low 16 bits are the index into the init
+				   section, high 16 bits are the index into
+				   the term section */
+    uint32_t ninit_nterm;      /* low 16 bits are the number of init section
+				  entries, high 16 bits are the number of
+				  term section entries */
+
+    uint32_t			/* for this module size of */
+        objc_module_info_size;	/*  the (__OBJC,__module_info) section */
+    uint64_t			/* for this module address of the start of */
+        objc_module_info_addr;	/*  the (__OBJC,__module_info) section */
+};
+
+/* 
+ * The entries in the reference symbol table are used when loading the module
+ * (both by the static and dynamic link editors) and if the module is unloaded
+ * or replaced.  Therefore all external symbols (defined and undefined) are
+ * listed in the module's reference table.  The flags describe the type of
+ * reference that is being made.  The constants for the flags are defined in
+ * <mach-o/nlist.h> as they are also used for symbol table entries.
+ */
+struct dylib_reference {
+    uint32_t isym:24,		/* index into the symbol table */
+    		  flags:8;	/* flags to indicate the type of reference */
+};
+
+/*
+ * The twolevel_hints_command contains the offset and number of hints in the
+ * two-level namespace lookup hints table.
+ */
+struct twolevel_hints_command {
+    uint32_t cmd;	/* LC_TWOLEVEL_HINTS */
+    uint32_t cmdsize;	/* sizeof(struct twolevel_hints_command) */
+    uint32_t offset;	/* offset to the hint table */
+    uint32_t nhints;	/* number of hints in the hint table */
+};
+
+/*
+ * The entries in the two-level namespace lookup hints table are twolevel_hint
+ * structs.  These provide hints to the dynamic link editor where to start
+ * looking for an undefined symbol in a two-level namespace image.  The
+ * isub_image field is an index into the sub-images (sub-frameworks and
+ * sub-umbrellas list) that made up the two-level image that the undefined
+ * symbol was found in when it was built by the static link editor.  If
+ * isub-image is 0 the the symbol is expected to be defined in library and not
+ * in the sub-images.  If isub-image is non-zero it is an index into the array
+ * of sub-images for the umbrella with the first index in the sub-images being
+ * 1. The array of sub-images is the ordered list of sub-images of the umbrella
+ * that would be searched for a symbol that has the umbrella recorded as its
+ * primary library.  The table of contents index is an index into the
+ * library's table of contents.  This is used as the starting point of the
+ * binary search or a directed linear search.
+ */
+struct twolevel_hint {
+    uint32_t 
+	isub_image:8,	/* index into the sub images */
+	itoc:24;	/* index into the table of contents */
+};
+
+/*
+ * The prebind_cksum_command contains the value of the original check sum for
+ * prebound files or zero.  When a prebound file is first created or modified
+ * for other than updating its prebinding information the value of the check sum
+ * is set to zero.  When the file has it prebinding re-done and if the value of
+ * the check sum is zero the original check sum is calculated and stored in
+ * cksum field of this load command in the output file.  If when the prebinding
+ * is re-done and the cksum field is non-zero it is left unchanged from the
+ * input file.
+ */
+struct prebind_cksum_command {
+    uint32_t cmd;	/* LC_PREBIND_CKSUM */
+    uint32_t cmdsize;	/* sizeof(struct prebind_cksum_command) */
+    uint32_t cksum;	/* the check sum or zero */
+};
+
+/*
+ * The uuid load command contains a single 128-bit unique random number that
+ * identifies an object produced by the static link editor.
+ */
+struct uuid_command {
+    uint32_t	cmd;		/* LC_UUID */
+    uint32_t	cmdsize;	/* sizeof(struct uuid_command) */
+    uint8_t	uuid[16];	/* the 128-bit uuid */
+};
+
+/*
+ * The rpath_command contains a path which at runtime should be added to
+ * the current run path used to find @rpath prefixed dylibs.
+ */
+struct rpath_command {
+    uint32_t	 cmd;		/* LC_RPATH */
+    uint32_t	 cmdsize;	/* includes string */
+    union lc_str path;		/* path to add to run path */
+};
+
+/*
+ * The linkedit_data_command contains the offsets and sizes of a blob
+ * of data in the __LINKEDIT segment.  
+ */
+struct linkedit_data_command {
+    uint32_t	cmd;		/* LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO,
+                                   LC_FUNCTION_STARTS, LC_DATA_IN_CODE,
+				   LC_DYLIB_CODE_SIGN_DRS or
+				   LC_LINKER_OPTIMIZATION_HINT. */
+    uint32_t	cmdsize;	/* sizeof(struct linkedit_data_command) */
+    uint32_t	dataoff;	/* file offset of data in __LINKEDIT segment */
+    uint32_t	datasize;	/* file size of data in __LINKEDIT segment  */
+};
+
+/*
+ * The encryption_info_command contains the file offset and size of an
+ * of an encrypted segment.
+ */
+struct encryption_info_command {
+   uint32_t	cmd;		/* LC_ENCRYPTION_INFO */
+   uint32_t	cmdsize;	/* sizeof(struct encryption_info_command) */
+   uint32_t	cryptoff;	/* file offset of encrypted range */
+   uint32_t	cryptsize;	/* file size of encrypted range */
+   uint32_t	cryptid;	/* which enryption system,
+				   0 means not-encrypted yet */
+};
+
+/*
+ * The encryption_info_command_64 contains the file offset and size of an
+ * of an encrypted segment (for use in x86_64 targets).
+ */
+struct encryption_info_command_64 {
+   uint32_t	cmd;		/* LC_ENCRYPTION_INFO_64 */
+   uint32_t	cmdsize;	/* sizeof(struct encryption_info_command_64) */
+   uint32_t	cryptoff;	/* file offset of encrypted range */
+   uint32_t	cryptsize;	/* file size of encrypted range */
+   uint32_t	cryptid;	/* which enryption system,
+				   0 means not-encrypted yet */
+   uint32_t	pad;		/* padding to make this struct's size a multiple
+				   of 8 bytes */
+};
+
+/*
+ * The version_min_command contains the min OS version on which this 
+ * binary was built to run.
+ */
+struct version_min_command {
+    uint32_t	cmd;		/* LC_VERSION_MIN_MACOSX or
+				   LC_VERSION_MIN_IPHONEOS or
+				   LC_VERSION_MIN_WATCHOS or
+				   LC_VERSION_MIN_TVOS */
+    uint32_t	cmdsize;	/* sizeof(struct min_version_command) */
+    uint32_t	version;	/* X.Y.Z is encoded in nibbles xxxx.yy.zz */
+    uint32_t	sdk;		/* X.Y.Z is encoded in nibbles xxxx.yy.zz */
+};
+
+/*
+ * The build_version_command contains the min OS version on which this
+ * binary was built to run for its platform.  The list of known platforms and
+ * tool values following it.
+ */
+struct build_version_command {
+    uint32_t	cmd;		/* LC_BUILD_VERSION */
+    uint32_t	cmdsize;	/* sizeof(struct build_version_command) plus */
+                                /* ntools * sizeof(struct build_tool_version) */
+    uint32_t	platform;	/* platform */
+    uint32_t	minos;		/* X.Y.Z is encoded in nibbles xxxx.yy.zz */
+    uint32_t	sdk;		/* X.Y.Z is encoded in nibbles xxxx.yy.zz */
+    uint32_t	ntools;		/* number of tool entries following this */
+};
+
+struct build_tool_version {
+    uint32_t	tool;		/* enum for the tool */
+    uint32_t	version;	/* version number of the tool */
+};
+
+/* Known values for the platform field above. */
+#define PLATFORM_MACOS 1
+#define PLATFORM_IOS 2
+#define PLATFORM_TVOS 3
+#define PLATFORM_WATCHOS 4
+
+/* Known values for the tool field above. */
+#define TOOL_CLANG 1
+#define TOOL_SWIFT 2
+#define TOOL_LD	3
+
+/*
+ * The dyld_info_command contains the file offsets and sizes of 
+ * the new compressed form of the information dyld needs to 
+ * load the image.  This information is used by dyld on Mac OS X
+ * 10.6 and later.  All information pointed to by this command
+ * is encoded using byte streams, so no endian swapping is needed
+ * to interpret it. 
+ */
+struct dyld_info_command {
+   uint32_t   cmd;		/* LC_DYLD_INFO or LC_DYLD_INFO_ONLY */
+   uint32_t   cmdsize;		/* sizeof(struct dyld_info_command) */
+
+    /*
+     * Dyld rebases an image whenever dyld loads it at an address different
+     * from its preferred address.  The rebase information is a stream
+     * of byte sized opcodes whose symbolic names start with REBASE_OPCODE_.
+     * Conceptually the rebase information is a table of tuples:
+     *    <seg-index, seg-offset, type>
+     * The opcodes are a compressed way to encode the table by only
+     * encoding when a column changes.  In addition simple patterns
+     * like "every n'th offset for m times" can be encoded in a few
+     * bytes.
+     */
+    uint32_t   rebase_off;	/* file offset to rebase info  */
+    uint32_t   rebase_size;	/* size of rebase info   */
+    
+    /*
+     * Dyld binds an image during the loading process, if the image
+     * requires any pointers to be initialized to symbols in other images.  
+     * The bind information is a stream of byte sized 
+     * opcodes whose symbolic names start with BIND_OPCODE_.
+     * Conceptually the bind information is a table of tuples:
+     *    <seg-index, seg-offset, type, symbol-library-ordinal, symbol-name, addend>
+     * The opcodes are a compressed way to encode the table by only
+     * encoding when a column changes.  In addition simple patterns
+     * like for runs of pointers initialzed to the same value can be 
+     * encoded in a few bytes.
+     */
+    uint32_t   bind_off;	/* file offset to binding info   */
+    uint32_t   bind_size;	/* size of binding info  */
+        
+    /*
+     * Some C++ programs require dyld to unique symbols so that all
+     * images in the process use the same copy of some code/data.
+     * This step is done after binding. The content of the weak_bind
+     * info is an opcode stream like the bind_info.  But it is sorted
+     * alphabetically by symbol name.  This enable dyld to walk 
+     * all images with weak binding information in order and look
+     * for collisions.  If there are no collisions, dyld does
+     * no updating.  That means that some fixups are also encoded
+     * in the bind_info.  For instance, all calls to "operator new"
+     * are first bound to libstdc++.dylib using the information
+     * in bind_info.  Then if some image overrides operator new
+     * that is detected when the weak_bind information is processed
+     * and the call to operator new is then rebound.
+     */
+    uint32_t   weak_bind_off;	/* file offset to weak binding info   */
+    uint32_t   weak_bind_size;  /* size of weak binding info  */
+    
+    /*
+     * Some uses of external symbols do not need to be bound immediately.
+     * Instead they can be lazily bound on first use.  The lazy_bind
+     * are contains a stream of BIND opcodes to bind all lazy symbols.
+     * Normal use is that dyld ignores the lazy_bind section when
+     * loading an image.  Instead the static linker arranged for the
+     * lazy pointer to initially point to a helper function which 
+     * pushes the offset into the lazy_bind area for the symbol
+     * needing to be bound, then jumps to dyld which simply adds
+     * the offset to lazy_bind_off to get the information on what 
+     * to bind.  
+     */
+    uint32_t   lazy_bind_off;	/* file offset to lazy binding info */
+    uint32_t   lazy_bind_size;  /* size of lazy binding infs */
+    
+    /*
+     * The symbols exported by a dylib are encoded in a trie.  This
+     * is a compact representation that factors out common prefixes.
+     * It also reduces LINKEDIT pages in RAM because it encodes all  
+     * information (name, address, flags) in one small, contiguous range.
+     * The export area is a stream of nodes.  The first node sequentially
+     * is the start node for the trie.  
+     *
+     * Nodes for a symbol start with a uleb128 that is the length of
+     * the exported symbol information for the string so far.
+     * If there is no exported symbol, the node starts with a zero byte. 
+     * If there is exported info, it follows the length.  
+	 *
+	 * First is a uleb128 containing flags. Normally, it is followed by
+     * a uleb128 encoded offset which is location of the content named
+     * by the symbol from the mach_header for the image.  If the flags
+     * is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags is
+     * a uleb128 encoded library ordinal, then a zero terminated
+     * UTF8 string.  If the string is zero length, then the symbol
+     * is re-export from the specified dylib with the same name.
+	 * If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, then following
+	 * the flags is two uleb128s: the stub offset and the resolver offset.
+	 * The stub is used by non-lazy pointers.  The resolver is used
+	 * by lazy pointers and must be called to get the actual address to use.
+     *
+     * After the optional exported symbol information is a byte of
+     * how many edges (0-255) that this node has leaving it, 
+     * followed by each edge.
+     * Each edge is a zero terminated UTF8 of the addition chars
+     * in the symbol, followed by a uleb128 offset for the node that
+     * edge points to.
+     *  
+     */
+    uint32_t   export_off;	/* file offset to lazy binding info */
+    uint32_t   export_size;	/* size of lazy binding infs */
+};
+
+/*
+ * The following are used to encode rebasing information
+ */
+#define REBASE_TYPE_POINTER					1
+#define REBASE_TYPE_TEXT_ABSOLUTE32				2
+#define REBASE_TYPE_TEXT_PCREL32				3
+
+#define REBASE_OPCODE_MASK					0xF0
+#define REBASE_IMMEDIATE_MASK					0x0F
+#define REBASE_OPCODE_DONE					0x00
+#define REBASE_OPCODE_SET_TYPE_IMM				0x10
+#define REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB		0x20
+#define REBASE_OPCODE_ADD_ADDR_ULEB				0x30
+#define REBASE_OPCODE_ADD_ADDR_IMM_SCALED			0x40
+#define REBASE_OPCODE_DO_REBASE_IMM_TIMES			0x50
+#define REBASE_OPCODE_DO_REBASE_ULEB_TIMES			0x60
+#define REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB			0x70
+#define REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB	0x80
+
+
+/*
+ * The following are used to encode binding information
+ */
+#define BIND_TYPE_POINTER					1
+#define BIND_TYPE_TEXT_ABSOLUTE32				2
+#define BIND_TYPE_TEXT_PCREL32					3
+
+#define BIND_SPECIAL_DYLIB_SELF					 0
+#define BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE			-1
+#define BIND_SPECIAL_DYLIB_FLAT_LOOKUP				-2
+
+#define BIND_SYMBOL_FLAGS_WEAK_IMPORT				0x1
+#define BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION			0x8
+
+#define BIND_OPCODE_MASK					0xF0
+#define BIND_IMMEDIATE_MASK					0x0F
+#define BIND_OPCODE_DONE					0x00
+#define BIND_OPCODE_SET_DYLIB_ORDINAL_IMM			0x10
+#define BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB			0x20
+#define BIND_OPCODE_SET_DYLIB_SPECIAL_IMM			0x30
+#define BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM		0x40
+#define BIND_OPCODE_SET_TYPE_IMM				0x50
+#define BIND_OPCODE_SET_ADDEND_SLEB				0x60
+#define BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB			0x70
+#define BIND_OPCODE_ADD_ADDR_ULEB				0x80
+#define BIND_OPCODE_DO_BIND					0x90
+#define BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB			0xA0
+#define BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED			0xB0
+#define BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB		0xC0
+
+
+/*
+ * The following are used on the flags byte of a terminal node
+ * in the export information.
+ */
+#define EXPORT_SYMBOL_FLAGS_KIND_MASK				0x03
+#define EXPORT_SYMBOL_FLAGS_KIND_REGULAR			0x00
+#define EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL			0x01
+#define EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION			0x04
+#define EXPORT_SYMBOL_FLAGS_REEXPORT				0x08
+#define EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER			0x10
+
+/*
+ * The linker_option_command contains linker options embedded in object files.
+ */
+struct linker_option_command {
+    uint32_t  cmd;	/* LC_LINKER_OPTION only used in MH_OBJECT filetypes */
+    uint32_t  cmdsize;
+    uint32_t  count;	/* number of strings */
+    /* concatenation of zero terminated UTF8 strings.
+       Zero filled at end to align */
+};
+
+/*
+ * The symseg_command contains the offset and size of the GNU style
+ * symbol table information as described in the header file <symseg.h>.
+ * The symbol roots of the symbol segments must also be aligned properly
+ * in the file.  So the requirement of keeping the offsets aligned to a
+ * multiple of a 4 bytes translates to the length field of the symbol
+ * roots also being a multiple of a long.  Also the padding must again be
+ * zeroed. (THIS IS OBSOLETE and no longer supported).
+ */
+struct symseg_command {
+	uint32_t	cmd;		/* LC_SYMSEG */
+	uint32_t	cmdsize;	/* sizeof(struct symseg_command) */
+	uint32_t	offset;		/* symbol segment offset */
+	uint32_t	size;		/* symbol segment size in bytes */
+};
+
+/*
+ * The ident_command contains a free format string table following the
+ * ident_command structure.  The strings are null terminated and the size of
+ * the command is padded out with zero bytes to a multiple of 4 bytes/
+ * (THIS IS OBSOLETE and no longer supported).
+ */
+struct ident_command {
+	uint32_t cmd;		/* LC_IDENT */
+	uint32_t cmdsize;	/* strings that follow this command */
+};
+
+/*
+ * The fvmfile_command contains a reference to a file to be loaded at the
+ * specified virtual address.  (Presently, this command is reserved for
+ * internal use.  The kernel ignores this command when loading a program into
+ * memory).
+ */
+struct fvmfile_command {
+	uint32_t cmd;			/* LC_FVMFILE */
+	uint32_t cmdsize;		/* includes pathname string */
+	union lc_str	name;		/* files pathname */
+	uint32_t	header_addr;	/* files virtual address */
+};
+
+
+/*
+ * The entry_point_command is a replacement for thread_command.
+ * It is used for main executables to specify the location (file offset)
+ * of main().  If -stack_size was used at link time, the stacksize
+ * field will contain the stack size need for the main thread.
+ */
+struct entry_point_command {
+    uint32_t  cmd;	/* LC_MAIN only used in MH_EXECUTE filetypes */
+    uint32_t  cmdsize;	/* 24 */
+    uint64_t  entryoff;	/* file (__TEXT) offset of main() */
+    uint64_t  stacksize;/* if not zero, initial stack size */
+};
+
+
+/*
+ * The source_version_command is an optional load command containing
+ * the version of the sources used to build the binary.
+ */
+struct source_version_command {
+    uint32_t  cmd;	/* LC_SOURCE_VERSION */
+    uint32_t  cmdsize;	/* 16 */
+    uint64_t  version;	/* A.B.C.D.E packed as a24.b10.c10.d10.e10 */
+};
+
+
+/*
+ * The LC_DATA_IN_CODE load commands uses a linkedit_data_command 
+ * to point to an array of data_in_code_entry entries. Each entry
+ * describes a range of data in a code section.
+ */
+struct data_in_code_entry {
+    uint32_t	offset;  /* from mach_header to start of data range*/
+    uint16_t	length;  /* number of bytes in data range */
+    uint16_t	kind;    /* a DICE_KIND_* value  */
+};
+#define DICE_KIND_DATA              0x0001
+#define DICE_KIND_JUMP_TABLE8       0x0002
+#define DICE_KIND_JUMP_TABLE16      0x0003
+#define DICE_KIND_JUMP_TABLE32      0x0004
+#define DICE_KIND_ABS_JUMP_TABLE32  0x0005
+
+
+
+/*
+ * Sections of type S_THREAD_LOCAL_VARIABLES contain an array 
+ * of tlv_descriptor structures.
+ */
+struct tlv_descriptor
+{
+	void*		(*thunk)(struct tlv_descriptor*);
+	unsigned long	key;
+	unsigned long	offset;
+};
+
+/*
+ * LC_NOTE commands describe a region of arbitrary data included in a Mach-O
+ * file.  Its initial use is to record extra data in MH_CORE files.
+ */
+struct note_command {
+    uint32_t	cmd;		/* LC_NOTE */
+    uint32_t	cmdsize;	/* sizeof(struct note_command) */
+    char	data_owner[16];	/* owner name for this LC_NOTE */
+    uint64_t	offset;		/* file offset of this data */
+    uint64_t	size;		/* length of data region */
+};
+
+#endif /* _MACHO_LOADER_H_ */
diff --git a/third_party/crashpad/crashpad/third_party/xnu/README.crashpad b/third_party/crashpad/crashpad/third_party/xnu/README.crashpad
new file mode 100644
index 0000000..274faf1
--- /dev/null
+++ b/third_party/crashpad/crashpad/third_party/xnu/README.crashpad
@@ -0,0 +1,19 @@
+Name: XNU
+Short Name: xnu
+URL: https://opensource.apple.com/source/xnu/
+URL: https://opensource.apple.com/tarballs/xnu/
+Version: 4903.221.2 (from macOS 10.14.1)
+License: APSL 2.0
+License File: APPLE_LICENSE
+Security Critical: no
+
+Description:
+XNU is the operating system kernel used on macOS and other Apple systems.
+
+Local Modifications:
+ - Only EXTERNAL_HEADERS/mach-o/loader.h is included. Its #includes of
+   <mach/machine/thread_status.h> and <architecture/byte_order.h> have been
+   removed as unnecessary. Note that its #includes of <mach/machine.h> and
+   <mach/vm_prot.h> have been retained but these headers have not been provided.
+   External headers must be made available to provide the cpu_type_t,
+   cpu_subtype_t, and vm_prot_t types.
diff --git a/third_party/crashpad/crashpad/util/BUILD.gn b/third_party/crashpad/crashpad/util/BUILD.gn
index b5e1561a..41a74d63 100644
--- a/third_party/crashpad/crashpad/util/BUILD.gn
+++ b/third_party/crashpad/crashpad/util/BUILD.gn
@@ -441,7 +441,10 @@
       "Foundation.framework",
       "IOKit.framework",
     ]
-    deps += [ ":mig" ]
+    deps += [
+      ":mig",
+      "../third_party/apple_cf:apple_cf",
+    ]
     include_dirs += [ "$root_build_dir/gen" ]
   }
 
diff --git a/third_party/crashpad/crashpad/util/fuchsia/koid_utilities.cc b/third_party/crashpad/crashpad/util/fuchsia/koid_utilities.cc
index bb40a1c..288f04b 100644
--- a/third_party/crashpad/crashpad/util/fuchsia/koid_utilities.cc
+++ b/third_party/crashpad/crashpad/util/fuchsia/koid_utilities.cc
@@ -15,7 +15,7 @@
 #include "util/fuchsia/koid_utilities.h"
 
 #include <fuchsia/sysinfo/c/fidl.h>
-#include <lib/fdio/util.h>
+#include <lib/fdio/fdio.h>
 #include <lib/zx/channel.h>
 #include <lib/zx/job.h>
 #include <lib/zx/process.h>
diff --git a/third_party/crashpad/crashpad/util/posix/scoped_mmap.cc b/third_party/crashpad/crashpad/util/posix/scoped_mmap.cc
index 0965fd67..fbf47fae 100644
--- a/third_party/crashpad/crashpad/util/posix/scoped_mmap.cc
+++ b/third_party/crashpad/crashpad/util/posix/scoped_mmap.cc
@@ -33,6 +33,11 @@
   return true;
 }
 
+size_t RoundPage(size_t size) {
+  const size_t kPageMask = base::checked_cast<size_t>(getpagesize()) - 1;
+  return (size + kPageMask) & ~kPageMask;
+}
+
 }  // namespace
 
 namespace crashpad {
@@ -41,7 +46,7 @@
 
 ScopedMmap::~ScopedMmap() {
   if (is_valid()) {
-    Munmap(reinterpret_cast<uintptr_t>(addr_), len_);
+    Munmap(reinterpret_cast<uintptr_t>(addr_), RoundPage(len_));
   }
 }
 
@@ -51,29 +56,28 @@
 
 bool ScopedMmap::ResetAddrLen(void* addr, size_t len) {
   const uintptr_t new_addr = reinterpret_cast<uintptr_t>(addr);
+  const size_t new_len_round = RoundPage(len);
 
   if (addr == MAP_FAILED) {
     DCHECK_EQ(len, 0u);
   } else {
-    // Round |len| up to the next page.
-    const size_t kPageMask = base::checked_cast<size_t>(getpagesize()) - 1;
-    len = (len + kPageMask) & ~kPageMask;
-
     DCHECK_NE(len, 0u);
     DCHECK_EQ(new_addr % getpagesize(), 0u);
-    DCHECK((base::CheckedNumeric<uintptr_t>(new_addr) + (len - 1)).IsValid());
+    DCHECK((base::CheckedNumeric<uintptr_t>(new_addr) + (new_len_round - 1))
+               .IsValid());
   }
 
   bool result = true;
 
   if (is_valid()) {
     const uintptr_t old_addr = reinterpret_cast<uintptr_t>(addr_);
+    const size_t old_len_round = RoundPage(len_);
     if (old_addr < new_addr) {
-      result &= Munmap(old_addr, std::min(len_, new_addr - old_addr));
+      result &= Munmap(old_addr, std::min(old_len_round, new_addr - old_addr));
     }
-    if (old_addr + len_ > new_addr + len) {
-      uintptr_t unmap_start = std::max(old_addr, new_addr + len);
-      result &= Munmap(unmap_start, old_addr + len_ - unmap_start);
+    if (old_addr + old_len_round > new_addr + new_len_round) {
+      uintptr_t unmap_start = std::max(old_addr, new_addr + new_len_round);
+      result &= Munmap(unmap_start, old_addr + old_len_round - unmap_start);
     }
   }
 
@@ -108,7 +112,7 @@
 }
 
 bool ScopedMmap::Mprotect(int prot) {
-  if (mprotect(addr_, len_, prot) < 0) {
+  if (mprotect(addr_, RoundPage(len_), prot) < 0) {
     PLOG(ERROR) << "mprotect";
     return false;
   }
diff --git a/third_party/crashpad/crashpad/util/posix/scoped_mmap.h b/third_party/crashpad/crashpad/util/posix/scoped_mmap.h
index b0ff3dc..9f22372b 100644
--- a/third_party/crashpad/crashpad/util/posix/scoped_mmap.h
+++ b/third_party/crashpad/crashpad/util/posix/scoped_mmap.h
@@ -91,6 +91,11 @@
   }
 
   //! \brief Returns the size of the memory-mapped region.
+  //!
+  //! This is the value originally passed to ResetAddrLen() or ResetMmap(), or
+  //! after Reset(), `0`. It may not be a round number of pages. Providing the
+  //! passed-in value is intended to ease tracking the intended lengths of
+  //! memory-mapped regions backed by files whose sizes are not whole pages.
   size_t len() const { return len_; }
 
  private:
diff --git a/third_party/crashpad/crashpad/util/posix/scoped_mmap_test.cc b/third_party/crashpad/crashpad/util/posix/scoped_mmap_test.cc
index e32fa159..5279fdb 100644
--- a/third_party/crashpad/crashpad/util/posix/scoped_mmap_test.cc
+++ b/third_party/crashpad/crashpad/util/posix/scoped_mmap_test.cc
@@ -309,7 +309,7 @@
   ASSERT_TRUE(ScopedMmapResetMmap(&mapping, kHalfPageSize));
   EXPECT_TRUE(mapping.is_valid());
   EXPECT_NE(mapping.addr(), MAP_FAILED);
-  EXPECT_EQ(mapping.len(), kPageSize);
+  EXPECT_EQ(mapping.len(), kHalfPageSize);
 
   TestCookie cookie;
   cookie.SetUp(mapping.addr_as<uint64_t*>());
@@ -319,7 +319,7 @@
   ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, kHalfPageSize));
   EXPECT_TRUE(mapping.is_valid());
   EXPECT_EQ(mapping.addr(), orig_addr);
-  EXPECT_EQ(mapping.len(), kPageSize);
+  EXPECT_EQ(mapping.len(), kHalfPageSize);
 
   EXPECT_EQ(cookie.Observed(), cookie.Expected());
 
@@ -328,14 +328,14 @@
   ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, 1));
   EXPECT_TRUE(mapping.is_valid());
   EXPECT_EQ(mapping.addr(), orig_addr);
-  EXPECT_EQ(mapping.len(), kPageSize);
+  EXPECT_EQ(mapping.len(), 1u);
 
   EXPECT_EQ(cookie.Observed(), cookie.Expected());
 
   ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, kPageSize - 1));
   EXPECT_TRUE(mapping.is_valid());
   EXPECT_EQ(mapping.addr(), orig_addr);
-  EXPECT_EQ(mapping.len(), kPageSize);
+  EXPECT_EQ(mapping.len(), kPageSize - 1);
 
   EXPECT_EQ(cookie.Observed(), cookie.Expected());
 
@@ -356,7 +356,7 @@
   ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, kHalfPageSize));
   EXPECT_TRUE(mapping.is_valid());
   EXPECT_EQ(mapping.addr(), orig_addr);
-  EXPECT_EQ(mapping.len(), kPageSize);
+  EXPECT_EQ(mapping.len(), kHalfPageSize);
 
   EXPECT_EQ(two_cookies[0].Observed(), two_cookies[0].Expected());
   EXPECT_DEATH_CRASH(two_cookies[1].Check(), "");
@@ -376,7 +376,7 @@
   ASSERT_TRUE(mapping.ResetAddrLen(orig_addr, kPageSize + kHalfPageSize));
   EXPECT_TRUE(mapping.is_valid());
   EXPECT_EQ(mapping.addr(), orig_addr);
-  EXPECT_EQ(mapping.len(), 2 * kPageSize);
+  EXPECT_EQ(mapping.len(), kPageSize + kHalfPageSize);
 
   EXPECT_EQ(two_cookies[0].Observed(), two_cookies[0].Expected());
   EXPECT_EQ(two_cookies[1].Observed(), two_cookies[1].Expected());
diff --git a/third_party/inspector_protocol/BUILD.gn b/third_party/inspector_protocol/BUILD.gn
index 0cf1a98..ddbe626 100644
--- a/third_party/inspector_protocol/BUILD.gn
+++ b/third_party/inspector_protocol/BUILD.gn
@@ -2,109 +2,15 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# All build targets below are experimental and not used within the
-# Chromium / V8 / etc. trees yet thus far. Do not depend on anything.
-
-import("//testing/test.gni")
-
-static_library("json_parser") {
+static_library("encoding") {
   sources = [
-    "encoding/json_parser.cc",
-    "encoding/json_parser.h",
-    "encoding/json_parser_handler.h",
-    "encoding/platform.h",
-    "encoding/span.h",
-    "encoding/status.h",
-    "encoding/str_util.cc",
-    "encoding/str_util.h",
+    "encoding/encoding.cc",
+    "encoding/encoding.h",
   ]
 }
 
-static_library("linux_dev_platform") {
-  sources = [
-    "encoding/linux_dev_platform.cc",
-    "encoding/linux_dev_platform.h",
-    "encoding/platform.h",
-  ]
-}
+# encoding/encoding_test.cc:
+# There's no target for this file here, instead it is included
+# in //content/test:content_unittest
+# via //content/browser/devtools:inspector_protocol_encoding_test.
 
-test("json_parser_test") {
-  sources = [
-    "encoding/json_parser_test.cc",
-  ]
-  deps = [
-    ":json_parser",
-    ":linux_dev_platform",
-    "//base",
-    "//third_party/googletest:gmock",
-    "//third_party/googletest:gtest",
-    "//third_party/googletest:gtest_main",
-  ]
-}
-
-static_library("cbor") {
-  sources = [
-    "encoding/cbor.cc",
-    "encoding/cbor.h",
-    "encoding/json_parser_handler.h",
-    "encoding/span.h",
-    "encoding/status.h",
-  ]
-  deps = [
-    ":json_parser",
-  ]
-}
-
-test("cbor_test") {
-  sources = [
-    "encoding/cbor_test.cc",
-  ]
-  deps = [
-    ":cbor",
-    ":json_parser",
-    ":json_std_string_writer",
-    ":linux_dev_platform",
-    "//base",
-    "//third_party/googletest:gmock",
-    "//third_party/googletest:gtest",
-    "//third_party/googletest:gtest_main",
-  ]
-}
-
-test("span_test") {
-  sources = [
-    "encoding/span.h",
-    "encoding/span_test.cc",
-  ]
-  deps = [
-    "//base",
-    "//third_party/googletest:gmock",
-    "//third_party/googletest:gtest",
-    "//third_party/googletest:gtest_main",
-  ]
-}
-
-static_library("json_std_string_writer") {
-  sources = [
-    "encoding/json_parser_handler.h",
-    "encoding/json_std_string_writer.cc",
-    "encoding/json_std_string_writer.h",
-    "encoding/platform.h",
-    "encoding/span.h",
-    "encoding/status.h",
-  ]
-}
-
-test("json_std_string_writer_test") {
-  sources = [
-    "encoding/json_std_string_writer_test.cc",
-  ]
-  deps = [
-    ":json_std_string_writer",
-    ":linux_dev_platform",
-    "//base",
-    "//third_party/googletest:gmock",
-    "//third_party/googletest:gtest",
-    "//third_party/googletest:gtest_main",
-  ]
-}
diff --git a/third_party/inspector_protocol/DEPS b/third_party/inspector_protocol/DEPS
index 81c9b082..20785c0 100644
--- a/third_party/inspector_protocol/DEPS
+++ b/third_party/inspector_protocol/DEPS
@@ -6,7 +6,7 @@
 specific_include_rules = {
   '^.*_test\.cc$': [
     '+base',
-    '+gmock',
-    '+gtest',
+    '+testing/gtest/include',
+    '+testing/gmock/include',
   ],
 }
diff --git a/third_party/inspector_protocol/README.chromium b/third_party/inspector_protocol/README.chromium
index 89f754b6..d8349fb4 100644
--- a/third_party/inspector_protocol/README.chromium
+++ b/third_party/inspector_protocol/README.chromium
@@ -2,7 +2,7 @@
 Short Name: inspector_protocol
 URL: https://chromium.googlesource.com/deps/inspector_protocol/
 Version: 0
-Revision: be5f927f77f7d4670a02f16ed026db0a3768980a
+Revision: 1e65f2e3a9759b799ca3a87a41dcc9f58fdd720f
 License: BSD
 License File: LICENSE
 Security Critical: no
diff --git a/third_party/inspector_protocol/code_generator.py b/third_party/inspector_protocol/code_generator.py
index fb9959d..18777d0f 100755
--- a/third_party/inspector_protocol/code_generator.py
+++ b/third_party/inspector_protocol/code_generator.py
@@ -632,7 +632,7 @@
             "Array_h.template",
             "DispatcherBase_h.template",
             "Parser_h.template",
-            "CBOR_h.template",
+            "encoding_h.template",
         ]
 
         protocol_cpp_templates = [
@@ -642,7 +642,7 @@
             "Object_cpp.template",
             "DispatcherBase_cpp.template",
             "Parser_cpp.template",
-            "CBOR_cpp.template",
+            "encoding_cpp.template",
         ]
 
         forward_h_templates = [
diff --git a/third_party/inspector_protocol/encoding/cbor.cc b/third_party/inspector_protocol/encoding/cbor.cc
deleted file mode 100644
index f771f5b..0000000
--- a/third_party/inspector_protocol/encoding/cbor.cc
+++ /dev/null
@@ -1,821 +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 "cbor.h"
-
-#include <cassert>
-#include <limits>
-#include "json_parser_handler.h"
-
-namespace inspector_protocol {
-using namespace cbor;
-
-namespace {
-
-// See RFC 7049 Section 2.3, Table 2.
-static constexpr uint8_t kEncodedTrue =
-    EncodeInitialByte(MajorType::SIMPLE_VALUE, 21);
-static constexpr uint8_t kEncodedFalse =
-    EncodeInitialByte(MajorType::SIMPLE_VALUE, 20);
-static constexpr uint8_t kEncodedNull =
-    EncodeInitialByte(MajorType::SIMPLE_VALUE, 22);
-static constexpr uint8_t kInitialByteForDouble =
-    EncodeInitialByte(MajorType::SIMPLE_VALUE, 27);
-
-}  // namespace
-
-uint8_t EncodeTrue() { return kEncodedTrue; }
-uint8_t EncodeFalse() { return kEncodedFalse; }
-uint8_t EncodeNull() { return kEncodedNull; }
-
-uint8_t EncodeIndefiniteLengthArrayStart() {
-  return kInitialByteIndefiniteLengthArray;
-}
-
-uint8_t EncodeIndefiniteLengthMapStart() {
-  return kInitialByteIndefiniteLengthMap;
-}
-
-uint8_t EncodeStop() { return kStopByte; }
-
-namespace {
-// See RFC 7049 Table 3 and Section 2.4.4.2. This is used as a prefix for
-// arbitrary binary data encoded as BYTE_STRING.
-static constexpr uint8_t kExpectedConversionToBase64Tag =
-    EncodeInitialByte(MajorType::TAG, 22);
-
-// When parsing CBOR, we limit recursion depth for objects and arrays
-// to this constant.
-static constexpr int kStackLimit = 1000;
-
-// Writes the bytes for |v| to |out|, starting with the most significant byte.
-// See also: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
-template <typename T>
-void WriteBytesMostSignificantByteFirst(T v, std::vector<uint8_t>* out) {
-  for (int shift_bytes = sizeof(T) - 1; shift_bytes >= 0; --shift_bytes)
-    out->push_back(0xff & (v >> (shift_bytes * 8)));
-}
-}  // namespace
-
-namespace cbor_internals {
-// Writes the start of a token with |type|. The |value| may indicate the size,
-// or it may be the payload if the value is an unsigned integer.
-void WriteTokenStart(MajorType type, uint64_t value,
-                     std::vector<uint8_t>* encoded) {
-  if (value < 24) {
-    // Values 0-23 are encoded directly into the additional info of the
-    // initial byte.
-    encoded->push_back(EncodeInitialByte(type, /*additional_info=*/value));
-    return;
-  }
-  if (value <= std::numeric_limits<uint8_t>::max()) {
-    // Values 24-255 are encoded with one initial byte, followed by the value.
-    encoded->push_back(EncodeInitialByte(type, kAdditionalInformation1Byte));
-    encoded->push_back(value);
-    return;
-  }
-  if (value <= std::numeric_limits<uint16_t>::max()) {
-    // Values 256-65535: 1 initial byte + 2 bytes payload.
-    encoded->push_back(EncodeInitialByte(type, kAdditionalInformation2Bytes));
-    WriteBytesMostSignificantByteFirst<uint16_t>(value, encoded);
-    return;
-  }
-  if (value <= std::numeric_limits<uint32_t>::max()) {
-    // 32 bit uint: 1 initial byte + 4 bytes payload.
-    encoded->push_back(EncodeInitialByte(type, kAdditionalInformation4Bytes));
-    WriteBytesMostSignificantByteFirst<uint32_t>(static_cast<uint32_t>(value),
-                                                 encoded);
-    return;
-  }
-  // 64 bit uint: 1 initial byte + 8 bytes payload.
-  encoded->push_back(EncodeInitialByte(type, kAdditionalInformation8Bytes));
-  WriteBytesMostSignificantByteFirst<uint64_t>(value, encoded);
-}
-}  // namespace cbor_internals
-
-namespace {
-// Extracts sizeof(T) bytes from |in| to extract a value of type T
-// (e.g. uint64_t, uint32_t, ...), most significant byte first.
-// See also: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
-template <typename T>
-T ReadBytesMostSignificantByteFirst(span<uint8_t> in) {
-  assert(static_cast<std::size_t>(in.size()) >= sizeof(T));
-  T result = 0;
-  for (std::size_t shift_bytes = 0; shift_bytes < sizeof(T); ++shift_bytes)
-    result |= T(in[sizeof(T) - 1 - shift_bytes]) << (shift_bytes * 8);
-  return result;
-}
-}  // namespace
-
-namespace cbor_internals {
-int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value) {
-  if (bytes.empty()) return -1;
-  uint8_t initial_byte = bytes[0];
-  *type = MajorType((initial_byte & kMajorTypeMask) >> kMajorTypeBitShift);
-
-  uint8_t additional_information = initial_byte & kAdditionalInformationMask;
-  if (additional_information < 24) {
-    // Values 0-23 are encoded directly into the additional info of the
-    // initial byte.
-    *value = additional_information;
-    return 1;
-  }
-  if (additional_information == kAdditionalInformation1Byte) {
-    // Values 24-255 are encoded with one initial byte, followed by the value.
-    if (bytes.size() < 2) return -1;
-    *value = ReadBytesMostSignificantByteFirst<uint8_t>(bytes.subspan(1));
-    return 2;
-  }
-  if (additional_information == kAdditionalInformation2Bytes) {
-    // Values 256-65535: 1 initial byte + 2 bytes payload.
-    if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint16_t))
-      return -1;
-    *value = ReadBytesMostSignificantByteFirst<uint16_t>(bytes.subspan(1));
-    return 3;
-  }
-  if (additional_information == kAdditionalInformation4Bytes) {
-    // 32 bit uint: 1 initial byte + 4 bytes payload.
-    if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint32_t))
-      return -1;
-    *value = ReadBytesMostSignificantByteFirst<uint32_t>(bytes.subspan(1));
-    return 5;
-  }
-  if (additional_information == kAdditionalInformation8Bytes) {
-    // 64 bit uint: 1 initial byte + 8 bytes payload.
-    if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint64_t))
-      return -1;
-    *value = ReadBytesMostSignificantByteFirst<uint64_t>(bytes.subspan(1));
-    return 9;
-  }
-  return -1;
-}
-}  // namespace cbor_internals
-
-using cbor_internals::WriteTokenStart;
-using cbor_internals::ReadTokenStart;
-
-void EncodeInt32(int32_t value, std::vector<uint8_t>* out) {
-  if (value >= 0) {
-    WriteTokenStart(MajorType::UNSIGNED, value, out);
-  } else {
-    uint64_t representation = static_cast<uint64_t>(-(value + 1));
-    WriteTokenStart(MajorType::NEGATIVE, representation, out);
-  }
-}
-
-void EncodeString16(span<uint16_t> in, std::vector<uint8_t>* out) {
-  uint64_t byte_length = static_cast<uint64_t>(in.size_bytes());
-  WriteTokenStart(MajorType::BYTE_STRING, byte_length, out);
-  // When emitting UTF16 characters, we always write the least significant byte
-  // first; this is because it's the native representation for X86.
-  // TODO(johannes): Implement a more efficient thing here later, e.g.
-  // casting *iff* the machine has this byte order.
-  // The wire format for UTF16 chars will probably remain the same
-  // (least significant byte first) since this way we can have
-  // golden files, unittests, etc. that port easily and universally.
-  // See also:
-  // https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
-  for (const uint16_t two_bytes : in) {
-    out->push_back(two_bytes);
-    out->push_back(two_bytes >> 8);
-  }
-}
-
-void EncodeString8(span<uint8_t> in, std::vector<uint8_t>* out) {
-  WriteTokenStart(MajorType::STRING, static_cast<uint64_t>(in.size_bytes()),
-                  out);
-  out->insert(out->end(), in.begin(), in.end());
-}
-
-void EncodeFromLatin1(span<uint8_t> latin1, std::vector<uint8_t>* out) {
-  for (std::ptrdiff_t ii = 0; ii < latin1.size(); ++ii) {
-    if (latin1[ii] <= 127)
-      continue;
-    // If there's at least one non-ASCII char, convert to UTF8.
-    std::vector<uint8_t> utf8(latin1.begin(), latin1.begin() + ii);
-    for (; ii < latin1.size(); ++ii) {
-      if (latin1[ii] <= 127) {
-        utf8.push_back(latin1[ii]);
-      } else {
-        // 0xC0 means it's a UTF8 sequence with 2 bytes.
-        utf8.push_back((latin1[ii] >> 6) | 0xc0);
-        utf8.push_back((latin1[ii] | 0x80) & 0xbf);
-      }
-    }
-    EncodeString8(span<uint8_t>(utf8.data(), utf8.size()), out);
-    return;
-  }
-  EncodeString8(latin1, out);
-}
-
-void EncodeFromUTF16(span<uint16_t> utf16, std::vector<uint8_t>* out) {
-  // If there's at least one non-ASCII char, encode as STRING16 (UTF16).
-  for (uint16_t ch : utf16) {
-    if (ch <= 127)
-      continue;
-    EncodeString16(utf16, out);
-    return;
-  }
-  // It's all US-ASCII, strip out every second byte and encode as UTF8.
-  WriteTokenStart(MajorType::STRING, static_cast<uint64_t>(utf16.size()), out);
-  out->insert(out->end(), utf16.begin(), utf16.end());
-}
-
-void EncodeBinary(span<uint8_t> in, std::vector<uint8_t>* out) {
-  out->push_back(kExpectedConversionToBase64Tag);
-  uint64_t byte_length = static_cast<uint64_t>(in.size_bytes());
-  WriteTokenStart(MajorType::BYTE_STRING, byte_length, out);
-  out->insert(out->end(), in.begin(), in.end());
-}
-
-// A double is encoded with a specific initial byte
-// (kInitialByteForDouble) plus the 64 bits of payload for its value.
-constexpr std::ptrdiff_t kEncodedDoubleSize = 1 + sizeof(uint64_t);
-
-// An envelope is encoded with a specific initial byte
-// (kInitialByteForEnvelope), plus the start byte for a BYTE_STRING with a 32
-// bit wide length, plus a 32 bit length for that string.
-constexpr std::ptrdiff_t kEncodedEnvelopeHeaderSize = 1 + 1 + sizeof(uint32_t);
-
-void EncodeDouble(double value, std::vector<uint8_t>* out) {
-  // The additional_info=27 indicates 64 bits for the double follow.
-  // See RFC 7049 Section 2.3, Table 1.
-  out->push_back(kInitialByteForDouble);
-  union {
-    double from_double;
-    uint64_t to_uint64;
-  } reinterpret;
-  reinterpret.from_double = value;
-  WriteBytesMostSignificantByteFirst<uint64_t>(reinterpret.to_uint64, out);
-}
-
-void EnvelopeEncoder::EncodeStart(std::vector<uint8_t>* out) {
-  assert(byte_size_pos_ == 0);
-  out->push_back(kInitialByteForEnvelope);
-  out->push_back(kInitialByteFor32BitLengthByteString);
-  byte_size_pos_ = out->size();
-  out->resize(out->size() + sizeof(uint32_t));
-}
-
-bool EnvelopeEncoder::EncodeStop(std::vector<uint8_t>* out) {
-  assert(byte_size_pos_ != 0);
-  // The byte size is the size of the payload, that is, all the
-  // bytes that were written past the byte size position itself.
-  uint64_t byte_size = out->size() - (byte_size_pos_ + sizeof(uint32_t));
-  // We store exactly 4 bytes, so at most INT32MAX, with most significant
-  // byte first.
-  if (byte_size > std::numeric_limits<uint32_t>::max()) return false;
-  for (int shift_bytes = sizeof(uint32_t) - 1; shift_bytes >= 0;
-       --shift_bytes) {
-    (*out)[byte_size_pos_++] = 0xff & (byte_size >> (shift_bytes * 8));
-  }
-  return true;
-}
-
-namespace {
-class JSONToCBOREncoder : public JSONParserHandler {
- public:
-  JSONToCBOREncoder(std::vector<uint8_t>* out, Status* status)
-      : out_(out), status_(status) {
-    *status_ = Status();
-  }
-
-  void HandleObjectBegin() override {
-    envelopes_.emplace_back();
-    envelopes_.back().EncodeStart(out_);
-    out_->push_back(kInitialByteIndefiniteLengthMap);
-  }
-
-  void HandleObjectEnd() override {
-    out_->push_back(kStopByte);
-    assert(!envelopes_.empty());
-    envelopes_.back().EncodeStop(out_);
-    envelopes_.pop_back();
-  }
-
-  void HandleArrayBegin() override {
-    envelopes_.emplace_back();
-    envelopes_.back().EncodeStart(out_);
-    out_->push_back(kInitialByteIndefiniteLengthArray);
-  }
-
-  void HandleArrayEnd() override {
-    out_->push_back(kStopByte);
-    assert(!envelopes_.empty());
-    envelopes_.back().EncodeStop(out_);
-    envelopes_.pop_back();
-  }
-
-  void HandleString8(span<uint8_t> chars) override {
-    EncodeString8(chars, out_);
-  }
-
-  void HandleString16(span<uint16_t> chars) override {
-    for (uint16_t ch : chars) {
-      if (ch >= 0x7f) {
-        // If there's at least one non-7bit character, we encode as UTF16.
-        EncodeString16(chars, out_);
-        return;
-      }
-    }
-    std::vector<uint8_t> sevenbit_chars(chars.begin(), chars.end());
-    EncodeString8(span<uint8_t>(sevenbit_chars.data(), sevenbit_chars.size()),
-                  out_);
-  }
-
-  void HandleBinary(std::vector<uint8_t> bytes) override {
-    EncodeBinary(span<uint8_t>(bytes.data(), bytes.size()), out_);
-  }
-
-  void HandleDouble(double value) override { EncodeDouble(value, out_); }
-
-  void HandleInt32(int32_t value) override { EncodeInt32(value, out_); }
-
-  void HandleBool(bool value) override {
-    // See RFC 7049 Section 2.3, Table 2.
-    out_->push_back(value ? kEncodedTrue : kEncodedFalse);
-  }
-
-  void HandleNull() override {
-    // See RFC 7049 Section 2.3, Table 2.
-    out_->push_back(kEncodedNull);
-  }
-
-  void HandleError(Status error) override {
-    assert(!error.ok());
-    *status_ = error;
-    out_->clear();
-  }
-
- private:
-  std::vector<uint8_t>* out_;
-  std::vector<EnvelopeEncoder> envelopes_;
-  Status* status_;
-};
-}  // namespace
-
-std::unique_ptr<JSONParserHandler> NewJSONToCBOREncoder(
-    std::vector<uint8_t>* out, Status* status) {
-  return std::unique_ptr<JSONParserHandler>(new JSONToCBOREncoder(out, status));
-}
-
-namespace {
-// Below are three parsing routines for CBOR, which cover enough
-// to roundtrip JSON messages.
-bool ParseMap(int32_t stack_depth, CBORTokenizer* tokenizer,
-              JSONParserHandler* out);
-bool ParseArray(int32_t stack_depth, CBORTokenizer* tokenizer,
-                JSONParserHandler* out);
-bool ParseValue(int32_t stack_depth, CBORTokenizer* tokenizer,
-                JSONParserHandler* out);
-
-void ParseUTF16String(CBORTokenizer* tokenizer, JSONParserHandler* out) {
-  std::vector<uint16_t> value;
-  span<uint8_t> rep = tokenizer->GetString16WireRep();
-  for (std::ptrdiff_t ii = 0; ii < rep.size(); ii += 2)
-    value.push_back((rep[ii + 1] << 8) | rep[ii]);
-  out->HandleString16(span<uint16_t>(value.data(), value.size()));
-  tokenizer->Next();
-}
-
-bool ParseUTF8String(CBORTokenizer* tokenizer, JSONParserHandler* out) {
-  assert(tokenizer->TokenTag() == CBORTokenTag::STRING8);
-  out->HandleString8(tokenizer->GetString8());
-  tokenizer->Next();
-  return true;
-}
-
-bool ParseValue(int32_t stack_depth, CBORTokenizer* tokenizer,
-                JSONParserHandler* out) {
-  if (stack_depth > kStackLimit) {
-    out->HandleError(
-        Status{Error::CBOR_STACK_LIMIT_EXCEEDED, tokenizer->Status().pos});
-    return false;
-  }
-  // Skip past the envelope to get to what's inside.
-  if (tokenizer->TokenTag() == CBORTokenTag::ENVELOPE)
-    tokenizer->EnterEnvelope();
-  switch (tokenizer->TokenTag()) {
-    case CBORTokenTag::ERROR_VALUE:
-      out->HandleError(tokenizer->Status());
-      return false;
-    case CBORTokenTag::DONE:
-      out->HandleError(Status{Error::CBOR_UNEXPECTED_EOF_EXPECTED_VALUE,
-                              tokenizer->Status().pos});
-      return false;
-    case CBORTokenTag::TRUE_VALUE:
-      out->HandleBool(true);
-      tokenizer->Next();
-      return true;
-    case CBORTokenTag::FALSE_VALUE:
-      out->HandleBool(false);
-      tokenizer->Next();
-      return true;
-    case CBORTokenTag::NULL_VALUE:
-      out->HandleNull();
-      tokenizer->Next();
-      return true;
-    case CBORTokenTag::INT32:
-      out->HandleInt32(tokenizer->GetInt32());
-      tokenizer->Next();
-      return true;
-    case CBORTokenTag::DOUBLE:
-      out->HandleDouble(tokenizer->GetDouble());
-      tokenizer->Next();
-      return true;
-    case CBORTokenTag::STRING8:
-      return ParseUTF8String(tokenizer, out);
-    case CBORTokenTag::STRING16:
-      ParseUTF16String(tokenizer, out);
-      return true;
-    case CBORTokenTag::BINARY: {
-      span<uint8_t> binary = tokenizer->GetBinary();
-      out->HandleBinary(std::vector<uint8_t>(binary.begin(), binary.end()));
-      tokenizer->Next();
-      return true;
-    }
-    case CBORTokenTag::MAP_START:
-      return ParseMap(stack_depth + 1, tokenizer, out);
-    case CBORTokenTag::ARRAY_START:
-      return ParseArray(stack_depth + 1, tokenizer, out);
-    default:
-      out->HandleError(
-          Status{Error::CBOR_UNSUPPORTED_VALUE, tokenizer->Status().pos});
-      return false;
-  }
-}
-
-// |bytes| must start with the indefinite length array byte, so basically,
-// ParseArray may only be called after an indefinite length array has been
-// detected.
-bool ParseArray(int32_t stack_depth, CBORTokenizer* tokenizer,
-                JSONParserHandler* out) {
-  assert(tokenizer->TokenTag() == CBORTokenTag::ARRAY_START);
-  tokenizer->Next();
-  out->HandleArrayBegin();
-  while (tokenizer->TokenTag() != CBORTokenTag::STOP) {
-    if (tokenizer->TokenTag() == CBORTokenTag::DONE) {
-      out->HandleError(
-          Status{Error::CBOR_UNEXPECTED_EOF_IN_ARRAY, tokenizer->Status().pos});
-      return false;
-    }
-    if (tokenizer->TokenTag() == CBORTokenTag::ERROR_VALUE) {
-      out->HandleError(tokenizer->Status());
-      return false;
-    }
-    // Parse value.
-    if (!ParseValue(stack_depth, tokenizer, out)) return false;
-  }
-  out->HandleArrayEnd();
-  tokenizer->Next();
-  return true;
-}
-
-// |bytes| must start with the indefinite length array byte, so basically,
-// ParseArray may only be called after an indefinite length array has been
-// detected.
-bool ParseMap(int32_t stack_depth, CBORTokenizer* tokenizer,
-              JSONParserHandler* out) {
-  assert(tokenizer->TokenTag() == CBORTokenTag::MAP_START);
-  out->HandleObjectBegin();
-  tokenizer->Next();
-  while (tokenizer->TokenTag() != CBORTokenTag::STOP) {
-    if (tokenizer->TokenTag() == CBORTokenTag::DONE) {
-      out->HandleError(
-          Status{Error::CBOR_UNEXPECTED_EOF_IN_MAP, tokenizer->Status().pos});
-      return false;
-    }
-    if (tokenizer->TokenTag() == CBORTokenTag::ERROR_VALUE) {
-      out->HandleError(tokenizer->Status());
-      return false;
-    }
-    // Parse key.
-    if (tokenizer->TokenTag() == CBORTokenTag::STRING8) {
-      if (!ParseUTF8String(tokenizer, out))
-        return false;
-    } else if (tokenizer->TokenTag() == CBORTokenTag::STRING16) {
-      ParseUTF16String(tokenizer, out);
-    } else {
-      out->HandleError(
-          Status{Error::CBOR_INVALID_MAP_KEY, tokenizer->Status().pos});
-      return false;
-    }
-    // Parse value.
-    if (!ParseValue(stack_depth, tokenizer, out)) return false;
-  }
-  out->HandleObjectEnd();
-  tokenizer->Next();
-  return true;
-}
-}  // namespace
-
-void ParseCBOR(span<uint8_t> bytes, JSONParserHandler* json_out) {
-  if (bytes.empty()) {
-    json_out->HandleError(Status{Error::CBOR_NO_INPUT, 0});
-    return;
-  }
-  if (bytes[0] != kInitialByteForEnvelope) {
-    json_out->HandleError(Status{Error::CBOR_INVALID_START_BYTE, 0});
-    return;
-  }
-  CBORTokenizer tokenizer(bytes);
-  if (tokenizer.TokenTag() == CBORTokenTag::ERROR_VALUE) {
-    json_out->HandleError(tokenizer.Status());
-    return;
-  }
-  // We checked for the envelope start byte above, so the tokenizer
-  // must agree here, since it's not an error.
-  assert(tokenizer.TokenTag() == CBORTokenTag::ENVELOPE);
-  tokenizer.EnterEnvelope();
-  if (tokenizer.TokenTag() != CBORTokenTag::MAP_START) {
-    json_out->HandleError(
-        Status{Error::CBOR_MAP_START_EXPECTED, tokenizer.Status().pos});
-    return;
-  }
-  if (!ParseMap(/*stack_depth=*/1, &tokenizer, json_out)) return;
-  if (tokenizer.TokenTag() == CBORTokenTag::DONE) return;
-  if (tokenizer.TokenTag() == CBORTokenTag::ERROR_VALUE) {
-    json_out->HandleError(tokenizer.Status());
-    return;
-  }
-  json_out->HandleError(
-      Status{Error::CBOR_TRAILING_JUNK, tokenizer.Status().pos});
-}
-
-CBORTokenizer::CBORTokenizer(span<uint8_t> bytes) : bytes_(bytes) {
-  ReadNextToken(/*enter_envelope=*/false);
-}
-CBORTokenizer::~CBORTokenizer() {}
-
-CBORTokenTag CBORTokenizer::TokenTag() const { return token_tag_; }
-
-void CBORTokenizer::Next() {
-  if (token_tag_ == CBORTokenTag::ERROR_VALUE || token_tag_ == CBORTokenTag::DONE)
-    return;
-  ReadNextToken(/*enter_envelope=*/false);
-}
-
-void CBORTokenizer::EnterEnvelope() {
-  assert(token_tag_ == CBORTokenTag::ENVELOPE);
-  ReadNextToken(/*enter_envelope=*/true);
-}
-
-Status CBORTokenizer::Status() const { return status_; }
-
-int32_t CBORTokenizer::GetInt32() const {
-  assert(token_tag_ == CBORTokenTag::INT32);
-  // The range checks happen in ::ReadNextToken().
-  return static_cast<uint32_t>(
-      token_start_type_ == MajorType::UNSIGNED
-          ? token_start_internal_value_
-          : -static_cast<int64_t>(token_start_internal_value_) - 1);
-}
-
-double CBORTokenizer::GetDouble() const {
-  assert(token_tag_ == CBORTokenTag::DOUBLE);
-  union {
-    uint64_t from_uint64;
-    double to_double;
-  } reinterpret;
-  reinterpret.from_uint64 = ReadBytesMostSignificantByteFirst<uint64_t>(
-      bytes_.subspan(status_.pos + 1));
-  return reinterpret.to_double;
-}
-
-span<uint8_t> CBORTokenizer::GetString8() const {
-  assert(token_tag_ == CBORTokenTag::STRING8);
-  auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
-  return bytes_.subspan(status_.pos + (token_byte_length_ - length), length);
-}
-
-span<uint8_t> CBORTokenizer::GetString16WireRep() const {
-  assert(token_tag_ == CBORTokenTag::STRING16);
-  auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
-  return bytes_.subspan(status_.pos + (token_byte_length_ - length), length);
-}
-
-span<uint8_t> CBORTokenizer::GetBinary() const {
-  assert(token_tag_ == CBORTokenTag::BINARY);
-  auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
-  return bytes_.subspan(status_.pos + (token_byte_length_ - length), length);
-}
-
-void CBORTokenizer::ReadNextToken(bool enter_envelope) {
-  if (enter_envelope) {
-    status_.pos += kEncodedEnvelopeHeaderSize;
-  } else {
-    status_.pos =
-        status_.pos == Status::npos() ? 0 : status_.pos + token_byte_length_;
-  }
-  status_.error = Error::OK;
-  if (status_.pos >= bytes_.size()) {
-    token_tag_ = CBORTokenTag::DONE;
-    return;
-  }
-  switch (bytes_[status_.pos]) {
-    case kStopByte:
-      SetToken(CBORTokenTag::STOP, 1);
-      return;
-    case kInitialByteIndefiniteLengthMap:
-      SetToken(CBORTokenTag::MAP_START, 1);
-      return;
-    case kInitialByteIndefiniteLengthArray:
-      SetToken(CBORTokenTag::ARRAY_START, 1);
-      return;
-    case kEncodedTrue:
-      SetToken(CBORTokenTag::TRUE_VALUE, 1);
-      return;
-    case kEncodedFalse:
-      SetToken(CBORTokenTag::FALSE_VALUE, 1);
-      return;
-    case kEncodedNull:
-      SetToken(CBORTokenTag::NULL_VALUE, 1);
-      return;
-    case kExpectedConversionToBase64Tag: {  // BINARY
-      int8_t bytes_read =
-          ReadTokenStart(bytes_.subspan(status_.pos + 1), &token_start_type_,
-                         &token_start_internal_value_);
-      int64_t token_byte_length = 1 + bytes_read + token_start_internal_value_;
-      if (-1 == bytes_read || token_start_type_ != MajorType::BYTE_STRING ||
-          status_.pos + token_byte_length > bytes_.size()) {
-        SetError(Error::CBOR_INVALID_BINARY);
-        return;
-      }
-      SetToken(CBORTokenTag::BINARY,
-               static_cast<std::ptrdiff_t>(token_byte_length));
-      return;
-    }
-    case kInitialByteForDouble: {  // DOUBLE
-      if (status_.pos + kEncodedDoubleSize > bytes_.size()) {
-        SetError(Error::CBOR_INVALID_DOUBLE);
-        return;
-      }
-      SetToken(CBORTokenTag::DOUBLE, kEncodedDoubleSize);
-      return;
-    }
-    case kInitialByteForEnvelope: {  // ENVELOPE
-      if (status_.pos + kEncodedEnvelopeHeaderSize > bytes_.size()) {
-        SetError(Error::CBOR_INVALID_ENVELOPE);
-        return;
-      }
-      // The envelope must be a byte string with 32 bit length.
-      if (bytes_[status_.pos + 1] != kInitialByteFor32BitLengthByteString) {
-        SetError(Error::CBOR_INVALID_ENVELOPE);
-        return;
-      }
-      // Read the length of the byte string.
-      token_start_internal_value_ = ReadBytesMostSignificantByteFirst<uint32_t>(
-          bytes_.subspan(status_.pos + 2));
-      // Make sure the payload is contained within the message.
-      if (token_start_internal_value_ + kEncodedEnvelopeHeaderSize +
-              status_.pos >
-          static_cast<std::size_t>(bytes_.size())) {
-        SetError(Error::CBOR_INVALID_ENVELOPE);
-        return;
-      }
-      auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
-      SetToken(CBORTokenTag::ENVELOPE,
-               kEncodedEnvelopeHeaderSize + length);
-      return;
-    }
-    default: {
-      span<uint8_t> remainder =
-          bytes_.subspan(status_.pos, bytes_.size() - status_.pos);
-      assert(!remainder.empty());
-      int8_t token_start_length = ReadTokenStart(remainder, &token_start_type_,
-                                                 &token_start_internal_value_);
-      bool success = token_start_length != -1;
-      switch (token_start_type_) {
-        case MajorType::UNSIGNED:  // INT32.
-          if (!success || std::numeric_limits<int32_t>::max() <
-                              token_start_internal_value_) {
-            SetError(Error::CBOR_INVALID_INT32);
-            return;
-          }
-          SetToken(CBORTokenTag::INT32, token_start_length);
-          return;
-        case MajorType::NEGATIVE:  // INT32.
-          if (!success ||
-              std::numeric_limits<int32_t>::min() >
-                  -static_cast<int64_t>(token_start_internal_value_) - 1) {
-            SetError(Error::CBOR_INVALID_INT32);
-            return;
-          }
-          SetToken(CBORTokenTag::INT32, token_start_length);
-          return;
-        case MajorType::STRING: {  // STRING8.
-          if (!success || remainder.size() < static_cast<int64_t>(
-                                                 token_start_internal_value_)) {
-            SetError(Error::CBOR_INVALID_STRING8);
-            return;
-          }
-          auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
-          SetToken(CBORTokenTag::STRING8, token_start_length + length);
-          return;
-        }
-        case MajorType::BYTE_STRING: {  // STRING16.
-          if (!success ||
-              remainder.size() <
-                  static_cast<int64_t>(token_start_internal_value_) ||
-              // Must be divisible by 2 since UTF16 is 2 bytes per character.
-              token_start_internal_value_ & 1) {
-            SetError(Error::CBOR_INVALID_STRING16);
-            return;
-          }
-          auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
-          SetToken(CBORTokenTag::STRING16, token_start_length + length);
-          return;
-        }
-        case MajorType::ARRAY:
-        case MajorType::MAP:
-        case MajorType::TAG:
-        case MajorType::SIMPLE_VALUE:
-          SetError(Error::CBOR_UNSUPPORTED_VALUE);
-          return;
-      }
-    }
-  }
-}
-
-void CBORTokenizer::SetToken(CBORTokenTag token_tag,
-                             std::ptrdiff_t token_byte_length) {
-  token_tag_ = token_tag;
-  token_byte_length_ = token_byte_length;
-}
-
-void CBORTokenizer::SetError(Error error) {
-  token_tag_ = CBORTokenTag::ERROR_VALUE;
-  status_.error = error;
-}
-
-#if 0
-void DumpCBOR(span<uint8_t> cbor) {
-  std::string indent;
-  CBORTokenizer tokenizer(cbor);
-  while (true) {
-    fprintf(stderr, "%s", indent.c_str());
-    switch (tokenizer.TokenTag()) {
-      case CBORTokenTag::ERROR_VALUE:
-        fprintf(stderr, "ERROR {status.error=%d, status.pos=%ld}\n",
-               tokenizer.Status().error, tokenizer.Status().pos);
-        return;
-      case CBORTokenTag::DONE:
-        fprintf(stderr, "DONE\n");
-        return;
-      case CBORTokenTag::TRUE_VALUE:
-        fprintf(stderr, "TRUE_VALUE\n");
-        break;
-      case CBORTokenTag::FALSE_VALUE:
-        fprintf(stderr, "FALSE_VALUE\n");
-        break;
-      case CBORTokenTag::NULL_VALUE:
-        fprintf(stderr, "NULL_VALUE\n");
-        break;
-      case CBORTokenTag::INT32:
-        fprintf(stderr, "INT32 [%d]\n", tokenizer.GetInt32());
-        break;
-      case CBORTokenTag::DOUBLE:
-        fprintf(stderr, "DOUBLE [%lf]\n", tokenizer.GetDouble());
-        break;
-      case CBORTokenTag::STRING8: {
-        span<uint8_t> v = tokenizer.GetString8();
-        std::string t(v.begin(), v.end());
-        fprintf(stderr, "STRING8 [%s]\n", t.c_str());
-        break;
-      }
-      case CBORTokenTag::STRING16: {
-        span<uint8_t> v = tokenizer.GetString16WireRep();
-        std::string t(v.begin(), v.end());
-        fprintf(stderr, "STRING16 [%s]\n", t.c_str());
-        break;
-      }
-      case CBORTokenTag::BINARY: {
-        span<uint8_t> v = tokenizer.GetBinary();
-        std::string t(v.begin(), v.end());
-        fprintf(stderr, "BINARY [%s]\n", t.c_str());
-        break;
-      }
-      case CBORTokenTag::MAP_START:
-        fprintf(stderr, "MAP_START\n");
-        indent += "  ";
-        break;
-      case CBORTokenTag::ARRAY_START:
-        fprintf(stderr, "ARRAY_START\n");
-        indent += "  ";
-        break;
-      case CBORTokenTag::STOP:
-        fprintf(stderr, "STOP\n");
-        indent.erase(0, 2);
-        break;
-      case CBORTokenTag::ENVELOPE:
-        fprintf(stderr, "ENVELOPE\n");
-        tokenizer.EnterEnvelope();
-        continue;
-    }
-    tokenizer.Next();
-  }
-}
-#endif
-
-}  // namespace inspector_protocol
diff --git a/third_party/inspector_protocol/encoding/cbor.h b/third_party/inspector_protocol/encoding/cbor.h
deleted file mode 100644
index 2785f633..0000000
--- a/third_party/inspector_protocol/encoding/cbor.h
+++ /dev/null
@@ -1,280 +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 INSPECTOR_PROTOCOL_ENCODING_CBOR_H_
-#define INSPECTOR_PROTOCOL_ENCODING_CBOR_H_
-
-#include <cstdint>
-#include <memory>
-#include <vector>
-#include "cbor_internals.h"
-#include "json_parser_handler.h"
-#include "span.h"
-#include "status.h"
-
-namespace inspector_protocol {
-
-namespace cbor {
-
-// The major types from RFC 7049 Section 2.1.
-enum class MajorType {
-  UNSIGNED = 0,
-  NEGATIVE = 1,
-  BYTE_STRING = 2,
-  STRING = 3,
-  ARRAY = 4,
-  MAP = 5,
-  TAG = 6,
-  SIMPLE_VALUE = 7
-};
-
-// Indicates the number of bits the "initial byte" needs to be shifted to the
-// right after applying |kMajorTypeMask| to produce the major type in the
-// lowermost bits.
-static constexpr uint8_t kMajorTypeBitShift = 5u;
-// Mask selecting the low-order 5 bits of the "initial byte", which is where
-// the additional information is encoded.
-static constexpr uint8_t kAdditionalInformationMask = 0x1f;
-// Mask selecting the high-order 3 bits of the "initial byte", which indicates
-// the major type of the encoded value.
-static constexpr uint8_t kMajorTypeMask = 0xe0;
-// Indicates the integer is in the following byte.
-static constexpr uint8_t kAdditionalInformation1Byte = 24u;
-// Indicates the integer is in the next 2 bytes.
-static constexpr uint8_t kAdditionalInformation2Bytes = 25u;
-// Indicates the integer is in the next 4 bytes.
-static constexpr uint8_t kAdditionalInformation4Bytes = 26u;
-// Indicates the integer is in the next 8 bytes.
-static constexpr uint8_t kAdditionalInformation8Bytes = 27u;
-
-// Encodes the initial byte, consisting of the |type| in the first 3 bits
-// followed by 5 bits of |additional_info|.
-constexpr uint8_t EncodeInitialByte(MajorType type, uint8_t additional_info) {
-  return (static_cast<uint8_t>(type) << kMajorTypeBitShift) |
-         (additional_info & kAdditionalInformationMask);
-}
-
-// TAG 24 indicates that what follows is a byte string which is
-// encoded in CBOR format. We use this as a wrapper for
-// maps and arrays, allowing us to skip them, because the
-// byte string carries its size (byte length).
-// https://tools.ietf.org/html/rfc7049#section-2.4.4.1
-static constexpr uint8_t kInitialByteForEnvelope =
-    EncodeInitialByte(MajorType::TAG, 24);
-// The initial byte for a byte string with at most 2^32 bytes
-// of payload. This is used for envelope encoding, even if
-// the byte string is shorter.
-static constexpr uint8_t kInitialByteFor32BitLengthByteString =
-    EncodeInitialByte(MajorType::BYTE_STRING, 26);
-
-// See RFC 7049 Section 2.2.1, indefinite length arrays / maps have additional
-// info = 31.
-static constexpr uint8_t kInitialByteIndefiniteLengthArray =
-    EncodeInitialByte(MajorType::ARRAY, 31);
-static constexpr uint8_t kInitialByteIndefiniteLengthMap =
-    EncodeInitialByte(MajorType::MAP, 31);
-// See RFC 7049 Section 2.3, Table 1; this is used for finishing indefinite
-// length maps / arrays.
-static constexpr uint8_t kStopByte =
-    EncodeInitialByte(MajorType::SIMPLE_VALUE, 31);
-
-}  // namespace cbor
-
-// The binary encoding for the inspector protocol follows the CBOR specification
-// (RFC 7049). Additional constraints:
-// - Only indefinite length maps and arrays are supported.
-// - Maps and arrays are wrapped with an envelope, that is, a
-//   CBOR tag with value 24 followed by a byte string specifying
-//   the byte length of the enclosed map / array. The byte string
-//   must use a 32 bit wide length.
-// - At the top level, a message must be an indefinite length map
-//   wrapped by an envelope.
-// - Maximal size for messages is 2^32 (4 GB).
-// - For scalars, we support only the int32_t range, encoded as
-//   UNSIGNED/NEGATIVE (major types 0 / 1).
-// - UTF16 strings, including with unbalanced surrogate pairs, are encoded
-//   as CBOR BYTE_STRING (major type 2). For such strings, the number of
-//   bytes encoded must be even.
-// - UTF8 strings (major type 3) are supported.
-// - 7 bit US-ASCII strings must always be encoded as UTF8 strings, not
-//   as UTF16 strings.
-// - Arbitrary byte arrays, in the inspector protocol called 'binary',
-//   are encoded as BYTE_STRING (major type 2), prefixed with a byte
-//   indicating base64 when rendered as JSON.
-
-// Encodes |value| as |UNSIGNED| (major type 0) iff >= 0, or |NEGATIVE|
-// (major type 1) iff < 0.
-void EncodeInt32(int32_t value, std::vector<uint8_t>* out);
-
-// Encodes a UTF16 string as a BYTE_STRING (major type 2). Each utf16
-// character in |in| is emitted with most significant byte first,
-// appending to |out|.
-void EncodeString16(span<uint16_t> in, std::vector<uint8_t>* out);
-
-// Encodes a UTF8 string |in| as STRING (major type 3).
-void EncodeString8(span<uint8_t> in, std::vector<uint8_t>* out);
-
-// Encodes the given |latin1| string as STRING8.
-// If any non-ASCII character is present, it will be represented
-// as a 2 byte UTF8 sequence.
-void EncodeFromLatin1(span<uint8_t> latin1, std::vector<uint8_t>* out);
-
-// Encodes the given |utf16| string as STRING8 if it's entirely US-ASCII.
-// Otherwise, encodes as STRING16.
-void EncodeFromUTF16(span<uint16_t> utf16, std::vector<uint8_t>* out);
-
-// Encodes arbitrary binary data in |in| as a BYTE_STRING (major type 2) with
-// definitive length, prefixed with tag 22 indicating expected conversion to
-// base64 (see RFC 7049, Table 3 and Section 2.4.4.2).
-void EncodeBinary(span<uint8_t> in, std::vector<uint8_t>* out);
-
-// Encodes / decodes a double as Major type 7 (SIMPLE_VALUE),
-// with additional info = 27, followed by 8 bytes in big endian.
-void EncodeDouble(double value, std::vector<uint8_t>* out);
-
-// Some constants for CBOR tokens that only take a single byte on the wire.
-uint8_t EncodeTrue();
-uint8_t EncodeFalse();
-uint8_t EncodeNull();
-uint8_t EncodeIndefiniteLengthArrayStart();
-uint8_t EncodeIndefiniteLengthMapStart();
-uint8_t EncodeStop();
-
-// An envelope indicates the byte length of a wrapped item.
-// We use this for maps and array, which allows the decoder
-// to skip such (nested) values whole sale.
-// It's implemented as a CBOR tag (major type 6) with additional
-// info = 24, followed by a byte string with a 32 bit length value;
-// so the maximal structure that we can wrap is 2^32 bits long.
-// See also: https://tools.ietf.org/html/rfc7049#section-2.4.4.1
-class EnvelopeEncoder {
- public:
-  // Emits the envelope start bytes and records the position for the
-  // byte size in |byte_size_pos_|. Also emits empty bytes for the
-  // byte sisze so that encoding can continue.
-  void EncodeStart(std::vector<uint8_t>* out);
-  // This records the current size in |out| at position byte_size_pos_.
-  // Returns true iff successful.
-  bool EncodeStop(std::vector<uint8_t>* out);
-
- private:
-  std::size_t byte_size_pos_ = 0;
-};
-
-// This can be used to convert from JSON to CBOR, by passing the
-// return value to the routines in json_parser.h.  The handler will encode into
-// |out|, and iff an error occurs it will set |status| to an error and clear
-// |out|. Otherwise, |status.ok()| will be |true|.
-std::unique_ptr<JSONParserHandler> NewJSONToCBOREncoder(
-    std::vector<uint8_t>* out, Status* status);
-
-// Parses a CBOR encoded message from |bytes|, sending JSON events to
-// |json_out|. If an error occurs, sends |out->HandleError|, and parsing stops.
-// The client is responsible for discarding the already received information in
-// that case.
-void ParseCBOR(span<uint8_t> bytes, JSONParserHandler* json_out);
-
-// Tags for the tokens within a CBOR message that CBORStream understands.
-// Note that this is not the same terminology as the CBOR spec (RFC 7049),
-// but rather, our adaptation. For instance, we lump unsigned and signed
-// major type into INT32 here (and disallow values outside the int32_t range).
-enum class CBORTokenTag {
-  // Encountered an error in the structure of the message. Consult
-  // status() for details.
-  ERROR_VALUE,
-  // Booleans and NULL.
-  TRUE_VALUE,
-  FALSE_VALUE,
-  NULL_VALUE,
-  // An int32_t (signed 32 bit integer).
-  INT32,
-  // A double (64 bit floating point).
-  DOUBLE,
-  // A UTF8 string.
-  STRING8,
-  // A UTF16 string.
-  STRING16,
-  // A binary string.
-  BINARY,
-  // Starts an indefinite length map; after the map start we expect
-  // alternating keys and values, followed by STOP.
-  MAP_START,
-  // Starts an indefinite length array; after the array start we
-  // expect values, followed by STOP.
-  ARRAY_START,
-  // Ends a map or an array.
-  STOP,
-  // An envelope indicator, wrapping a map or array.
-  // Internally this carries the byte length of the wrapped
-  // map or array. While CBORTokenizer::Next() will read / skip the entire
-  // envelope, CBORTokenizer::EnterEnvelope() reads the tokens
-  // inside of it.
-  ENVELOPE,
-  // We've reached the end there is nothing else to read.
-  DONE,
-};
-
-// CBORTokenizer segments a CBOR message, presenting the tokens therein as
-// numbers, strings, etc. This is not a complete CBOR parser, but makes it much
-// easier to implement one (e.g. ParseCBOR, above). It can also be used to parse
-// messages partially.
-class CBORTokenizer {
- public:
-  explicit CBORTokenizer(span<uint8_t> bytes);
-  ~CBORTokenizer();
-
-  // Identifies the current token that we're looking at,
-  // or ERROR_VALUE (in which ase ::Status() has details)
-  // or DONE (if we're past the last token).
-  CBORTokenTag TokenTag() const;
-
-  // Advances to the next token.
-  void Next();
-  // Can only be called if TokenTag() == CBORTokenTag::ENVELOPE.
-  // While Next() would skip past the entire envelope / what it's
-  // wrapping, EnterEnvelope positions the cursor inside of the envelope,
-  // letting the client explore the nested structure.
-  void EnterEnvelope();
-
-  // If TokenTag() is CBORTokenTag::ERROR_VALUE, then Status().error describes
-  // the error more precisely; otherwise it'll be set to Error::OK.
-  // In either case, Status().pos is the current position.
-  struct Status Status() const;
-
-  // The following methods retrieve the token values. They can only
-  // be called if TokenTag() matches.
-
-  // To be called only if ::TokenTag() == CBORTokenTag::INT32.
-  int32_t GetInt32() const;
-
-  // To be called only if ::TokenTag() == CBORTokenTag::DOUBLE.
-  double GetDouble() const;
-
-  // To be called only if ::TokenTag() == CBORTokenTag::STRING8.
-  span<uint8_t> GetString8() const;
-
-  // Wire representation for STRING16 is low byte first (little endian).
-  // To be called only if ::TokenTag() == CBORTokenTag::STRING16.
-  span<uint8_t> GetString16WireRep() const;
-
-  // To be called only if ::TokenTag() == CBORTokenTag::BINARY.
-  span<uint8_t> GetBinary() const;
-
- private:
-  void ReadNextToken(bool enter_envelope);
-  void SetToken(CBORTokenTag token, std::ptrdiff_t token_byte_length);
-  void SetError(Error error);
-
-  span<uint8_t> bytes_;
-  CBORTokenTag token_tag_;
-  struct Status status_;
-  std::ptrdiff_t token_byte_length_;
-  cbor::MajorType token_start_type_;
-  uint64_t token_start_internal_value_;
-};
-
-void DumpCBOR(span<uint8_t> cbor);
-
-}  // namespace inspector_protocol
-#endif  // INSPECTOR_PROTOCOL_ENCODING_CBOR_H_
diff --git a/third_party/inspector_protocol/encoding/cbor_internals.h b/third_party/inspector_protocol/encoding/cbor_internals.h
deleted file mode 100644
index e2621d89..0000000
--- a/third_party/inspector_protocol/encoding/cbor_internals.h
+++ /dev/null
@@ -1,39 +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 INSPECTOR_PROTOCOL_ENCODING_CBOR_INTERNALS_H_
-#define INSPECTOR_PROTOCOL_ENCODING_CBOR_INTERNALS_H_
-
-#include <cstdint>
-#include <vector>
-#include "span.h"
-#include "status.h"
-
-// These internals are exposed for testing and implementing cbor.h.
-// Never directly depend on them from other production code.
-namespace inspector_protocol {
-namespace cbor {
-enum class MajorType;
-}
-
-namespace cbor_internals {
-
-// Reads the start of a token with definitive size from |bytes|.
-// |type| is the major type as specified in RFC 7049 Section 2.1.
-// |value| is the payload (e.g. for MajorType::UNSIGNED) or is the size
-// (e.g. for BYTE_STRING).
-// If successful, returns the number of bytes read. Otherwise returns -1.
-int8_t ReadTokenStart(span<uint8_t> bytes,
-                      cbor::MajorType* type,
-                      uint64_t* value);
-
-// Writes the start of a token with |type|. The |value| may indicate the size,
-// or it may be the payload if the value is an unsigned integer.
-void WriteTokenStart(cbor::MajorType type,
-                     uint64_t value,
-                     std::vector<uint8_t>* encoded);
-}  // namespace cbor_internals
-}  // namespace inspector_protocol
-
-#endif  // INSPECTOR_PROTOCOL_ENCODING_CBOR_H_
diff --git a/third_party/inspector_protocol/encoding/cbor_test.cc b/third_party/inspector_protocol/encoding/cbor_test.cc
deleted file mode 100644
index 9f6201f..0000000
--- a/third_party/inspector_protocol/encoding/cbor_test.cc
+++ /dev/null
@@ -1,994 +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 "cbor.h"
-
-#include <array>
-#include <cmath>
-#include <string>
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include "json_parser.h"
-#include "json_std_string_writer.h"
-#include "linux_dev_platform.h"
-
-using testing::ElementsAreArray;
-
-namespace inspector_protocol {
-
-using cbor::MajorType;
-
-//
-// EncodeInt32 / CBORTokenTag::INT32
-//
-TEST(EncodeDecodeInt32Test, Roundtrips23) {
-  // This roundtrips the int32_t value 23 through the pair of EncodeInt32 /
-  // CBORTokenizer; this is interesting since 23 is encoded as a single byte.
-  std::vector<uint8_t> encoded;
-  EncodeInt32(23, &encoded);
-  // first three bits: major type = 0; remaining five bits: additional info =
-  // value 23.
-  EXPECT_THAT(encoded, ElementsAreArray(std::array<uint8_t, 1>{{23}}));
-
-  // Reverse direction: decode with CBORTokenizer.
-  CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-  EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag());
-  EXPECT_EQ(23, tokenizer.GetInt32());
-  tokenizer.Next();
-  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
-}
-
-TEST(EncodeDecodeInt32Test, RoundtripsUint8) {
-  // This roundtrips the int32_t value 42 through the pair of EncodeInt32 /
-  // CBORTokenizer. This is different from Roundtrip23 because 42 is encoded
-  // in an extra byte after the initial one.
-  std::vector<uint8_t> encoded;
-  EncodeInt32(42, &encoded);
-  // first three bits: major type = 0;
-  // remaining five bits: additional info = 24, indicating payload is uint8.
-  EXPECT_THAT(encoded, ElementsAreArray(std::array<uint8_t, 2>{{24, 42}}));
-
-  // Reverse direction: decode with CBORTokenizer.
-  CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-  EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag());
-  EXPECT_EQ(42, tokenizer.GetInt32());
-  tokenizer.Next();
-  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
-}
-
-TEST(EncodeDecodeInt32Test, RoundtripsUint16) {
-  // 500 is encoded as a uint16 after the initial byte.
-  std::vector<uint8_t> encoded;
-  EncodeInt32(500, &encoded);
-  // 1 for initial byte, 2 for uint16.
-  EXPECT_EQ(static_cast<std::size_t>(3), encoded.size());
-  // first three bits: major type = 0;
-  // remaining five bits: additional info = 25, indicating payload is uint16.
-  EXPECT_EQ(25, encoded[0]);
-  EXPECT_EQ(0x01, encoded[1]);
-  EXPECT_EQ(0xf4, encoded[2]);
-
-  // Reverse direction: decode with CBORTokenizer.
-  CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-  EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag());
-  EXPECT_EQ(500, tokenizer.GetInt32());
-  tokenizer.Next();
-  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
-}
-
-TEST(EncodeDecodeInt32Test, RoundtripsInt32Max) {
-  // std::numeric_limits<int32_t> is encoded as a uint32 after the initial byte.
-  std::vector<uint8_t> encoded;
-  EncodeInt32(std::numeric_limits<int32_t>::max(), &encoded);
-  // 1 for initial byte, 4 for the uint32.
-  // first three bits: major type = 0;
-  // remaining five bits: additional info = 26, indicating payload is uint32.
-  EXPECT_THAT(
-      encoded,
-      ElementsAreArray(std::array<uint8_t, 5>{{26, 0x7f, 0xff, 0xff, 0xff}}));
-
-  // Reverse direction: decode with CBORTokenizer.
-  CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-  EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag());
-  EXPECT_EQ(std::numeric_limits<int32_t>::max(), tokenizer.GetInt32());
-  tokenizer.Next();
-  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
-}
-
-TEST(EncodeDecodeInt32Test, CantRoundtripUint32) {
-  // 0xdeadbeef is a value which does not fit below
-  // std::numerical_limits<int32_t>::max(), so we can't encode
-  // it with EncodeInt32. However, CBOR does support this, so we
-  // encode it here manually with the internal routine, just to observe
-  // that it's considered an invalid int32 by CBORTokenizer.
-  std::vector<uint8_t> encoded;
-  cbor_internals::WriteTokenStart(MajorType::UNSIGNED, 0xdeadbeef, &encoded);
-  // 1 for initial byte, 4 for the uint32.
-  // first three bits: major type = 0;
-  // remaining five bits: additional info = 26, indicating payload is uint32.
-  EXPECT_THAT(
-      encoded,
-      ElementsAreArray(std::array<uint8_t, 5>{{26, 0xde, 0xad, 0xbe, 0xef}}));
-
-  // Now try to decode; we treat this as an invalid INT32.
-  CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-  // 0xdeadbeef is > std::numerical_limits<int32_t>::max().
-  EXPECT_EQ(CBORTokenTag::ERROR_VALUE, tokenizer.TokenTag());
-  EXPECT_EQ(Error::CBOR_INVALID_INT32, tokenizer.Status().error);
-}
-
-TEST(EncodeDecodeInt32Test, DecodeErrorCases) {
-  struct TestCase {
-    std::vector<uint8_t> data;
-    std::string msg;
-  };
-  std::vector<TestCase> tests{
-      {TestCase{
-           {24},
-           "additional info = 24 would require 1 byte of payload (but it's 0)"},
-       TestCase{{27, 0xaa, 0xbb, 0xcc},
-                "additional info = 27 would require 8 bytes of payload (but "
-                "it's 3)"},
-       TestCase{{29}, "additional info = 29 isn't recognized"}}};
-
-  for (const TestCase& test : tests) {
-    SCOPED_TRACE(test.msg);
-    span<uint8_t> encoded_bytes(&test.data[0], test.data.size());
-    CBORTokenizer tokenizer(
-        span<uint8_t>(&encoded_bytes[0], encoded_bytes.size()));
-    EXPECT_EQ(CBORTokenTag::ERROR_VALUE, tokenizer.TokenTag());
-    EXPECT_EQ(Error::CBOR_INVALID_INT32, tokenizer.Status().error);
-  }
-}
-
-TEST(EncodeDecodeInt32Test, RoundtripsMinus24) {
-  // This roundtrips the int32_t value -24 through the pair of EncodeInt32 /
-  // CBORTokenizer; this is interesting since -24 is encoded as
-  // a single byte as NEGATIVE, and it tests the specific encoding
-  // (note how for unsigned the single byte covers values up to 23).
-  // Additional examples are covered in RoundtripsAdditionalExamples.
-  std::vector<uint8_t> encoded;
-  EncodeInt32(-24, &encoded);
-  // first three bits: major type = 1; remaining five bits: additional info =
-  // value 23.
-  EXPECT_THAT(encoded, ElementsAreArray(std::array<uint8_t, 1>{{1 << 5 | 23}}));
-
-  // Reverse direction: decode with CBORTokenizer.
-  CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-  EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag());
-  EXPECT_EQ(-24, tokenizer.GetInt32());
-  tokenizer.Next();
-  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
-}
-
-TEST(EncodeDecodeInt32Test, RoundtripsAdditionalNegativeExamples) {
-  std::vector<int32_t> examples = {-1,
-                                   -10,
-                                   -24,
-                                   -25,
-                                   -300,
-                                   -30000,
-                                   -300 * 1000,
-                                   -1000 * 1000,
-                                   -1000 * 1000 * 1000,
-                                   std::numeric_limits<int32_t>::min()};
-  for (int32_t example : examples) {
-    SCOPED_TRACE(base::StringPrintf("example %d", example));
-    std::vector<uint8_t> encoded;
-    EncodeInt32(example, &encoded);
-    CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-    EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag());
-    EXPECT_EQ(example, tokenizer.GetInt32());
-    tokenizer.Next();
-    EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
-  }
-}
-
-//
-// EncodeString16 / CBORTokenTag::STRING16
-//
-TEST(EncodeDecodeString16Test, RoundtripsEmpty) {
-  // This roundtrips the empty utf16 string through the pair of EncodeString16 /
-  // CBORTokenizer.
-  std::vector<uint8_t> encoded;
-  EncodeString16(span<uint16_t>(), &encoded);
-  EXPECT_EQ(static_cast<std::size_t>(1), encoded.size());
-  // first three bits: major type = 2; remaining five bits: additional info =
-  // size 0.
-  EXPECT_EQ(2 << 5, encoded[0]);
-
-  // Reverse direction: decode with CBORTokenizer.
-  CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-  EXPECT_EQ(CBORTokenTag::STRING16, tokenizer.TokenTag());
-  span<uint8_t> decoded_string16_wirerep = tokenizer.GetString16WireRep();
-  EXPECT_TRUE(decoded_string16_wirerep.empty());
-  tokenizer.Next();
-  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
-}
-
-// On the wire, we STRING16 is encoded as little endian (least
-// significant byte first). The host may or may not be little endian,
-// so this routine follows the advice in
-// https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html.
-std::vector<uint16_t> String16WireRepToHost(span<uint8_t> in) {
-  assert((in.size() & 1) == 0);  // must be even number of bytes.
-  std::vector<uint16_t> host_out;
-  for (std::ptrdiff_t ii = 0; ii < in.size(); ii += 2)
-    host_out.push_back(in[ii + 1] << 8 | in[ii]);
-  return host_out;
-}
-
-TEST(EncodeDecodeString16Test, RoundtripsHelloWorld) {
-  // This roundtrips the hello world message which is given here in utf16
-  // characters. 0xd83c, 0xdf0e: UTF16 encoding for the "Earth Globe Americas"
-  // character, 🌎.
-  std::array<uint16_t, 10> msg{
-      {'H', 'e', 'l', 'l', 'o', ',', ' ', 0xd83c, 0xdf0e, '.'}};
-  std::vector<uint8_t> encoded;
-  EncodeString16(span<uint16_t>(msg.data(), msg.size()), &encoded);
-  // This will be encoded as BYTE_STRING of length 20, so the 20 is encoded in
-  // the additional info part of the initial byte. Payload is two bytes for each
-  // UTF16 character.
-  uint8_t initial_byte = /*major type=*/2 << 5 | /*additional info=*/20;
-  std::array<uint8_t, 21> encoded_expected = {
-      {initial_byte, 'H', 0,   'e', 0,    'l',  0,    'l',  0,   'o', 0,
-       ',',          0,   ' ', 0,   0x3c, 0xd8, 0x0e, 0xdf, '.', 0}};
-  EXPECT_THAT(encoded, ElementsAreArray(encoded_expected));
-
-  // Now decode to complete the roundtrip.
-  CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-  EXPECT_EQ(CBORTokenTag::STRING16, tokenizer.TokenTag());
-  std::vector<uint16_t> decoded =
-      String16WireRepToHost(tokenizer.GetString16WireRep());
-  EXPECT_THAT(decoded, ElementsAreArray(msg));
-  tokenizer.Next();
-  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
-
-  // For bonus points, we look at the decoded message in UTF8 as well so we can
-  // easily see it on the terminal screen.
-  std::string utf8_decoded =
-      base::UTF16ToUTF8(base::StringPiece16(decoded.data(), decoded.size()));
-  EXPECT_EQ("Hello, 🌎.", utf8_decoded);
-}
-
-TEST(EncodeDecodeString16Test, Roundtrips500) {
-  // We roundtrip a message that has 250 16 bit values. Each of these are just
-  // set to their index. 250 is interesting because the cbor spec uses a
-  // BYTE_STRING of length 500 for one of their examples of how to encode the
-  // start of it (section 2.1) so it's easy for us to look at the first three
-  // bytes closely.
-  std::vector<uint16_t> two_fifty;
-  for (uint16_t ii = 0; ii < 250; ++ii) two_fifty.push_back(ii);
-  std::vector<uint8_t> encoded;
-  EncodeString16(span<uint16_t>(two_fifty.data(), two_fifty.size()), &encoded);
-  EXPECT_EQ(static_cast<std::size_t>(3 + 250 * 2), encoded.size());
-  // Now check the first three bytes:
-  // Major type: 2 (BYTE_STRING)
-  // Additional information: 25, indicating size is represented by 2 bytes.
-  // Bytes 1 and 2 encode 500 (0x01f4).
-  EXPECT_EQ(2 << 5 | 25, encoded[0]);
-  EXPECT_EQ(0x01, encoded[1]);
-  EXPECT_EQ(0xf4, encoded[2]);
-
-  // Now decode to complete the roundtrip.
-  CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-  EXPECT_EQ(CBORTokenTag::STRING16, tokenizer.TokenTag());
-  std::vector<uint16_t> decoded =
-      String16WireRepToHost(tokenizer.GetString16WireRep());
-  EXPECT_THAT(decoded, ElementsAreArray(two_fifty));
-  tokenizer.Next();
-  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
-}
-
-TEST(EncodeDecodeString16Test, ErrorCases) {
-  struct TestCase {
-    std::vector<uint8_t> data;
-    std::string msg;
-  };
-  std::vector<TestCase> tests{
-      {TestCase{{2 << 5 | 1, 'a'},
-                "length must be divisible by 2 (but it's 1)"},
-       TestCase{{2 << 5 | 29}, "additional info = 29 isn't recognized"}}};
-  for (const TestCase& test : tests) {
-    SCOPED_TRACE(test.msg);
-    CBORTokenizer tokenizer(span<uint8_t>(&test.data[0], test.data.size()));
-    EXPECT_EQ(CBORTokenTag::ERROR_VALUE, tokenizer.TokenTag());
-    EXPECT_EQ(Error::CBOR_INVALID_STRING16, tokenizer.Status().error);
-  }
-}
-
-//
-// EncodeString8 / CBORTokenTag::STRING8
-//
-TEST(EncodeDecodeString8Test, RoundtripsHelloWorld) {
-  // This roundtrips the hello world message which is given here in utf8
-  // characters. 🌎 is a four byte utf8 character.
-  std::string utf8_msg = "Hello, 🌎.";
-  std::vector<uint8_t> msg(utf8_msg.begin(), utf8_msg.end());
-  std::vector<uint8_t> encoded;
-  EncodeString8(span<uint8_t>(msg.data(), msg.size()), &encoded);
-  // This will be encoded as STRING of length 12, so the 12 is encoded in
-  // the additional info part of the initial byte. Payload is one byte per
-  // utf8 byte.
-  uint8_t initial_byte = /*major type=*/3 << 5 | /*additional info=*/12;
-  std::array<uint8_t, 13> encoded_expected = {{initial_byte, 'H', 'e', 'l', 'l',
-                                               'o', ',', ' ', 0xF0, 0x9f, 0x8c,
-                                               0x8e, '.'}};
-  EXPECT_THAT(encoded, ElementsAreArray(encoded_expected));
-
-  // Now decode to complete the roundtrip.
-  CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-  EXPECT_EQ(CBORTokenTag::STRING8, tokenizer.TokenTag());
-  std::vector<uint8_t> decoded(tokenizer.GetString8().begin(),
-                               tokenizer.GetString8().end());
-  EXPECT_THAT(decoded, ElementsAreArray(msg));
-  tokenizer.Next();
-  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
-}
-
-TEST(EncodeFromLatin1Test, ConvertsToUTF8IfNeeded) {
-  std::vector<std::pair<std::string, std::string>> examples = {
-      {"Hello, world.", "Hello, world."},
-      {"Above: \xDC"
-       "ber",
-       "Above: Über"},
-      {"\xA5 500 are about \xA3 3.50; a y with umlaut is \xFF",
-       "¥ 500 are about £ 3.50; a y with umlaut is ÿ"}};
-
-  for (const auto& example : examples) {
-    const std::string& latin1 = example.first;
-    const std::string& expected_utf8 = example.second;
-    std::vector<uint8_t> encoded;
-    EncodeFromLatin1(
-        span<uint8_t>(reinterpret_cast<const uint8_t*>(latin1.data()),
-                      latin1.size()),
-        &encoded);
-    CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-    EXPECT_EQ(CBORTokenTag::STRING8, tokenizer.TokenTag());
-    std::vector<uint8_t> decoded(tokenizer.GetString8().begin(),
-                                 tokenizer.GetString8().end());
-    std::string decoded_str(decoded.begin(), decoded.end());
-    EXPECT_THAT(decoded_str, testing::Eq(expected_utf8));
-  }
-}
-
-TEST(EncodeFromUTF16Test, ConvertsToUTF8IfEasy) {
-  std::vector<uint16_t> ascii = {'e', 'a', 's', 'y'};
-  std::vector<uint8_t> encoded;
-  EncodeFromUTF16(span<uint16_t>(ascii.data(), ascii.size()), &encoded);
-
-  CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-  EXPECT_EQ(CBORTokenTag::STRING8, tokenizer.TokenTag());
-  std::vector<uint8_t> decoded(tokenizer.GetString8().begin(),
-                               tokenizer.GetString8().end());
-  std::string decoded_str(decoded.begin(), decoded.end());
-  EXPECT_THAT(decoded_str, testing::Eq("easy"));
-}
-
-TEST(EncodeFromUTF16Test, EncodesAsString16IfNeeded) {
-  // Since this message contains non-ASCII characters, the routine is
-  // forced to encode as UTF16. We see this below by checking that the
-  // token tag is STRING16.
-  std::vector<uint16_t> msg = {'H', 'e', 'l',    'l',    'o',
-                               ',', ' ', 0xd83c, 0xdf0e, '.'};
-  std::vector<uint8_t> encoded;
-  EncodeFromUTF16(span<uint16_t>(msg.data(), msg.size()), &encoded);
-
-  CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-  EXPECT_EQ(CBORTokenTag::STRING16, tokenizer.TokenTag());
-  std::vector<uint16_t> decoded =
-      String16WireRepToHost(tokenizer.GetString16WireRep());
-  std::string utf8_decoded =
-      base::UTF16ToUTF8(base::StringPiece16(decoded.data(), decoded.size()));
-  EXPECT_EQ("Hello, 🌎.", utf8_decoded);
-}
-
-//
-// EncodeBinary / CBORTokenTag::BINARY
-//
-TEST(EncodeDecodeBinaryTest, RoundtripsHelloWorld) {
-  std::vector<uint8_t> binary = {'H', 'e', 'l', 'l', 'o', ',', ' ',
-                                 'w', 'o', 'r', 'l', 'd', '.'};
-  std::vector<uint8_t> encoded;
-  EncodeBinary(span<uint8_t>(binary.data(), binary.size()), &encoded);
-  // So, on the wire we see that the binary blob travels unmodified.
-  EXPECT_THAT(
-      encoded,
-      ElementsAreArray(std::array<uint8_t, 15>{
-          {(6 << 5 | 22),  // tag 22 indicating base64 interpretation in JSON
-           (2 << 5 | 13),  // BYTE_STRING (type 2) of length 13
-           'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.'}}));
-  std::vector<uint8_t> decoded;
-  CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-  EXPECT_EQ(CBORTokenTag::BINARY, tokenizer.TokenTag());
-  EXPECT_EQ(0, int(tokenizer.Status().error));
-  decoded = std::vector<uint8_t>(tokenizer.GetBinary().begin(),
-                                 tokenizer.GetBinary().end());
-  EXPECT_THAT(decoded, ElementsAreArray(binary));
-  tokenizer.Next();
-  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
-}
-
-//
-// EncodeDouble / CBORTokenTag::DOUBLE
-//
-TEST(EncodeDecodeDoubleTest, RoundtripsWikipediaExample) {
-  // https://en.wikipedia.org/wiki/Double-precision_floating-point_format
-  // provides the example of a hex representation 3FD5 5555 5555 5555, which
-  // approximates 1/3.
-
-  const double kOriginalValue = 1.0 / 3;
-  std::vector<uint8_t> encoded;
-  EncodeDouble(kOriginalValue, &encoded);
-  // first three bits: major type = 7; remaining five bits: additional info =
-  // value 27. This is followed by 8 bytes of payload (which match Wikipedia).
-  EXPECT_THAT(
-      encoded,
-      ElementsAreArray(std::array<uint8_t, 9>{
-          {7 << 5 | 27, 0x3f, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}}));
-
-  // Reverse direction: decode and compare with original value.
-  CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-  EXPECT_EQ(CBORTokenTag::DOUBLE, tokenizer.TokenTag());
-  EXPECT_THAT(tokenizer.GetDouble(), testing::DoubleEq(kOriginalValue));
-  tokenizer.Next();
-  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
-}
-
-TEST(EncodeDecodeDoubleTest, RoundtripsAdditionalExamples) {
-  std::vector<double> examples = {0.0,
-                                  1.0,
-                                  -1.0,
-                                  3.1415,
-                                  std::numeric_limits<double>::min(),
-                                  std::numeric_limits<double>::max(),
-                                  std::numeric_limits<double>::infinity(),
-                                  std::numeric_limits<double>::quiet_NaN()};
-  for (double example : examples) {
-    SCOPED_TRACE(base::StringPrintf("example %lf", example));
-    std::vector<uint8_t> encoded;
-    EncodeDouble(example, &encoded);
-    span<uint8_t> encoded_bytes(&encoded[0], encoded.size());
-    CBORTokenizer tokenizer(span<uint8_t>(&encoded[0], encoded.size()));
-    EXPECT_EQ(CBORTokenTag::DOUBLE, tokenizer.TokenTag());
-    if (std::isnan(example))
-      EXPECT_TRUE(std::isnan(tokenizer.GetDouble()));
-    else
-      EXPECT_THAT(tokenizer.GetDouble(), testing::DoubleEq(example));
-    tokenizer.Next();
-    EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
-  }
-}
-
-//
-// NewJSONToCBOREncoder
-//
-void EncodeUTF8ForTest(const std::string& key, std::vector<uint8_t>* out) {
-  EncodeString8(
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(key.data()), key.size()),
-      out);
-}
-
-TEST(JSONToCBOREncoderTest, SevenBitStrings) {
-  // When a string can be represented as 7 bit ASCII, the encoder will use the
-  // STRING (major Type 3) type, so the actual characters end up as bytes on the
-  // wire.
-  std::vector<uint8_t> encoded;
-  Status status;
-  std::unique_ptr<JSONParserHandler> encoder =
-      NewJSONToCBOREncoder(&encoded, &status);
-  std::vector<uint16_t> utf16 = {'f', 'o', 'o'};
-  encoder->HandleString16(span<uint16_t>(utf16.data(), utf16.size()));
-  EXPECT_EQ(Error::OK, status.error);
-  // Here we assert that indeed, seven bit strings are represented as
-  // bytes on the wire, "foo" is just "foo".
-  EXPECT_THAT(encoded,
-              ElementsAreArray(std::array<uint8_t, 4>{
-                  {/*major type 3*/ 3 << 5 | /*length*/ 3, 'f', 'o', 'o'}}));
-}
-
-TEST(JsonCborRoundtrip, EncodingDecoding) {
-  // Hits all the cases except binary and error in JSONParserHandler, first
-  // parsing a JSON message into CBOR, then parsing it back from CBOR into JSON.
-  std::string json =
-      "{"
-      "\"string\":\"Hello, \\ud83c\\udf0e.\","
-      "\"double\":3.1415,"
-      "\"int\":1,"
-      "\"negative int\":-1,"
-      "\"bool\":true,"
-      "\"null\":null,"
-      "\"array\":[1,2,3]"
-      "}";
-  std::vector<uint8_t> encoded;
-  Status status;
-  std::unique_ptr<JSONParserHandler> encoder =
-      NewJSONToCBOREncoder(&encoded, &status);
-  span<uint8_t> ascii_in(reinterpret_cast<const uint8_t*>(json.data()),
-                         json.size());
-  ParseJSONChars(GetLinuxDevPlatform(), ascii_in, encoder.get());
-  std::vector<uint8_t> expected = {
-      0xd8,            // envelope
-      0x5a,            // byte string with 32 bit length
-      0,    0, 0, 94,  // length is 94 bytes
-  };
-  expected.push_back(0xbf);  // indef length map start
-  EncodeUTF8ForTest("string", &expected);
-  // This is followed by the encoded string for "Hello, 🌎."
-  // So, it's the same bytes that we tested above in
-  // EncodeDecodeString16Test.RoundtripsHelloWorld.
-  expected.push_back(/*major type=*/2 << 5 | /*additional info=*/20);
-  for (uint8_t ch : std::array<uint8_t, 20>{
-           {'H', 0, 'e', 0, 'l',  0,    'l',  0,    'o', 0,
-            ',', 0, ' ', 0, 0x3c, 0xd8, 0x0e, 0xdf, '.', 0}})
-    expected.push_back(ch);
-  EncodeUTF8ForTest("double", &expected);
-  EncodeDouble(3.1415, &expected);
-  EncodeUTF8ForTest("int", &expected);
-  EncodeInt32(1, &expected);
-  EncodeUTF8ForTest("negative int", &expected);
-  EncodeInt32(-1, &expected);
-  EncodeUTF8ForTest("bool", &expected);
-  expected.push_back(7 << 5 | 21);  // RFC 7049 Section 2.3, Table 2: true
-  EncodeUTF8ForTest("null", &expected);
-  expected.push_back(7 << 5 | 22);  // RFC 7049 Section 2.3, Table 2: null
-  EncodeUTF8ForTest("array", &expected);
-  expected.push_back(0xd8);  // envelope
-  expected.push_back(0x5a);  // byte string with 32 bit length
-  // the length is 5 bytes (that's up to end indef length array below).
-  for (uint8_t ch : std::array<uint8_t, 4>{{0, 0, 0, 5}})
-    expected.push_back(ch);
-  expected.push_back(0x9f);  // RFC 7049 Section 2.2.1, indef length array start
-  expected.push_back(1);     // Three UNSIGNED values (easy since Major Type 0)
-  expected.push_back(2);
-  expected.push_back(3);
-  expected.push_back(0xff);  // End indef length array
-  expected.push_back(0xff);  // End indef length map
-  EXPECT_TRUE(status.ok());
-  EXPECT_THAT(encoded, ElementsAreArray(expected));
-
-  // And now we roundtrip, decoding the message we just encoded.
-  std::string decoded;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &decoded, &status);
-  ParseCBOR(span<uint8_t>(encoded.data(), encoded.size()), json_writer.get());
-  EXPECT_EQ(Error::OK, status.error);
-  EXPECT_EQ(json, decoded);
-}
-
-TEST(JsonCborRoundtrip, MoreRoundtripExamples) {
-  std::vector<std::string> examples = {
-      // Tests that after closing a nested objects, additional key/value pairs
-      // are considered.
-      "{\"foo\":{\"bar\":1},\"baz\":2}", "{\"foo\":[1,2,3],\"baz\":2}"};
-  for (const std::string& json : examples) {
-    SCOPED_TRACE(std::string("example: ") + json);
-    std::vector<uint8_t> encoded;
-    Status status;
-    std::unique_ptr<JSONParserHandler> encoder =
-        NewJSONToCBOREncoder(&encoded, &status);
-    span<uint8_t> ascii_in(reinterpret_cast<const uint8_t*>(json.data()),
-                           json.size());
-    ParseJSONChars(GetLinuxDevPlatform(), ascii_in, encoder.get());
-    std::string decoded;
-    std::unique_ptr<JSONParserHandler> json_writer =
-        NewJSONWriter(GetLinuxDevPlatform(), &decoded, &status);
-    ParseCBOR(span<uint8_t>(encoded.data(), encoded.size()), json_writer.get());
-    EXPECT_EQ(Error::OK, status.error);
-    EXPECT_EQ(json, decoded);
-  }
-}
-
-TEST(JSONToCBOREncoderTest, HelloWorldBinary_WithTripToJson) {
-  // The JSONParserHandler::HandleBinary is a special case: The JSON parser will
-  // never call this method, because JSON does not natively support the binary
-  // type. So, we can't fully roundtrip. However, the other direction works:
-  // binary will be rendered in JSON, as a base64 string. So, we make calls to
-  // the encoder directly here, to construct a message, and one of these calls
-  // is ::HandleBinary, to which we pass a "binary" string containing "Hello,
-  // world.".
-  std::vector<uint8_t> encoded;
-  Status status;
-  std::unique_ptr<JSONParserHandler> encoder =
-      NewJSONToCBOREncoder(&encoded, &status);
-  encoder->HandleObjectBegin();
-  // Emit a key.
-  std::vector<uint16_t> key = {'f', 'o', 'o'};
-  encoder->HandleString16(span<uint16_t>(key.data(), key.size()));
-  // Emit the binary payload, an arbitrary array of bytes that happens to
-  // be the ascii message "Hello, world.".
-  encoder->HandleBinary(std::vector<uint8_t>{'H', 'e', 'l', 'l', 'o', ',', ' ',
-                                             'w', 'o', 'r', 'l', 'd', '.'});
-  encoder->HandleObjectEnd();
-  EXPECT_EQ(Error::OK, status.error);
-
-  // Now drive the json writer via the CBOR decoder.
-  std::string decoded;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &decoded, &status);
-  ParseCBOR(span<uint8_t>(encoded.data(), encoded.size()), json_writer.get());
-  EXPECT_EQ(Error::OK, status.error);
-  EXPECT_EQ(Status::npos(), status.pos);
-  // "Hello, world." in base64 is "SGVsbG8sIHdvcmxkLg==".
-  EXPECT_EQ("{\"foo\":\"SGVsbG8sIHdvcmxkLg==\"}", decoded);
-}
-
-//
-// ParseCBOR
-//
-TEST(ParseCBORTest, ParseEmptyCBORMessage) {
-  // An envelope starting with 0xd8, 0x5a, with the byte length
-  // of 2, containing a map that's empty (0xbf for map
-  // start, and 0xff for map end).
-  std::vector<uint8_t> in = {0xd8, 0x5a, 0, 0, 0, 2, 0xbf, 0xff};
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  ParseCBOR(span<uint8_t>(in.data(), in.size()), json_writer.get());
-  EXPECT_EQ(Error::OK, status.error);
-  EXPECT_EQ("{}", out);
-}
-
-TEST(ParseCBORTest, ParseCBORHelloWorld) {
-  const uint8_t kPayloadLen = 27;
-  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen};
-  bytes.push_back(0xbf);                       // start indef length map.
-  EncodeUTF8ForTest("msg", &bytes);            // key: msg
-  // Now write the value, the familiar "Hello, 🌎." where the globe is expressed
-  // as two utf16 chars.
-  bytes.push_back(/*major type=*/2 << 5 | /*additional info=*/20);
-  for (uint8_t ch : std::array<uint8_t, 20>{
-           {'H', 0, 'e', 0, 'l',  0,    'l',  0,    'o', 0,
-            ',', 0, ' ', 0, 0x3c, 0xd8, 0x0e, 0xdf, '.', 0}})
-    bytes.push_back(ch);
-  bytes.push_back(0xff);  // stop byte
-  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
-
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-  EXPECT_EQ(Error::OK, status.error);
-  EXPECT_EQ("{\"msg\":\"Hello, \\ud83c\\udf0e.\"}", out);
-}
-
-TEST(ParseCBORTest, UTF8IsSupportedInKeys) {
-  const uint8_t kPayloadLen = 11;
-  std::vector<uint8_t> bytes = {cbor::kInitialByteForEnvelope,
-                                cbor::kInitialByteFor32BitLengthByteString,
-                                0,
-                                0,
-                                0,
-                                kPayloadLen};
-  bytes.push_back(cbor::kInitialByteIndefiniteLengthMap);
-  EncodeUTF8ForTest("🌎", &bytes);  // Two UTF16 chars.
-  EncodeUTF8ForTest("☾", &bytes);  // Can be encoded as a single UTF16 char.
-  bytes.push_back(cbor::kStopByte);
-  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
-
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-  EXPECT_EQ(Error::OK, status.error);
-  EXPECT_EQ("{\"\\ud83c\\udf0e\":\"\\u263e\"}", out);
-}
-
-TEST(ParseCBORTest, NoInputError) {
-  std::vector<uint8_t> in = {};
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  ParseCBOR(span<uint8_t>(in.data(), in.size()), json_writer.get());
-  EXPECT_EQ(Error::CBOR_NO_INPUT, status.error);
-  EXPECT_EQ("", out);
-}
-
-TEST(ParseCBORTest, InvalidStartByteError) {
-  // Here we test that some actual json, which usually starts with {,
-  // is not considered CBOR. CBOR messages must start with 0x5a, the
-  // envelope start byte.
-  std::string json = "{\"msg\": \"Hello, world.\"}";
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  ParseCBOR(
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      json_writer.get());
-  EXPECT_EQ(Error::CBOR_INVALID_START_BYTE, status.error);
-  EXPECT_EQ("", out);
-}
-
-TEST(ParseCBORTest, UnexpectedEofExpectedValueError) {
-  constexpr uint8_t kPayloadLen = 5;
-  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
-                                0xbf};                             // map start
-  EncodeUTF8ForTest("key", &bytes);  // A key; so value would be next.
-  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-  EXPECT_EQ(Error::CBOR_UNEXPECTED_EOF_EXPECTED_VALUE, status.error);
-  EXPECT_EQ(static_cast<int64_t>(bytes.size()), status.pos);
-  EXPECT_EQ("", out);
-}
-
-TEST(ParseCBORTest, UnexpectedEofInArrayError) {
-  constexpr uint8_t kPayloadLen = 8;
-  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
-                                0xbf};  // The byte for starting a map.
-  EncodeUTF8ForTest("array", &bytes);   // A key; so value would be next.
-  bytes.push_back(0x9f);  // byte for indefinite length array start.
-  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-  EXPECT_EQ(Error::CBOR_UNEXPECTED_EOF_IN_ARRAY, status.error);
-  EXPECT_EQ(static_cast<int64_t>(bytes.size()), status.pos);
-  EXPECT_EQ("", out);
-}
-
-TEST(ParseCBORTest, UnexpectedEofInMapError) {
-  constexpr uint8_t kPayloadLen = 1;
-  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
-                                0xbf};  // The byte for starting a map.
-  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-  EXPECT_EQ(Error::CBOR_UNEXPECTED_EOF_IN_MAP, status.error);
-  EXPECT_EQ(7, status.pos);
-  EXPECT_EQ("", out);
-}
-
-TEST(ParseCBORTest, InvalidMapKeyError) {
-  constexpr uint8_t kPayloadLen = 2;
-  std::vector<uint8_t> bytes = {0xd8,       0x5a, 0,
-                                0,          0,    kPayloadLen,  // envelope
-                                0xbf,                           // map start
-                                7 << 5 | 22};  // null (not a valid map key)
-  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-  EXPECT_EQ(Error::CBOR_INVALID_MAP_KEY, status.error);
-  EXPECT_EQ(7, status.pos);
-  EXPECT_EQ("", out);
-}
-
-std::vector<uint8_t> MakeNestedCBOR(int depth) {
-  std::vector<uint8_t> bytes;
-  std::vector<EnvelopeEncoder> envelopes;
-  for (int ii = 0; ii < depth; ++ii) {
-    envelopes.emplace_back();
-    envelopes.back().EncodeStart(&bytes);
-    bytes.push_back(0xbf);  // indef length map start
-    EncodeUTF8ForTest("key", &bytes);
-  }
-  EncodeUTF8ForTest("innermost_value", &bytes);
-  for (int ii = 0; ii < depth; ++ii) {
-    bytes.push_back(0xff);  // stop byte, finishes map.
-    envelopes.back().EncodeStop(&bytes);
-    envelopes.pop_back();
-  }
-  return bytes;
-}
-
-TEST(ParseCBORTest, StackLimitExceededError) {
-  {  // Depth 3: no stack limit exceeded error and is easy to inspect.
-    std::vector<uint8_t> bytes = MakeNestedCBOR(3);
-    std::string out;
-    Status status;
-    std::unique_ptr<JSONParserHandler> json_writer =
-        NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-    ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-    EXPECT_EQ(Error::OK, status.error);
-    EXPECT_EQ(Status::npos(), status.pos);
-    EXPECT_EQ("{\"key\":{\"key\":{\"key\":\"innermost_value\"}}}", out);
-  }
-  {  // Depth 1000: no stack limit exceeded.
-    std::vector<uint8_t> bytes = MakeNestedCBOR(1000);
-    std::string out;
-    Status status;
-    std::unique_ptr<JSONParserHandler> json_writer =
-        NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-    ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-    EXPECT_EQ(Error::OK, status.error);
-    EXPECT_EQ(Status::npos(), status.pos);
-  }
-
-  // We just want to know the length of one opening map so we can compute
-  // where the error is encountered. So we look at a small example and find
-  // the second envelope start.
-  std::vector<uint8_t> small_example = MakeNestedCBOR(3);
-  int64_t opening_segment_size = 1;  // Start after the first envelope start.
-  while (opening_segment_size < static_cast<int64_t>(small_example.size()) &&
-         small_example[opening_segment_size] != 0xd8)
-    opening_segment_size++;
-
-  {  // Depth 1001: limit exceeded.
-    std::vector<uint8_t> bytes = MakeNestedCBOR(1001);
-    std::string out;
-    Status status;
-    std::unique_ptr<JSONParserHandler> json_writer =
-        NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-    ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-    EXPECT_EQ(Error::CBOR_STACK_LIMIT_EXCEEDED, status.error);
-    EXPECT_EQ(opening_segment_size * 1001, status.pos);
-  }
-  {  // Depth 1200: still limit exceeded, and at the same pos as for 1001
-    std::vector<uint8_t> bytes = MakeNestedCBOR(1200);
-    std::string out;
-    Status status;
-    std::unique_ptr<JSONParserHandler> json_writer =
-        NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-    ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-    EXPECT_EQ(Error::CBOR_STACK_LIMIT_EXCEEDED, status.error);
-    EXPECT_EQ(opening_segment_size * 1001, status.pos);
-  }
-}
-
-TEST(ParseCBORTest, UnsupportedValueError) {
-  constexpr uint8_t kPayloadLen = 6;
-  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
-                                0xbf};                             // map start
-  EncodeUTF8ForTest("key", &bytes);
-  int64_t error_pos = bytes.size();
-  bytes.push_back(6 << 5 | 5);  // tags aren't supported yet.
-  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
-
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-  EXPECT_EQ(Error::CBOR_UNSUPPORTED_VALUE, status.error);
-  EXPECT_EQ(error_pos, status.pos);
-  EXPECT_EQ("", out);
-}
-
-TEST(ParseCBORTest, InvalidString16Error) {
-  constexpr uint8_t kPayloadLen = 11;
-  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
-                                0xbf};                             // map start
-  EncodeUTF8ForTest("key", &bytes);
-  int64_t error_pos = bytes.size();
-  // a BYTE_STRING of length 5 as value; since we interpret these as string16,
-  // it's going to be invalid as each character would need two bytes, but
-  // 5 isn't divisible by 2.
-  bytes.push_back(2 << 5 | 5);
-  for (int ii = 0; ii < 5; ++ii) bytes.push_back(' ');
-  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-  EXPECT_EQ(Error::CBOR_INVALID_STRING16, status.error);
-  EXPECT_EQ(error_pos, status.pos);
-  EXPECT_EQ("", out);
-}
-
-TEST(ParseCBORTest, InvalidString8Error) {
-  constexpr uint8_t kPayloadLen = 6;
-  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
-                                0xbf};                             // map start
-  EncodeUTF8ForTest("key", &bytes);
-  int64_t error_pos = bytes.size();
-  // a STRING of length 5 as value, but we're at the end of the bytes array
-  // so it can't be decoded successfully.
-  bytes.push_back(3 << 5 | 5);
-  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-  EXPECT_EQ(Error::CBOR_INVALID_STRING8, status.error);
-  EXPECT_EQ(error_pos, status.pos);
-  EXPECT_EQ("", out);
-}
-
-TEST(ParseCBORTest, InvalidBinaryError) {
-  constexpr uint8_t kPayloadLen = 9;
-  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
-                                0xbf};                             // map start
-  EncodeUTF8ForTest("key", &bytes);
-  int64_t error_pos = bytes.size();
-  bytes.push_back(6 << 5 | 22);  // base64 hint for JSON; indicates binary
-  bytes.push_back(2 << 5 | 10);  // BYTE_STRING (major type 2) of length 10
-  // Just two garbage bytes, not enough for the binary.
-  bytes.push_back(0x31);
-  bytes.push_back(0x23);
-  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-  EXPECT_EQ(Error::CBOR_INVALID_BINARY, status.error);
-  EXPECT_EQ(error_pos, status.pos);
-  EXPECT_EQ("", out);
-}
-
-TEST(ParseCBORTest, InvalidDoubleError) {
-  constexpr uint8_t kPayloadLen = 8;
-  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
-                                0xbf};                             // map start
-  EncodeUTF8ForTest("key", &bytes);
-  int64_t error_pos = bytes.size();
-  bytes.push_back(7 << 5 | 27);  // initial byte for double
-  // Just two garbage bytes, not enough to represent an actual double.
-  bytes.push_back(0x31);
-  bytes.push_back(0x23);
-  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-  EXPECT_EQ(Error::CBOR_INVALID_DOUBLE, status.error);
-  EXPECT_EQ(error_pos, status.pos);
-  EXPECT_EQ("", out);
-}
-
-TEST(ParseCBORTest, InvalidSignedError) {
-  constexpr uint8_t kPayloadLen = 14;
-  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
-                                0xbf};                             // map start
-  EncodeUTF8ForTest("key", &bytes);
-  int64_t error_pos = bytes.size();
-  // uint64_t max is a perfectly fine value to encode as CBOR unsigned,
-  // but we don't support this since we only cover the int32_t range.
-  cbor_internals::WriteTokenStart(MajorType::UNSIGNED,
-                                  std::numeric_limits<uint64_t>::max(), &bytes);
-  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-  EXPECT_EQ(Error::CBOR_INVALID_INT32, status.error);
-  EXPECT_EQ(error_pos, status.pos);
-  EXPECT_EQ("", out);
-}
-
-TEST(ParseCBORTest, TrailingJunk) {
-  constexpr uint8_t kPayloadLen = 35;
-  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
-                                0xbf};                             // map start
-  EncodeUTF8ForTest("key", &bytes);
-  EncodeUTF8ForTest("value", &bytes);
-  bytes.push_back(0xff);  // Up to here, it's a perfectly fine msg.
-  int64_t error_pos = bytes.size();
-  EncodeUTF8ForTest("trailing junk", &bytes);
-
-  cbor_internals::WriteTokenStart(MajorType::UNSIGNED,
-                                  std::numeric_limits<uint64_t>::max(), &bytes);
-  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> json_writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
-  EXPECT_EQ(Error::CBOR_TRAILING_JUNK, status.error);
-  EXPECT_EQ(error_pos, status.pos);
-  EXPECT_EQ("", out);
-}
-}  // namespace inspector_protocol
diff --git a/third_party/inspector_protocol/encoding/encoding.cc b/third_party/inspector_protocol/encoding/encoding.cc
new file mode 100644
index 0000000..c2c6545a4
--- /dev/null
+++ b/third_party/inspector_protocol/encoding/encoding.cc
@@ -0,0 +1,1796 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "encoding.h"
+
+#include <cassert>
+#include <cstring>
+#include <limits>
+#include <stack>
+
+namespace inspector_protocol_encoding {
+namespace cbor {
+namespace {
+// Indicates the number of bits the "initial byte" needs to be shifted to the
+// right after applying |kMajorTypeMask| to produce the major type in the
+// lowermost bits.
+static constexpr uint8_t kMajorTypeBitShift = 5u;
+// Mask selecting the low-order 5 bits of the "initial byte", which is where
+// the additional information is encoded.
+static constexpr uint8_t kAdditionalInformationMask = 0x1f;
+// Mask selecting the high-order 3 bits of the "initial byte", which indicates
+// the major type of the encoded value.
+static constexpr uint8_t kMajorTypeMask = 0xe0;
+// Indicates the integer is in the following byte.
+static constexpr uint8_t kAdditionalInformation1Byte = 24u;
+// Indicates the integer is in the next 2 bytes.
+static constexpr uint8_t kAdditionalInformation2Bytes = 25u;
+// Indicates the integer is in the next 4 bytes.
+static constexpr uint8_t kAdditionalInformation4Bytes = 26u;
+// Indicates the integer is in the next 8 bytes.
+static constexpr uint8_t kAdditionalInformation8Bytes = 27u;
+
+// Encodes the initial byte, consisting of the |type| in the first 3 bits
+// followed by 5 bits of |additional_info|.
+constexpr uint8_t EncodeInitialByte(MajorType type, uint8_t additional_info) {
+  return (static_cast<uint8_t>(type) << kMajorTypeBitShift) |
+         (additional_info & kAdditionalInformationMask);
+}
+
+// TAG 24 indicates that what follows is a byte string which is
+// encoded in CBOR format. We use this as a wrapper for
+// maps and arrays, allowing us to skip them, because the
+// byte string carries its size (byte length).
+// https://tools.ietf.org/html/rfc7049#section-2.4.4.1
+static constexpr uint8_t kInitialByteForEnvelope =
+    EncodeInitialByte(MajorType::TAG, 24);
+// The initial byte for a byte string with at most 2^32 bytes
+// of payload. This is used for envelope encoding, even if
+// the byte string is shorter.
+static constexpr uint8_t kInitialByteFor32BitLengthByteString =
+    EncodeInitialByte(MajorType::BYTE_STRING, 26);
+
+// See RFC 7049 Section 2.2.1, indefinite length arrays / maps have additional
+// info = 31.
+static constexpr uint8_t kInitialByteIndefiniteLengthArray =
+    EncodeInitialByte(MajorType::ARRAY, 31);
+static constexpr uint8_t kInitialByteIndefiniteLengthMap =
+    EncodeInitialByte(MajorType::MAP, 31);
+// See RFC 7049 Section 2.3, Table 1; this is used for finishing indefinite
+// length maps / arrays.
+static constexpr uint8_t kStopByte =
+    EncodeInitialByte(MajorType::SIMPLE_VALUE, 31);
+
+// See RFC 7049 Section 2.3, Table 2.
+static constexpr uint8_t kEncodedTrue =
+    EncodeInitialByte(MajorType::SIMPLE_VALUE, 21);
+static constexpr uint8_t kEncodedFalse =
+    EncodeInitialByte(MajorType::SIMPLE_VALUE, 20);
+static constexpr uint8_t kEncodedNull =
+    EncodeInitialByte(MajorType::SIMPLE_VALUE, 22);
+static constexpr uint8_t kInitialByteForDouble =
+    EncodeInitialByte(MajorType::SIMPLE_VALUE, 27);
+
+// See RFC 7049 Table 3 and Section 2.4.4.2. This is used as a prefix for
+// arbitrary binary data encoded as BYTE_STRING.
+static constexpr uint8_t kExpectedConversionToBase64Tag =
+    EncodeInitialByte(MajorType::TAG, 22);
+
+// Writes the bytes for |v| to |out|, starting with the most significant byte.
+// See also: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
+template <typename T>
+void WriteBytesMostSignificantByteFirst(T v, std::vector<uint8_t>* out) {
+  for (int shift_bytes = sizeof(T) - 1; shift_bytes >= 0; --shift_bytes)
+    out->push_back(0xff & (v >> (shift_bytes * 8)));
+}
+
+// Extracts sizeof(T) bytes from |in| to extract a value of type T
+// (e.g. uint64_t, uint32_t, ...), most significant byte first.
+// See also: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
+template <typename T>
+T ReadBytesMostSignificantByteFirst(span<uint8_t> in) {
+  assert(static_cast<std::size_t>(in.size()) >= sizeof(T));
+  T result = 0;
+  for (std::size_t shift_bytes = 0; shift_bytes < sizeof(T); ++shift_bytes)
+    result |= T(in[sizeof(T) - 1 - shift_bytes]) << (shift_bytes * 8);
+  return result;
+}
+}  // namespace
+
+namespace internals {
+// Reads the start of a token with definitive size from |bytes|.
+// |type| is the major type as specified in RFC 7049 Section 2.1.
+// |value| is the payload (e.g. for MajorType::UNSIGNED) or is the size
+// (e.g. for BYTE_STRING).
+// If successful, returns the number of bytes read. Otherwise returns -1.
+int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value) {
+  if (bytes.empty())
+    return -1;
+  uint8_t initial_byte = bytes[0];
+  *type = MajorType((initial_byte & kMajorTypeMask) >> kMajorTypeBitShift);
+
+  uint8_t additional_information = initial_byte & kAdditionalInformationMask;
+  if (additional_information < 24) {
+    // Values 0-23 are encoded directly into the additional info of the
+    // initial byte.
+    *value = additional_information;
+    return 1;
+  }
+  if (additional_information == kAdditionalInformation1Byte) {
+    // Values 24-255 are encoded with one initial byte, followed by the value.
+    if (bytes.size() < 2)
+      return -1;
+    *value = ReadBytesMostSignificantByteFirst<uint8_t>(bytes.subspan(1));
+    return 2;
+  }
+  if (additional_information == kAdditionalInformation2Bytes) {
+    // Values 256-65535: 1 initial byte + 2 bytes payload.
+    if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint16_t))
+      return -1;
+    *value = ReadBytesMostSignificantByteFirst<uint16_t>(bytes.subspan(1));
+    return 3;
+  }
+  if (additional_information == kAdditionalInformation4Bytes) {
+    // 32 bit uint: 1 initial byte + 4 bytes payload.
+    if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint32_t))
+      return -1;
+    *value = ReadBytesMostSignificantByteFirst<uint32_t>(bytes.subspan(1));
+    return 5;
+  }
+  if (additional_information == kAdditionalInformation8Bytes) {
+    // 64 bit uint: 1 initial byte + 8 bytes payload.
+    if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint64_t))
+      return -1;
+    *value = ReadBytesMostSignificantByteFirst<uint64_t>(bytes.subspan(1));
+    return 9;
+  }
+  return -1;
+}
+
+// Writes the start of a token with |type|. The |value| may indicate the size,
+// or it may be the payload if the value is an unsigned integer.
+void WriteTokenStart(MajorType type,
+                     uint64_t value,
+                     std::vector<uint8_t>* encoded) {
+  if (value < 24) {
+    // Values 0-23 are encoded directly into the additional info of the
+    // initial byte.
+    encoded->push_back(EncodeInitialByte(type, /*additional_info=*/value));
+    return;
+  }
+  if (value <= std::numeric_limits<uint8_t>::max()) {
+    // Values 24-255 are encoded with one initial byte, followed by the value.
+    encoded->push_back(EncodeInitialByte(type, kAdditionalInformation1Byte));
+    encoded->push_back(value);
+    return;
+  }
+  if (value <= std::numeric_limits<uint16_t>::max()) {
+    // Values 256-65535: 1 initial byte + 2 bytes payload.
+    encoded->push_back(EncodeInitialByte(type, kAdditionalInformation2Bytes));
+    WriteBytesMostSignificantByteFirst<uint16_t>(value, encoded);
+    return;
+  }
+  if (value <= std::numeric_limits<uint32_t>::max()) {
+    // 32 bit uint: 1 initial byte + 4 bytes payload.
+    encoded->push_back(EncodeInitialByte(type, kAdditionalInformation4Bytes));
+    WriteBytesMostSignificantByteFirst<uint32_t>(static_cast<uint32_t>(value),
+                                                 encoded);
+    return;
+  }
+  // 64 bit uint: 1 initial byte + 8 bytes payload.
+  encoded->push_back(EncodeInitialByte(type, kAdditionalInformation8Bytes));
+  WriteBytesMostSignificantByteFirst<uint64_t>(value, encoded);
+}
+}  // namespace internals
+
+// =============================================================================
+// Detecting CBOR content
+// =============================================================================
+
+uint8_t InitialByteForEnvelope() {
+  return kInitialByteForEnvelope;
+}
+uint8_t InitialByteFor32BitLengthByteString() {
+  return kInitialByteFor32BitLengthByteString;
+}
+bool IsCBORMessage(span<uint8_t> msg) {
+  return msg.size() >= 6 && msg[0] == InitialByteForEnvelope() &&
+         msg[1] == InitialByteFor32BitLengthByteString();
+}
+
+// =============================================================================
+// Encoding invidiual CBOR items
+// =============================================================================
+
+uint8_t EncodeTrue() {
+  return kEncodedTrue;
+}
+uint8_t EncodeFalse() {
+  return kEncodedFalse;
+}
+uint8_t EncodeNull() {
+  return kEncodedNull;
+}
+
+uint8_t EncodeIndefiniteLengthArrayStart() {
+  return kInitialByteIndefiniteLengthArray;
+}
+
+uint8_t EncodeIndefiniteLengthMapStart() {
+  return kInitialByteIndefiniteLengthMap;
+}
+
+uint8_t EncodeStop() {
+  return kStopByte;
+}
+
+void EncodeInt32(int32_t value, std::vector<uint8_t>* out) {
+  if (value >= 0) {
+    internals::WriteTokenStart(MajorType::UNSIGNED, value, out);
+  } else {
+    uint64_t representation = static_cast<uint64_t>(-(value + 1));
+    internals::WriteTokenStart(MajorType::NEGATIVE, representation, out);
+  }
+}
+
+void EncodeString16(span<uint16_t> in, std::vector<uint8_t>* out) {
+  uint64_t byte_length = static_cast<uint64_t>(in.size_bytes());
+  internals::WriteTokenStart(MajorType::BYTE_STRING, byte_length, out);
+  // When emitting UTF16 characters, we always write the least significant byte
+  // first; this is because it's the native representation for X86.
+  // TODO(johannes): Implement a more efficient thing here later, e.g.
+  // casting *iff* the machine has this byte order.
+  // The wire format for UTF16 chars will probably remain the same
+  // (least significant byte first) since this way we can have
+  // golden files, unittests, etc. that port easily and universally.
+  // See also:
+  // https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
+  for (const uint16_t two_bytes : in) {
+    out->push_back(two_bytes);
+    out->push_back(two_bytes >> 8);
+  }
+}
+
+void EncodeString8(span<uint8_t> in, std::vector<uint8_t>* out) {
+  internals::WriteTokenStart(MajorType::STRING,
+                             static_cast<uint64_t>(in.size_bytes()), out);
+  out->insert(out->end(), in.begin(), in.end());
+}
+
+void EncodeFromLatin1(span<uint8_t> latin1, std::vector<uint8_t>* out) {
+  for (std::ptrdiff_t ii = 0; ii < latin1.size(); ++ii) {
+    if (latin1[ii] <= 127)
+      continue;
+    // If there's at least one non-ASCII char, convert to UTF8.
+    std::vector<uint8_t> utf8(latin1.begin(), latin1.begin() + ii);
+    for (; ii < latin1.size(); ++ii) {
+      if (latin1[ii] <= 127) {
+        utf8.push_back(latin1[ii]);
+      } else {
+        // 0xC0 means it's a UTF8 sequence with 2 bytes.
+        utf8.push_back((latin1[ii] >> 6) | 0xc0);
+        utf8.push_back((latin1[ii] | 0x80) & 0xbf);
+      }
+    }
+    EncodeString8(SpanFromVector(utf8), out);
+    return;
+  }
+  EncodeString8(latin1, out);
+}
+
+void EncodeFromUTF16(span<uint16_t> utf16, std::vector<uint8_t>* out) {
+  // If there's at least one non-ASCII char, encode as STRING16 (UTF16).
+  for (uint16_t ch : utf16) {
+    if (ch <= 127)
+      continue;
+    EncodeString16(utf16, out);
+    return;
+  }
+  // It's all US-ASCII, strip out every second byte and encode as UTF8.
+  internals::WriteTokenStart(MajorType::STRING,
+                             static_cast<uint64_t>(utf16.size()), out);
+  out->insert(out->end(), utf16.begin(), utf16.end());
+}
+
+void EncodeBinary(span<uint8_t> in, std::vector<uint8_t>* out) {
+  out->push_back(kExpectedConversionToBase64Tag);
+  uint64_t byte_length = static_cast<uint64_t>(in.size_bytes());
+  internals::WriteTokenStart(MajorType::BYTE_STRING, byte_length, out);
+  out->insert(out->end(), in.begin(), in.end());
+}
+
+// A double is encoded with a specific initial byte
+// (kInitialByteForDouble) plus the 64 bits of payload for its value.
+constexpr std::ptrdiff_t kEncodedDoubleSize = 1 + sizeof(uint64_t);
+
+// An envelope is encoded with a specific initial byte
+// (kInitialByteForEnvelope), plus the start byte for a BYTE_STRING with a 32
+// bit wide length, plus a 32 bit length for that string.
+constexpr std::ptrdiff_t kEncodedEnvelopeHeaderSize = 1 + 1 + sizeof(uint32_t);
+
+void EncodeDouble(double value, std::vector<uint8_t>* out) {
+  // The additional_info=27 indicates 64 bits for the double follow.
+  // See RFC 7049 Section 2.3, Table 1.
+  out->push_back(kInitialByteForDouble);
+  union {
+    double from_double;
+    uint64_t to_uint64;
+  } reinterpret;
+  reinterpret.from_double = value;
+  WriteBytesMostSignificantByteFirst<uint64_t>(reinterpret.to_uint64, out);
+}
+
+// =============================================================================
+// cbor::EnvelopeEncoder - for wrapping submessages
+// =============================================================================
+
+void EnvelopeEncoder::EncodeStart(std::vector<uint8_t>* out) {
+  assert(byte_size_pos_ == 0);
+  out->push_back(kInitialByteForEnvelope);
+  out->push_back(kInitialByteFor32BitLengthByteString);
+  byte_size_pos_ = out->size();
+  out->resize(out->size() + sizeof(uint32_t));
+}
+
+bool EnvelopeEncoder::EncodeStop(std::vector<uint8_t>* out) {
+  assert(byte_size_pos_ != 0);
+  // The byte size is the size of the payload, that is, all the
+  // bytes that were written past the byte size position itself.
+  uint64_t byte_size = out->size() - (byte_size_pos_ + sizeof(uint32_t));
+  // We store exactly 4 bytes, so at most INT32MAX, with most significant
+  // byte first.
+  if (byte_size > std::numeric_limits<uint32_t>::max())
+    return false;
+  for (int shift_bytes = sizeof(uint32_t) - 1; shift_bytes >= 0;
+       --shift_bytes) {
+    (*out)[byte_size_pos_++] = 0xff & (byte_size >> (shift_bytes * 8));
+  }
+  return true;
+}
+
+// =============================================================================
+// cbor::NewCBOREncoder - for encoding from a streaming parser
+// =============================================================================
+
+namespace {
+class CBOREncoder : public StreamingParserHandler {
+ public:
+  CBOREncoder(std::vector<uint8_t>* out, Status* status)
+      : out_(out), status_(status) {
+    *status_ = Status();
+  }
+
+  void HandleMapBegin() override {
+    envelopes_.emplace_back();
+    envelopes_.back().EncodeStart(out_);
+    out_->push_back(kInitialByteIndefiniteLengthMap);
+  }
+
+  void HandleMapEnd() override {
+    out_->push_back(kStopByte);
+    assert(!envelopes_.empty());
+    envelopes_.back().EncodeStop(out_);
+    envelopes_.pop_back();
+  }
+
+  void HandleArrayBegin() override {
+    envelopes_.emplace_back();
+    envelopes_.back().EncodeStart(out_);
+    out_->push_back(kInitialByteIndefiniteLengthArray);
+  }
+
+  void HandleArrayEnd() override {
+    out_->push_back(kStopByte);
+    assert(!envelopes_.empty());
+    envelopes_.back().EncodeStop(out_);
+    envelopes_.pop_back();
+  }
+
+  void HandleString8(span<uint8_t> chars) override {
+    EncodeString8(chars, out_);
+  }
+
+  void HandleString16(span<uint16_t> chars) override {
+    EncodeFromUTF16(chars, out_);
+  }
+
+  void HandleBinary(span<uint8_t> bytes) override { EncodeBinary(bytes, out_); }
+
+  void HandleDouble(double value) override { EncodeDouble(value, out_); }
+
+  void HandleInt32(int32_t value) override { EncodeInt32(value, out_); }
+
+  void HandleBool(bool value) override {
+    // See RFC 7049 Section 2.3, Table 2.
+    out_->push_back(value ? kEncodedTrue : kEncodedFalse);
+  }
+
+  void HandleNull() override {
+    // See RFC 7049 Section 2.3, Table 2.
+    out_->push_back(kEncodedNull);
+  }
+
+  void HandleError(Status error) override {
+    assert(!error.ok());
+    *status_ = error;
+    out_->clear();
+  }
+
+ private:
+  std::vector<uint8_t>* out_;
+  std::vector<EnvelopeEncoder> envelopes_;
+  Status* status_;
+};
+}  // namespace
+
+std::unique_ptr<StreamingParserHandler> NewCBOREncoder(
+    std::vector<uint8_t>* out,
+    Status* status) {
+  return std::unique_ptr<StreamingParserHandler>(new CBOREncoder(out, status));
+}
+
+// =============================================================================
+// cbor::CBORTokenizer - for parsing individual CBOR items
+// =============================================================================
+
+CBORTokenizer::CBORTokenizer(span<uint8_t> bytes) : bytes_(bytes) {
+  ReadNextToken(/*enter_envelope=*/false);
+}
+CBORTokenizer::~CBORTokenizer() {}
+
+CBORTokenTag CBORTokenizer::TokenTag() const {
+  return token_tag_;
+}
+
+void CBORTokenizer::Next() {
+  if (token_tag_ == CBORTokenTag::ERROR_VALUE ||
+      token_tag_ == CBORTokenTag::DONE)
+    return;
+  ReadNextToken(/*enter_envelope=*/false);
+}
+
+void CBORTokenizer::EnterEnvelope() {
+  assert(token_tag_ == CBORTokenTag::ENVELOPE);
+  ReadNextToken(/*enter_envelope=*/true);
+}
+
+Status CBORTokenizer::Status() const {
+  return status_;
+}
+
+int32_t CBORTokenizer::GetInt32() const {
+  assert(token_tag_ == CBORTokenTag::INT32);
+  // The range checks happen in ::ReadNextToken().
+  return static_cast<uint32_t>(
+      token_start_type_ == MajorType::UNSIGNED
+          ? token_start_internal_value_
+          : -static_cast<int64_t>(token_start_internal_value_) - 1);
+}
+
+double CBORTokenizer::GetDouble() const {
+  assert(token_tag_ == CBORTokenTag::DOUBLE);
+  union {
+    uint64_t from_uint64;
+    double to_double;
+  } reinterpret;
+  reinterpret.from_uint64 = ReadBytesMostSignificantByteFirst<uint64_t>(
+      bytes_.subspan(status_.pos + 1));
+  return reinterpret.to_double;
+}
+
+span<uint8_t> CBORTokenizer::GetString8() const {
+  assert(token_tag_ == CBORTokenTag::STRING8);
+  auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
+  return bytes_.subspan(status_.pos + (token_byte_length_ - length), length);
+}
+
+span<uint8_t> CBORTokenizer::GetString16WireRep() const {
+  assert(token_tag_ == CBORTokenTag::STRING16);
+  auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
+  return bytes_.subspan(status_.pos + (token_byte_length_ - length), length);
+}
+
+span<uint8_t> CBORTokenizer::GetBinary() const {
+  assert(token_tag_ == CBORTokenTag::BINARY);
+  auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
+  return bytes_.subspan(status_.pos + (token_byte_length_ - length), length);
+}
+
+span<uint8_t> CBORTokenizer::GetEnvelopeContents() const {
+  assert(token_tag_ == CBORTokenTag::ENVELOPE);
+  auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
+  return bytes_.subspan(status_.pos + kEncodedEnvelopeHeaderSize, length);
+}
+
+void CBORTokenizer::ReadNextToken(bool enter_envelope) {
+  if (enter_envelope) {
+    status_.pos += kEncodedEnvelopeHeaderSize;
+  } else {
+    status_.pos =
+        status_.pos == Status::npos() ? 0 : status_.pos + token_byte_length_;
+  }
+  status_.error = Error::OK;
+  if (status_.pos >= bytes_.size()) {
+    token_tag_ = CBORTokenTag::DONE;
+    return;
+  }
+  switch (bytes_[status_.pos]) {
+    case kStopByte:
+      SetToken(CBORTokenTag::STOP, 1);
+      return;
+    case kInitialByteIndefiniteLengthMap:
+      SetToken(CBORTokenTag::MAP_START, 1);
+      return;
+    case kInitialByteIndefiniteLengthArray:
+      SetToken(CBORTokenTag::ARRAY_START, 1);
+      return;
+    case kEncodedTrue:
+      SetToken(CBORTokenTag::TRUE_VALUE, 1);
+      return;
+    case kEncodedFalse:
+      SetToken(CBORTokenTag::FALSE_VALUE, 1);
+      return;
+    case kEncodedNull:
+      SetToken(CBORTokenTag::NULL_VALUE, 1);
+      return;
+    case kExpectedConversionToBase64Tag: {  // BINARY
+      int8_t bytes_read = internals::ReadTokenStart(
+          bytes_.subspan(status_.pos + 1), &token_start_type_,
+          &token_start_internal_value_);
+      int64_t token_byte_length = 1 + bytes_read + token_start_internal_value_;
+      if (-1 == bytes_read || token_start_type_ != MajorType::BYTE_STRING ||
+          status_.pos + token_byte_length > bytes_.size()) {
+        SetError(Error::CBOR_INVALID_BINARY);
+        return;
+      }
+      SetToken(CBORTokenTag::BINARY,
+               static_cast<std::ptrdiff_t>(token_byte_length));
+      return;
+    }
+    case kInitialByteForDouble: {  // DOUBLE
+      if (status_.pos + kEncodedDoubleSize > bytes_.size()) {
+        SetError(Error::CBOR_INVALID_DOUBLE);
+        return;
+      }
+      SetToken(CBORTokenTag::DOUBLE, kEncodedDoubleSize);
+      return;
+    }
+    case kInitialByteForEnvelope: {  // ENVELOPE
+      if (status_.pos + kEncodedEnvelopeHeaderSize > bytes_.size()) {
+        SetError(Error::CBOR_INVALID_ENVELOPE);
+        return;
+      }
+      // The envelope must be a byte string with 32 bit length.
+      if (bytes_[status_.pos + 1] != kInitialByteFor32BitLengthByteString) {
+        SetError(Error::CBOR_INVALID_ENVELOPE);
+        return;
+      }
+      // Read the length of the byte string.
+      token_start_internal_value_ = ReadBytesMostSignificantByteFirst<uint32_t>(
+          bytes_.subspan(status_.pos + 2));
+      // Make sure the payload is contained within the message.
+      if (token_start_internal_value_ + kEncodedEnvelopeHeaderSize +
+              status_.pos >
+          static_cast<std::size_t>(bytes_.size())) {
+        SetError(Error::CBOR_INVALID_ENVELOPE);
+        return;
+      }
+      auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
+      SetToken(CBORTokenTag::ENVELOPE, kEncodedEnvelopeHeaderSize + length);
+      return;
+    }
+    default: {
+      span<uint8_t> remainder =
+          bytes_.subspan(status_.pos, bytes_.size() - status_.pos);
+      assert(!remainder.empty());
+      int8_t token_start_length = internals::ReadTokenStart(
+          remainder, &token_start_type_, &token_start_internal_value_);
+      bool success = token_start_length != -1;
+      switch (token_start_type_) {
+        case MajorType::UNSIGNED:  // INT32.
+          if (!success || std::numeric_limits<int32_t>::max() <
+                              token_start_internal_value_) {
+            SetError(Error::CBOR_INVALID_INT32);
+            return;
+          }
+          SetToken(CBORTokenTag::INT32, token_start_length);
+          return;
+        case MajorType::NEGATIVE:  // INT32.
+          if (!success ||
+              std::numeric_limits<int32_t>::min() >
+                  -static_cast<int64_t>(token_start_internal_value_) - 1) {
+            SetError(Error::CBOR_INVALID_INT32);
+            return;
+          }
+          SetToken(CBORTokenTag::INT32, token_start_length);
+          return;
+        case MajorType::STRING: {  // STRING8.
+          if (!success || remainder.size() < static_cast<int64_t>(
+                                                 token_start_internal_value_)) {
+            SetError(Error::CBOR_INVALID_STRING8);
+            return;
+          }
+          auto length =
+              static_cast<std::ptrdiff_t>(token_start_internal_value_);
+          SetToken(CBORTokenTag::STRING8, token_start_length + length);
+          return;
+        }
+        case MajorType::BYTE_STRING: {  // STRING16.
+          if (!success ||
+              remainder.size() <
+                  static_cast<int64_t>(token_start_internal_value_) ||
+              // Must be divisible by 2 since UTF16 is 2 bytes per character.
+              token_start_internal_value_ & 1) {
+            SetError(Error::CBOR_INVALID_STRING16);
+            return;
+          }
+          auto length =
+              static_cast<std::ptrdiff_t>(token_start_internal_value_);
+          SetToken(CBORTokenTag::STRING16, token_start_length + length);
+          return;
+        }
+        case MajorType::ARRAY:
+        case MajorType::MAP:
+        case MajorType::TAG:
+        case MajorType::SIMPLE_VALUE:
+          SetError(Error::CBOR_UNSUPPORTED_VALUE);
+          return;
+      }
+    }
+  }
+}
+
+void CBORTokenizer::SetToken(CBORTokenTag token_tag,
+                             std::ptrdiff_t token_byte_length) {
+  token_tag_ = token_tag;
+  token_byte_length_ = token_byte_length;
+}
+
+void CBORTokenizer::SetError(Error error) {
+  token_tag_ = CBORTokenTag::ERROR_VALUE;
+  status_.error = error;
+}
+
+// =============================================================================
+// cbor::ParseCBOR - for receiving streaming parser events for CBOR messages
+// =============================================================================
+
+namespace {
+// When parsing CBOR, we limit recursion depth for objects and arrays
+// to this constant.
+static constexpr int kStackLimit = 200;
+
+// Below are three parsing routines for CBOR, which cover enough
+// to roundtrip JSON messages.
+bool ParseMap(int32_t stack_depth,
+              CBORTokenizer* tokenizer,
+              StreamingParserHandler* out);
+bool ParseArray(int32_t stack_depth,
+                CBORTokenizer* tokenizer,
+                StreamingParserHandler* out);
+bool ParseValue(int32_t stack_depth,
+                CBORTokenizer* tokenizer,
+                StreamingParserHandler* out);
+
+void ParseUTF16String(CBORTokenizer* tokenizer, StreamingParserHandler* out) {
+  std::vector<uint16_t> value;
+  span<uint8_t> rep = tokenizer->GetString16WireRep();
+  for (std::ptrdiff_t ii = 0; ii < rep.size(); ii += 2)
+    value.push_back((rep[ii + 1] << 8) | rep[ii]);
+  out->HandleString16(span<uint16_t>(value.data(), value.size()));
+  tokenizer->Next();
+}
+
+bool ParseUTF8String(CBORTokenizer* tokenizer, StreamingParserHandler* out) {
+  assert(tokenizer->TokenTag() == CBORTokenTag::STRING8);
+  out->HandleString8(tokenizer->GetString8());
+  tokenizer->Next();
+  return true;
+}
+
+bool ParseValue(int32_t stack_depth,
+                CBORTokenizer* tokenizer,
+                StreamingParserHandler* out) {
+  if (stack_depth > kStackLimit) {
+    out->HandleError(
+        Status{Error::CBOR_STACK_LIMIT_EXCEEDED, tokenizer->Status().pos});
+    return false;
+  }
+  // Skip past the envelope to get to what's inside.
+  if (tokenizer->TokenTag() == CBORTokenTag::ENVELOPE)
+    tokenizer->EnterEnvelope();
+  switch (tokenizer->TokenTag()) {
+    case CBORTokenTag::ERROR_VALUE:
+      out->HandleError(tokenizer->Status());
+      return false;
+    case CBORTokenTag::DONE:
+      out->HandleError(Status{Error::CBOR_UNEXPECTED_EOF_EXPECTED_VALUE,
+                              tokenizer->Status().pos});
+      return false;
+    case CBORTokenTag::TRUE_VALUE:
+      out->HandleBool(true);
+      tokenizer->Next();
+      return true;
+    case CBORTokenTag::FALSE_VALUE:
+      out->HandleBool(false);
+      tokenizer->Next();
+      return true;
+    case CBORTokenTag::NULL_VALUE:
+      out->HandleNull();
+      tokenizer->Next();
+      return true;
+    case CBORTokenTag::INT32:
+      out->HandleInt32(tokenizer->GetInt32());
+      tokenizer->Next();
+      return true;
+    case CBORTokenTag::DOUBLE:
+      out->HandleDouble(tokenizer->GetDouble());
+      tokenizer->Next();
+      return true;
+    case CBORTokenTag::STRING8:
+      return ParseUTF8String(tokenizer, out);
+    case CBORTokenTag::STRING16:
+      ParseUTF16String(tokenizer, out);
+      return true;
+    case CBORTokenTag::BINARY: {
+      out->HandleBinary(tokenizer->GetBinary());
+      tokenizer->Next();
+      return true;
+    }
+    case CBORTokenTag::MAP_START:
+      return ParseMap(stack_depth + 1, tokenizer, out);
+    case CBORTokenTag::ARRAY_START:
+      return ParseArray(stack_depth + 1, tokenizer, out);
+    default:
+      out->HandleError(
+          Status{Error::CBOR_UNSUPPORTED_VALUE, tokenizer->Status().pos});
+      return false;
+  }
+}
+
+// |bytes| must start with the indefinite length array byte, so basically,
+// ParseArray may only be called after an indefinite length array has been
+// detected.
+bool ParseArray(int32_t stack_depth,
+                CBORTokenizer* tokenizer,
+                StreamingParserHandler* out) {
+  assert(tokenizer->TokenTag() == CBORTokenTag::ARRAY_START);
+  tokenizer->Next();
+  out->HandleArrayBegin();
+  while (tokenizer->TokenTag() != CBORTokenTag::STOP) {
+    if (tokenizer->TokenTag() == CBORTokenTag::DONE) {
+      out->HandleError(
+          Status{Error::CBOR_UNEXPECTED_EOF_IN_ARRAY, tokenizer->Status().pos});
+      return false;
+    }
+    if (tokenizer->TokenTag() == CBORTokenTag::ERROR_VALUE) {
+      out->HandleError(tokenizer->Status());
+      return false;
+    }
+    // Parse value.
+    if (!ParseValue(stack_depth, tokenizer, out))
+      return false;
+  }
+  out->HandleArrayEnd();
+  tokenizer->Next();
+  return true;
+}
+
+// |bytes| must start with the indefinite length array byte, so basically,
+// ParseArray may only be called after an indefinite length array has been
+// detected.
+bool ParseMap(int32_t stack_depth,
+              CBORTokenizer* tokenizer,
+              StreamingParserHandler* out) {
+  assert(tokenizer->TokenTag() == CBORTokenTag::MAP_START);
+  out->HandleMapBegin();
+  tokenizer->Next();
+  while (tokenizer->TokenTag() != CBORTokenTag::STOP) {
+    if (tokenizer->TokenTag() == CBORTokenTag::DONE) {
+      out->HandleError(
+          Status{Error::CBOR_UNEXPECTED_EOF_IN_MAP, tokenizer->Status().pos});
+      return false;
+    }
+    if (tokenizer->TokenTag() == CBORTokenTag::ERROR_VALUE) {
+      out->HandleError(tokenizer->Status());
+      return false;
+    }
+    // Parse key.
+    if (tokenizer->TokenTag() == CBORTokenTag::STRING8) {
+      if (!ParseUTF8String(tokenizer, out))
+        return false;
+    } else if (tokenizer->TokenTag() == CBORTokenTag::STRING16) {
+      ParseUTF16String(tokenizer, out);
+    } else {
+      out->HandleError(
+          Status{Error::CBOR_INVALID_MAP_KEY, tokenizer->Status().pos});
+      return false;
+    }
+    // Parse value.
+    if (!ParseValue(stack_depth, tokenizer, out))
+      return false;
+  }
+  out->HandleMapEnd();
+  tokenizer->Next();
+  return true;
+}
+}  // namespace
+
+void ParseCBOR(span<uint8_t> bytes, StreamingParserHandler* out) {
+  if (bytes.empty()) {
+    out->HandleError(Status{Error::CBOR_NO_INPUT, 0});
+    return;
+  }
+  if (bytes[0] != kInitialByteForEnvelope) {
+    out->HandleError(Status{Error::CBOR_INVALID_START_BYTE, 0});
+    return;
+  }
+  CBORTokenizer tokenizer(bytes);
+  if (tokenizer.TokenTag() == CBORTokenTag::ERROR_VALUE) {
+    out->HandleError(tokenizer.Status());
+    return;
+  }
+  // We checked for the envelope start byte above, so the tokenizer
+  // must agree here, since it's not an error.
+  assert(tokenizer.TokenTag() == CBORTokenTag::ENVELOPE);
+  tokenizer.EnterEnvelope();
+  if (tokenizer.TokenTag() != CBORTokenTag::MAP_START) {
+    out->HandleError(
+        Status{Error::CBOR_MAP_START_EXPECTED, tokenizer.Status().pos});
+    return;
+  }
+  if (!ParseMap(/*stack_depth=*/1, &tokenizer, out))
+    return;
+  if (tokenizer.TokenTag() == CBORTokenTag::DONE)
+    return;
+  if (tokenizer.TokenTag() == CBORTokenTag::ERROR_VALUE) {
+    out->HandleError(tokenizer.Status());
+    return;
+  }
+  out->HandleError(Status{Error::CBOR_TRAILING_JUNK, tokenizer.Status().pos});
+}
+}  // namespace cbor
+
+namespace json {
+
+// =============================================================================
+// json::NewJSONEncoder - for encoding streaming parser events as JSON
+// =============================================================================
+
+namespace {
+// Prints |value| to |out| with 4 hex digits, most significant chunk first.
+void PrintHex(uint16_t value, std::string* out) {
+  for (int ii = 3; ii >= 0; --ii) {
+    int four_bits = 0xf & (value >> (4 * ii));
+    out->append(1, four_bits + ((four_bits <= 9) ? '0' : ('a' - 10)));
+  }
+}
+
+// In the writer below, we maintain a stack of State instances.
+// It is just enough to emit the appropriate delimiters and brackets
+// in JSON.
+enum class Container {
+  // Used for the top-level, initial state.
+  NONE,
+  // Inside a JSON object.
+  MAP,
+  // Inside a JSON array.
+  ARRAY
+};
+class State {
+ public:
+  explicit State(Container container) : container_(container) {}
+  void StartElement(std::string* out) {
+    assert(container_ != Container::NONE || size_ == 0);
+    if (size_ != 0) {
+      char delim = (!(size_ & 1) || container_ == Container::ARRAY) ? ',' : ':';
+      out->append(1, delim);
+    }
+    ++size_;
+  }
+  Container container() const { return container_; }
+
+ private:
+  Container container_ = Container::NONE;
+  int size_ = 0;
+};
+
+constexpr char kBase64Table[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "abcdefghijklmnopqrstuvwxyz0123456789+/";
+
+void Base64Encode(const span<uint8_t>& in, std::string* out) {
+  // The following three cases are based on the tables in the example
+  // section in https://en.wikipedia.org/wiki/Base64. We process three
+  // input bytes at a time, emitting 4 output bytes at a time.
+  std::ptrdiff_t ii = 0;
+
+  // While possible, process three input bytes.
+  for (; ii + 3 <= in.size(); ii += 3) {
+    uint32_t twentyfour_bits = (in[ii] << 16) | (in[ii + 1] << 8) | in[ii + 2];
+    out->push_back(kBase64Table[(twentyfour_bits >> 18)]);
+    out->push_back(kBase64Table[(twentyfour_bits >> 12) & 0x3f]);
+    out->push_back(kBase64Table[(twentyfour_bits >> 6) & 0x3f]);
+    out->push_back(kBase64Table[twentyfour_bits & 0x3f]);
+  }
+  if (ii + 2 <= in.size()) {  // Process two input bytes.
+    uint32_t twentyfour_bits = (in[ii] << 16) | (in[ii + 1] << 8);
+    out->push_back(kBase64Table[(twentyfour_bits >> 18)]);
+    out->push_back(kBase64Table[(twentyfour_bits >> 12) & 0x3f]);
+    out->push_back(kBase64Table[(twentyfour_bits >> 6) & 0x3f]);
+    out->push_back('=');  // Emit padding.
+    return;
+  }
+  if (ii + 1 <= in.size()) {  // Process a single input byte.
+    uint32_t twentyfour_bits = (in[ii] << 16);
+    out->push_back(kBase64Table[(twentyfour_bits >> 18)]);
+    out->push_back(kBase64Table[(twentyfour_bits >> 12) & 0x3f]);
+    out->push_back('=');  // Emit padding.
+    out->push_back('=');  // Emit padding.
+  }
+}
+
+// Implements a handler for JSON parser events to emit a JSON string.
+class JSONEncoder : public StreamingParserHandler {
+ public:
+  JSONEncoder(const Platform* platform, std::string* out, Status* status)
+      : platform_(platform), out_(out), status_(status) {
+    *status_ = Status();
+    state_.emplace(Container::NONE);
+  }
+
+  void HandleMapBegin() override {
+    if (!status_->ok())
+      return;
+    assert(!state_.empty());
+    state_.top().StartElement(out_);
+    state_.emplace(Container::MAP);
+    out_->append("{");
+  }
+
+  void HandleMapEnd() override {
+    if (!status_->ok())
+      return;
+    assert(state_.size() >= 2 && state_.top().container() == Container::MAP);
+    state_.pop();
+    out_->append("}");
+  }
+
+  void HandleArrayBegin() override {
+    if (!status_->ok())
+      return;
+    state_.top().StartElement(out_);
+    state_.emplace(Container::ARRAY);
+    out_->append("[");
+  }
+
+  void HandleArrayEnd() override {
+    if (!status_->ok())
+      return;
+    assert(state_.size() >= 2 && state_.top().container() == Container::ARRAY);
+    state_.pop();
+    out_->append("]");
+  }
+
+  void HandleString16(span<uint16_t> chars) override {
+    if (!status_->ok())
+      return;
+    state_.top().StartElement(out_);
+    out_->append("\"");
+    for (const uint16_t ch : chars) {
+      if (ch == '"') {
+        out_->append("\\\"");
+      } else if (ch == '\\') {
+        out_->append("\\\\");
+      } else if (ch == '\b') {
+        out_->append("\\b");
+      } else if (ch == '\f') {
+        out_->append("\\f");
+      } else if (ch == '\n') {
+        out_->append("\\n");
+      } else if (ch == '\r') {
+        out_->append("\\r");
+      } else if (ch == '\t') {
+        out_->append("\\t");
+      } else if (ch >= 32 && ch <= 126) {
+        out_->append(1, ch);
+      } else {
+        out_->append("\\u");
+        PrintHex(ch, out_);
+      }
+    }
+    out_->append("\"");
+  }
+
+  void HandleString8(span<uint8_t> chars) override {
+    if (!status_->ok())
+      return;
+    state_.top().StartElement(out_);
+    out_->append("\"");
+    for (std::ptrdiff_t ii = 0; ii < chars.size(); ++ii) {
+      uint8_t c = chars[ii];
+      if (c == '"') {
+        out_->append("\\\"");
+      } else if (c == '\\') {
+        out_->append("\\\\");
+      } else if (c == '\b') {
+        out_->append("\\b");
+      } else if (c == '\f') {
+        out_->append("\\f");
+      } else if (c == '\n') {
+        out_->append("\\n");
+      } else if (c == '\r') {
+        out_->append("\\r");
+      } else if (c == '\t') {
+        out_->append("\\t");
+      } else if (c >= 32 && c <= 126) {
+        out_->append(1, c);
+      } else if (c < 32) {
+        out_->append("\\u");
+        PrintHex(static_cast<uint16_t>(c), out_);
+      } else {
+        // Inspect the leading byte to figure out how long the utf8
+        // byte sequence is; while doing this initialize |codepoint|
+        // with the first few bits.
+        // See table in: https://en.wikipedia.org/wiki/UTF-8
+        // byte one is 110x xxxx -> 2 byte utf8 sequence
+        // byte one is 1110 xxxx -> 3 byte utf8 sequence
+        // byte one is 1111 0xxx -> 4 byte utf8 sequence
+        uint32_t codepoint;
+        int num_bytes_left;
+        if ((c & 0xe0) == 0xc0) {  // 2 byte utf8 sequence
+          num_bytes_left = 1;
+          codepoint = c & 0x1f;
+        } else if ((c & 0xf0) == 0xe0) {  // 3 byte utf8 sequence
+          num_bytes_left = 2;
+          codepoint = c & 0x0f;
+        } else if ((c & 0xf8) == 0xf0) {  // 4 byte utf8 sequence
+          codepoint = c & 0x07;
+          num_bytes_left = 3;
+        } else {
+          continue;  // invalid leading byte
+        }
+
+        // If we have enough bytes in our input, decode the remaining ones
+        // belonging to this Unicode character into |codepoint|.
+        if (ii + num_bytes_left > chars.size())
+          continue;
+        while (num_bytes_left > 0) {
+          c = chars[++ii];
+          --num_bytes_left;
+          // Check the next byte is a continuation byte, that is 10xx xxxx.
+          if ((c & 0xc0) != 0x80)
+            continue;
+          codepoint = (codepoint << 6) | (c & 0x3f);
+        }
+
+        // Disallow overlong encodings for ascii characters, as these
+        // would include " and other characters significant to JSON
+        // string termination / control.
+        if (codepoint < 0x7f)
+          continue;
+        // Invalid in UTF8, and can't be represented in UTF16 anyway.
+        if (codepoint > 0x10ffff)
+          continue;
+
+        // So, now we transcode to UTF16,
+        // using the math described at https://en.wikipedia.org/wiki/UTF-16,
+        // for either one or two 16 bit characters.
+        if (codepoint < 0xffff) {
+          out_->append("\\u");
+          PrintHex(static_cast<uint16_t>(codepoint), out_);
+          continue;
+        }
+        codepoint -= 0x10000;
+        // high surrogate
+        out_->append("\\u");
+        PrintHex(static_cast<uint16_t>((codepoint >> 10) + 0xd800), out_);
+        // low surrogate
+        out_->append("\\u");
+        PrintHex(static_cast<uint16_t>((codepoint & 0x3ff) + 0xdc00), out_);
+      }
+    }
+    out_->append("\"");
+  }
+
+  void HandleBinary(span<uint8_t> bytes) override {
+    if (!status_->ok())
+      return;
+    state_.top().StartElement(out_);
+    out_->append("\"");
+    Base64Encode(bytes, out_);
+    out_->append("\"");
+  }
+
+  void HandleDouble(double value) override {
+    if (!status_->ok())
+      return;
+    state_.top().StartElement(out_);
+    std::unique_ptr<char[]> str_value = platform_->DToStr(value);
+
+    // DToStr may fail to emit a 0 before the decimal dot. E.g. this is
+    // the case in base::NumberToString in Chromium (which is based on
+    // dmg_fp). So, much like
+    // https://cs.chromium.org/chromium/src/base/json/json_writer.cc
+    // we probe for this and emit the leading 0 anyway if necessary.
+    const char* chars = str_value.get();
+    if (chars[0] == '.') {
+      out_->append("0");
+    } else if (chars[0] == '-' && chars[1] == '.') {
+      out_->append("-0");
+      ++chars;
+    }
+    out_->append(chars);
+  }
+
+  void HandleInt32(int32_t value) override {
+    if (!status_->ok())
+      return;
+    state_.top().StartElement(out_);
+    out_->append(std::to_string(value));
+  }
+
+  void HandleBool(bool value) override {
+    if (!status_->ok())
+      return;
+    state_.top().StartElement(out_);
+    out_->append(value ? "true" : "false");
+  }
+
+  void HandleNull() override {
+    if (!status_->ok())
+      return;
+    state_.top().StartElement(out_);
+    out_->append("null");
+  }
+
+  void HandleError(Status error) override {
+    assert(!error.ok());
+    *status_ = error;
+    out_->clear();
+  }
+
+ private:
+  const Platform* platform_;
+  std::string* out_;
+  Status* status_;
+  std::stack<State> state_;
+};
+}  // namespace
+
+std::unique_ptr<StreamingParserHandler> NewJSONEncoder(const Platform* platform,
+                                                       std::string* out,
+                                                       Status* status) {
+  return std::unique_ptr<StreamingParserHandler>(
+      new JSONEncoder(platform, out, status));
+}
+
+// =============================================================================
+// json::ParseJSON - for receiving streaming parser events for JSON.
+// =============================================================================
+
+namespace {
+const int kStackLimit = 200;
+
+enum Token {
+  ObjectBegin,
+  ObjectEnd,
+  ArrayBegin,
+  ArrayEnd,
+  StringLiteral,
+  Number,
+  BoolTrue,
+  BoolFalse,
+  NullToken,
+  ListSeparator,
+  ObjectPairSeparator,
+  InvalidToken,
+  NoInput
+};
+
+const char* const kNullString = "null";
+const char* const kTrueString = "true";
+const char* const kFalseString = "false";
+
+template <typename Char>
+class JsonParser {
+ public:
+  JsonParser(const Platform* platform, StreamingParserHandler* handler)
+      : platform_(platform), handler_(handler) {}
+
+  void Parse(const Char* start, std::size_t length) {
+    start_pos_ = start;
+    const Char* end = start + length;
+    const Char* tokenEnd;
+    ParseValue(start, end, &tokenEnd, 0);
+    if (tokenEnd != end) {
+      HandleError(Error::JSON_PARSER_UNPROCESSED_INPUT_REMAINS, tokenEnd);
+    }
+  }
+
+ private:
+  bool CharsToDouble(const uint16_t* chars,
+                     std::size_t length,
+                     double* result) {
+    std::string buffer;
+    buffer.reserve(length + 1);
+    for (std::size_t ii = 0; ii < length; ++ii) {
+      bool is_ascii = !(chars[ii] & ~0x7F);
+      if (!is_ascii)
+        return false;
+      buffer.push_back(static_cast<char>(chars[ii]));
+    }
+    return platform_->StrToD(buffer.c_str(), result);
+  }
+
+  bool CharsToDouble(const uint8_t* chars, std::size_t length, double* result) {
+    std::string buffer(reinterpret_cast<const char*>(chars), length);
+    return platform_->StrToD(buffer.c_str(), result);
+  }
+
+  static bool ParseConstToken(const Char* start,
+                              const Char* end,
+                              const Char** token_end,
+                              const char* token) {
+    // |token| is \0 terminated, it's one of the constants at top of the file.
+    while (start < end && *token != '\0' && *start++ == *token++) {
+    }
+    if (*token != '\0')
+      return false;
+    *token_end = start;
+    return true;
+  }
+
+  static bool ReadInt(const Char* start,
+                      const Char* end,
+                      const Char** token_end,
+                      bool allow_leading_zeros) {
+    if (start == end)
+      return false;
+    bool has_leading_zero = '0' == *start;
+    int length = 0;
+    while (start < end && '0' <= *start && *start <= '9') {
+      ++start;
+      ++length;
+    }
+    if (!length)
+      return false;
+    if (!allow_leading_zeros && length > 1 && has_leading_zero)
+      return false;
+    *token_end = start;
+    return true;
+  }
+
+  static bool ParseNumberToken(const Char* start,
+                               const Char* end,
+                               const Char** token_end) {
+    // We just grab the number here. We validate the size in DecodeNumber.
+    // According to RFC4627, a valid number is: [minus] int [frac] [exp]
+    if (start == end)
+      return false;
+    Char c = *start;
+    if ('-' == c)
+      ++start;
+
+    if (!ReadInt(start, end, &start, /*allow_leading_zeros=*/false))
+      return false;
+    if (start == end) {
+      *token_end = start;
+      return true;
+    }
+
+    // Optional fraction part
+    c = *start;
+    if ('.' == c) {
+      ++start;
+      if (!ReadInt(start, end, &start, /*allow_leading_zeros=*/true))
+        return false;
+      if (start == end) {
+        *token_end = start;
+        return true;
+      }
+      c = *start;
+    }
+
+    // Optional exponent part
+    if ('e' == c || 'E' == c) {
+      ++start;
+      if (start == end)
+        return false;
+      c = *start;
+      if ('-' == c || '+' == c) {
+        ++start;
+        if (start == end)
+          return false;
+      }
+      if (!ReadInt(start, end, &start, /*allow_leading_zeros=*/true))
+        return false;
+    }
+
+    *token_end = start;
+    return true;
+  }
+
+  static bool ReadHexDigits(const Char* start,
+                            const Char* end,
+                            const Char** token_end,
+                            int digits) {
+    if (end - start < digits)
+      return false;
+    for (int i = 0; i < digits; ++i) {
+      Char c = *start++;
+      if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') ||
+            ('A' <= c && c <= 'F')))
+        return false;
+    }
+    *token_end = start;
+    return true;
+  }
+
+  static bool ParseStringToken(const Char* start,
+                               const Char* end,
+                               const Char** token_end) {
+    while (start < end) {
+      Char c = *start++;
+      if ('\\' == c) {
+        if (start == end)
+          return false;
+        c = *start++;
+        // Make sure the escaped char is valid.
+        switch (c) {
+          case 'x':
+            if (!ReadHexDigits(start, end, &start, 2))
+              return false;
+            break;
+          case 'u':
+            if (!ReadHexDigits(start, end, &start, 4))
+              return false;
+            break;
+          case '\\':
+          case '/':
+          case 'b':
+          case 'f':
+          case 'n':
+          case 'r':
+          case 't':
+          case 'v':
+          case '"':
+            break;
+          default:
+            return false;
+        }
+      } else if ('"' == c) {
+        *token_end = start;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  static bool SkipComment(const Char* start,
+                          const Char* end,
+                          const Char** comment_end) {
+    if (start == end)
+      return false;
+
+    if (*start != '/' || start + 1 >= end)
+      return false;
+    ++start;
+
+    if (*start == '/') {
+      // Single line comment, read to newline.
+      for (++start; start < end; ++start) {
+        if (*start == '\n' || *start == '\r') {
+          *comment_end = start + 1;
+          return true;
+        }
+      }
+      *comment_end = end;
+      // Comment reaches end-of-input, which is fine.
+      return true;
+    }
+
+    if (*start == '*') {
+      Char previous = '\0';
+      // Block comment, read until end marker.
+      for (++start; start < end; previous = *start++) {
+        if (previous == '*' && *start == '/') {
+          *comment_end = start + 1;
+          return true;
+        }
+      }
+      // Block comment must close before end-of-input.
+      return false;
+    }
+
+    return false;
+  }
+
+  static bool IsSpaceOrNewLine(Char c) {
+    // \v = vertial tab; \f = form feed page break.
+    return c == ' ' || c == '\n' || c == '\v' || c == '\f' || c == '\r' ||
+           c == '\t';
+  }
+
+  static void SkipWhitespaceAndComments(const Char* start,
+                                        const Char* end,
+                                        const Char** whitespace_end) {
+    while (start < end) {
+      if (IsSpaceOrNewLine(*start)) {
+        ++start;
+      } else if (*start == '/') {
+        const Char* comment_end;
+        if (!SkipComment(start, end, &comment_end))
+          break;
+        start = comment_end;
+      } else {
+        break;
+      }
+    }
+    *whitespace_end = start;
+  }
+
+  static Token ParseToken(const Char* start,
+                          const Char* end,
+                          const Char** tokenStart,
+                          const Char** token_end) {
+    SkipWhitespaceAndComments(start, end, tokenStart);
+    start = *tokenStart;
+
+    if (start == end)
+      return NoInput;
+
+    switch (*start) {
+      case 'n':
+        if (ParseConstToken(start, end, token_end, kNullString))
+          return NullToken;
+        break;
+      case 't':
+        if (ParseConstToken(start, end, token_end, kTrueString))
+          return BoolTrue;
+        break;
+      case 'f':
+        if (ParseConstToken(start, end, token_end, kFalseString))
+          return BoolFalse;
+        break;
+      case '[':
+        *token_end = start + 1;
+        return ArrayBegin;
+      case ']':
+        *token_end = start + 1;
+        return ArrayEnd;
+      case ',':
+        *token_end = start + 1;
+        return ListSeparator;
+      case '{':
+        *token_end = start + 1;
+        return ObjectBegin;
+      case '}':
+        *token_end = start + 1;
+        return ObjectEnd;
+      case ':':
+        *token_end = start + 1;
+        return ObjectPairSeparator;
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+      case '-':
+        if (ParseNumberToken(start, end, token_end))
+          return Number;
+        break;
+      case '"':
+        if (ParseStringToken(start + 1, end, token_end))
+          return StringLiteral;
+        break;
+    }
+    return InvalidToken;
+  }
+
+  static int HexToInt(Char c) {
+    if ('0' <= c && c <= '9')
+      return c - '0';
+    if ('A' <= c && c <= 'F')
+      return c - 'A' + 10;
+    if ('a' <= c && c <= 'f')
+      return c - 'a' + 10;
+    assert(false);  // Unreachable.
+    return 0;
+  }
+
+  static bool DecodeString(const Char* start,
+                           const Char* end,
+                           std::vector<uint16_t>* output) {
+    if (start == end)
+      return true;
+    if (start > end)
+      return false;
+    output->reserve(end - start);
+    while (start < end) {
+      uint16_t c = *start++;
+      // If the |Char| we're dealing with is really a byte, then
+      // we have utf8 here, and we need to check for multibyte characters
+      // and transcode them to utf16 (either one or two utf16 chars).
+      if (sizeof(Char) == sizeof(uint8_t) && c >= 0x7f) {
+        // Inspect the leading byte to figure out how long the utf8
+        // byte sequence is; while doing this initialize |codepoint|
+        // with the first few bits.
+        // See table in: https://en.wikipedia.org/wiki/UTF-8
+        // byte one is 110x xxxx -> 2 byte utf8 sequence
+        // byte one is 1110 xxxx -> 3 byte utf8 sequence
+        // byte one is 1111 0xxx -> 4 byte utf8 sequence
+        uint32_t codepoint;
+        int num_bytes_left;
+        if ((c & 0xe0) == 0xc0) {  // 2 byte utf8 sequence
+          num_bytes_left = 1;
+          codepoint = c & 0x1f;
+        } else if ((c & 0xf0) == 0xe0) {  // 3 byte utf8 sequence
+          num_bytes_left = 2;
+          codepoint = c & 0x0f;
+        } else if ((c & 0xf8) == 0xf0) {  // 4 byte utf8 sequence
+          codepoint = c & 0x07;
+          num_bytes_left = 3;
+        } else {
+          return false;  // invalid leading byte
+        }
+
+        // If we have enough bytes in our inpput, decode the remaining ones
+        // belonging to this Unicode character into |codepoint|.
+        if (start + num_bytes_left > end)
+          return false;
+        while (num_bytes_left > 0) {
+          c = *start++;
+          --num_bytes_left;
+          // Check the next byte is a continuation byte, that is 10xx xxxx.
+          if ((c & 0xc0) != 0x80)
+            return false;
+          codepoint = (codepoint << 6) | (c & 0x3f);
+        }
+
+        // Disallow overlong encodings for ascii characters, as these
+        // would include " and other characters significant to JSON
+        // string termination / control.
+        if (codepoint < 0x7f)
+          return false;
+        // Invalid in UTF8, and can't be represented in UTF16 anyway.
+        if (codepoint > 0x10ffff)
+          return false;
+
+        // So, now we transcode to UTF16,
+        // using the math described at https://en.wikipedia.org/wiki/UTF-16,
+        // for either one or two 16 bit characters.
+        if (codepoint < 0xffff) {
+          output->push_back(codepoint);
+          continue;
+        }
+        codepoint -= 0x10000;
+        output->push_back((codepoint >> 10) + 0xd800);    // high surrogate
+        output->push_back((codepoint & 0x3ff) + 0xdc00);  // low surrogate
+        continue;
+      }
+      if ('\\' != c) {
+        output->push_back(c);
+        continue;
+      }
+      if (start == end)
+        return false;
+      c = *start++;
+
+      if (c == 'x') {
+        // \x is not supported.
+        return false;
+      }
+
+      switch (c) {
+        case '"':
+        case '/':
+        case '\\':
+          break;
+        case 'b':
+          c = '\b';
+          break;
+        case 'f':
+          c = '\f';
+          break;
+        case 'n':
+          c = '\n';
+          break;
+        case 'r':
+          c = '\r';
+          break;
+        case 't':
+          c = '\t';
+          break;
+        case 'v':
+          c = '\v';
+          break;
+        case 'u':
+          c = (HexToInt(*start) << 12) + (HexToInt(*(start + 1)) << 8) +
+              (HexToInt(*(start + 2)) << 4) + HexToInt(*(start + 3));
+          start += 4;
+          break;
+        default:
+          return false;
+      }
+      output->push_back(c);
+    }
+    return true;
+  }
+
+  void ParseValue(const Char* start,
+                  const Char* end,
+                  const Char** value_token_end,
+                  int depth) {
+    if (depth > kStackLimit) {
+      HandleError(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, start);
+      return;
+    }
+    const Char* token_start;
+    const Char* token_end;
+    Token token = ParseToken(start, end, &token_start, &token_end);
+    switch (token) {
+      case NoInput:
+        HandleError(Error::JSON_PARSER_NO_INPUT, token_start);
+        return;
+      case InvalidToken:
+        HandleError(Error::JSON_PARSER_INVALID_TOKEN, token_start);
+        return;
+      case NullToken:
+        handler_->HandleNull();
+        break;
+      case BoolTrue:
+        handler_->HandleBool(true);
+        break;
+      case BoolFalse:
+        handler_->HandleBool(false);
+        break;
+      case Number: {
+        double value;
+        if (!CharsToDouble(token_start, token_end - token_start, &value)) {
+          HandleError(Error::JSON_PARSER_INVALID_NUMBER, token_start);
+          return;
+        }
+        if (value >= std::numeric_limits<int32_t>::min() &&
+            value <= std::numeric_limits<int32_t>::max() &&
+            static_cast<int32_t>(value) == value)
+          handler_->HandleInt32(static_cast<int32_t>(value));
+        else
+          handler_->HandleDouble(value);
+        break;
+      }
+      case StringLiteral: {
+        std::vector<uint16_t> value;
+        bool ok = DecodeString(token_start + 1, token_end - 1, &value);
+        if (!ok) {
+          HandleError(Error::JSON_PARSER_INVALID_STRING, token_start);
+          return;
+        }
+        handler_->HandleString16(span<uint16_t>(value.data(), value.size()));
+        break;
+      }
+      case ArrayBegin: {
+        handler_->HandleArrayBegin();
+        start = token_end;
+        token = ParseToken(start, end, &token_start, &token_end);
+        while (token != ArrayEnd) {
+          ParseValue(start, end, &token_end, depth + 1);
+          if (error_)
+            return;
+
+          // After a list value, we expect a comma or the end of the list.
+          start = token_end;
+          token = ParseToken(start, end, &token_start, &token_end);
+          if (token == ListSeparator) {
+            start = token_end;
+            token = ParseToken(start, end, &token_start, &token_end);
+            if (token == ArrayEnd) {
+              HandleError(Error::JSON_PARSER_UNEXPECTED_ARRAY_END, token_start);
+              return;
+            }
+          } else if (token != ArrayEnd) {
+            // Unexpected value after list value. Bail out.
+            HandleError(Error::JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED,
+                        token_start);
+            return;
+          }
+        }
+        handler_->HandleArrayEnd();
+        break;
+      }
+      case ObjectBegin: {
+        handler_->HandleMapBegin();
+        start = token_end;
+        token = ParseToken(start, end, &token_start, &token_end);
+        while (token != ObjectEnd) {
+          if (token != StringLiteral) {
+            HandleError(Error::JSON_PARSER_STRING_LITERAL_EXPECTED,
+                        token_start);
+            return;
+          }
+          std::vector<uint16_t> key;
+          if (!DecodeString(token_start + 1, token_end - 1, &key)) {
+            HandleError(Error::JSON_PARSER_INVALID_STRING, token_start);
+            return;
+          }
+          handler_->HandleString16(span<uint16_t>(key.data(), key.size()));
+          start = token_end;
+
+          token = ParseToken(start, end, &token_start, &token_end);
+          if (token != ObjectPairSeparator) {
+            HandleError(Error::JSON_PARSER_COLON_EXPECTED, token_start);
+            return;
+          }
+          start = token_end;
+
+          ParseValue(start, end, &token_end, depth + 1);
+          if (error_)
+            return;
+          start = token_end;
+
+          // After a key/value pair, we expect a comma or the end of the
+          // object.
+          token = ParseToken(start, end, &token_start, &token_end);
+          if (token == ListSeparator) {
+            start = token_end;
+            token = ParseToken(start, end, &token_start, &token_end);
+            if (token == ObjectEnd) {
+              HandleError(Error::JSON_PARSER_UNEXPECTED_MAP_END, token_start);
+              return;
+            }
+          } else if (token != ObjectEnd) {
+            // Unexpected value after last object value. Bail out.
+            HandleError(Error::JSON_PARSER_COMMA_OR_MAP_END_EXPECTED,
+                        token_start);
+            return;
+          }
+        }
+        handler_->HandleMapEnd();
+        break;
+      }
+
+      default:
+        // We got a token that's not a value.
+        HandleError(Error::JSON_PARSER_VALUE_EXPECTED, token_start);
+        return;
+    }
+
+    SkipWhitespaceAndComments(token_end, end, value_token_end);
+  }
+
+  void HandleError(Error error, const Char* pos) {
+    assert(error != Error::OK);
+    if (!error_) {
+      handler_->HandleError(Status{error, pos - start_pos_});
+      error_ = true;
+    }
+  }
+
+  const Char* start_pos_ = nullptr;
+  bool error_ = false;
+  const Platform* platform_;
+  StreamingParserHandler* handler_;
+};
+}  // namespace
+
+void ParseJSON(const Platform* platform,
+               span<uint8_t> chars,
+               StreamingParserHandler* handler) {
+  JsonParser<uint8_t> parser(platform, handler);
+  parser.Parse(chars.data(), chars.size());
+}
+
+void ParseJSON(const Platform* platform,
+               span<uint16_t> chars,
+               StreamingParserHandler* handler) {
+  JsonParser<uint16_t> parser(platform, handler);
+  parser.Parse(chars.data(), chars.size());
+}
+}  // namespace json
+}  // namespace inspector_protocol_encoding
diff --git a/third_party/inspector_protocol/lib/CBOR_h.template b/third_party/inspector_protocol/encoding/encoding.h
similarity index 65%
rename from third_party/inspector_protocol/lib/CBOR_h.template
rename to third_party/inspector_protocol/encoding/encoding.h
index 9d28adb..b958ff4 100644
--- a/third_party/inspector_protocol/lib/CBOR_h.template
+++ b/third_party/inspector_protocol/encoding/encoding.h
@@ -1,75 +1,21 @@
-{# This template is generated by gen_cbor_templates.py. #}
-// Generated by lib/CBOR_h.template.
-
 // Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef {{"_".join(config.protocol.namespace)}}_CBOR_h
-#define {{"_".join(config.protocol.namespace)}}_CBOR_h
+#ifndef INSPECTOR_PROTOCOL_ENCODING_ENCODING_H_
+#define INSPECTOR_PROTOCOL_ENCODING_ENCODING_H_
 
 #include <cstddef>
 #include <cstdint>
 #include <memory>
+#include <string>
 #include <vector>
 
-{% for namespace in config.protocol.namespace %}
-namespace {{namespace}} {
-{% endfor %}
+namespace inspector_protocol_encoding {
 
-// ===== encoding/status.h =====
-
-// Error codes.
-enum class Error {
-  OK = 0,
-  // JSON parsing errors - json_parser.{h,cc}.
-  JSON_PARSER_UNPROCESSED_INPUT_REMAINS = 0x01,
-  JSON_PARSER_STACK_LIMIT_EXCEEDED = 0x02,
-  JSON_PARSER_NO_INPUT = 0x03,
-  JSON_PARSER_INVALID_TOKEN = 0x04,
-  JSON_PARSER_INVALID_NUMBER = 0x05,
-  JSON_PARSER_INVALID_STRING = 0x06,
-  JSON_PARSER_UNEXPECTED_ARRAY_END = 0x07,
-  JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED = 0x08,
-  JSON_PARSER_STRING_LITERAL_EXPECTED = 0x09,
-  JSON_PARSER_COLON_EXPECTED = 0x0a,
-  JSON_PARSER_UNEXPECTED_OBJECT_END = 0x0b,
-  JSON_PARSER_COMMA_OR_OBJECT_END_EXPECTED = 0x0c,
-  JSON_PARSER_VALUE_EXPECTED = 0x0d,
-
-  CBOR_INVALID_INT32 = 0x0e,
-  CBOR_INVALID_DOUBLE = 0x0f,
-  CBOR_INVALID_ENVELOPE = 0x10,
-  CBOR_INVALID_STRING8 = 0x11,
-  CBOR_INVALID_STRING16 = 0x12,
-  CBOR_INVALID_BINARY = 0x13,
-  CBOR_UNSUPPORTED_VALUE = 0x14,
-  CBOR_NO_INPUT = 0x15,
-  CBOR_INVALID_START_BYTE = 0x16,
-  CBOR_UNEXPECTED_EOF_EXPECTED_VALUE = 0x17,
-  CBOR_UNEXPECTED_EOF_IN_ARRAY = 0x18,
-  CBOR_UNEXPECTED_EOF_IN_MAP = 0x19,
-  CBOR_INVALID_MAP_KEY = 0x1a,
-  CBOR_STACK_LIMIT_EXCEEDED = 0x1b,
-  CBOR_STRING8_MUST_BE_7BIT = 0x1c,
-  CBOR_TRAILING_JUNK = 0x1d,
-  CBOR_MAP_START_EXPECTED = 0x1e,
-};
-
-// A status value with position that can be copied. The default status
-// is OK. Usually, error status values should come with a valid position.
-struct Status {
-  static constexpr std::ptrdiff_t npos() { return -1; }
-
-  bool ok() const { return error == Error::OK; }
-
-  Error error = Error::OK;
-  std::ptrdiff_t pos = npos();
-  Status(Error error, std::ptrdiff_t pos) : error(error), pos(pos) {}
-  Status() = default;
-};
-
-// ===== encoding/span.h =====
+// =============================================================================
+// span - sequence of bytes
+// =============================================================================
 
 // This template is similar to std::span, which will be included in C++20.  Like
 // std::span it uses ptrdiff_t, which is signed (and thus a bit annoying
@@ -107,19 +53,78 @@
   index_type size_;
 };
 
-// ===== encoding/json_parser_handler.h =====
+template <typename T>
+span<T> SpanFromVector(const std::vector<T>& v) {
+  return span<T>(v.data(), v.size());
+}
 
-// Handler interface for JSON parser events. See also json_parser.h.
-class JSONParserHandler {
+inline span<uint8_t> SpanFromStdString(const std::string& v) {
+  return span<uint8_t>(reinterpret_cast<const uint8_t*>(v.data()), v.size());
+}
+
+// Error codes.
+enum class Error {
+  OK = 0,
+  // JSON parsing errors - json_parser.{h,cc}.
+  JSON_PARSER_UNPROCESSED_INPUT_REMAINS = 0x01,
+  JSON_PARSER_STACK_LIMIT_EXCEEDED = 0x02,
+  JSON_PARSER_NO_INPUT = 0x03,
+  JSON_PARSER_INVALID_TOKEN = 0x04,
+  JSON_PARSER_INVALID_NUMBER = 0x05,
+  JSON_PARSER_INVALID_STRING = 0x06,
+  JSON_PARSER_UNEXPECTED_ARRAY_END = 0x07,
+  JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED = 0x08,
+  JSON_PARSER_STRING_LITERAL_EXPECTED = 0x09,
+  JSON_PARSER_COLON_EXPECTED = 0x0a,
+  JSON_PARSER_UNEXPECTED_MAP_END = 0x0b,
+  JSON_PARSER_COMMA_OR_MAP_END_EXPECTED = 0x0c,
+  JSON_PARSER_VALUE_EXPECTED = 0x0d,
+
+  CBOR_INVALID_INT32 = 0x0e,
+  CBOR_INVALID_DOUBLE = 0x0f,
+  CBOR_INVALID_ENVELOPE = 0x10,
+  CBOR_INVALID_STRING8 = 0x11,
+  CBOR_INVALID_STRING16 = 0x12,
+  CBOR_INVALID_BINARY = 0x13,
+  CBOR_UNSUPPORTED_VALUE = 0x14,
+  CBOR_NO_INPUT = 0x15,
+  CBOR_INVALID_START_BYTE = 0x16,
+  CBOR_UNEXPECTED_EOF_EXPECTED_VALUE = 0x17,
+  CBOR_UNEXPECTED_EOF_IN_ARRAY = 0x18,
+  CBOR_UNEXPECTED_EOF_IN_MAP = 0x19,
+  CBOR_INVALID_MAP_KEY = 0x1a,
+  CBOR_STACK_LIMIT_EXCEEDED = 0x1b,
+  CBOR_STRING8_MUST_BE_7BIT = 0x1c,
+  CBOR_TRAILING_JUNK = 0x1d,
+  CBOR_MAP_START_EXPECTED = 0x1e,
+};
+
+// A status value with position that can be copied. The default status
+// is OK. Usually, error status values should come with a valid position.
+struct Status {
+  static constexpr std::ptrdiff_t npos() { return -1; }
+
+  bool ok() const { return error == Error::OK; }
+
+  Error error = Error::OK;
+  std::ptrdiff_t pos = npos();
+  Status(Error error, std::ptrdiff_t pos) : error(error), pos(pos) {}
+  Status() = default;
+};
+
+// Handler interface for parser events emitted by a streaming parser.
+// See cbor::NewCBOREncoder, cbor::ParseCBOR, json::NewJSONEncoder,
+// json::ParseJSON.
+class StreamingParserHandler {
  public:
-  virtual ~JSONParserHandler() = default;
-  virtual void HandleObjectBegin() = 0;
-  virtual void HandleObjectEnd() = 0;
+  virtual ~StreamingParserHandler() = default;
+  virtual void HandleMapBegin() = 0;
+  virtual void HandleMapEnd() = 0;
   virtual void HandleArrayBegin() = 0;
   virtual void HandleArrayEnd() = 0;
   virtual void HandleString8(span<uint8_t> chars) = 0;
   virtual void HandleString16(span<uint16_t> chars) = 0;
-  virtual void HandleBinary(std::vector<uint8_t> bytes) = 0;
+  virtual void HandleBinary(span<uint8_t> bytes) = 0;
   virtual void HandleDouble(double value) = 0;
   virtual void HandleInt32(int32_t value) = 0;
   virtual void HandleBool(bool value) = 0;
@@ -132,97 +137,7 @@
   virtual void HandleError(Status error) = 0;
 };
 
-// ===== encoding/cbor_internals.h =====
-
 namespace cbor {
-enum class MajorType;
-}
-
-namespace cbor_internals {
-
-// Reads the start of a token with definitive size from |bytes|.
-// |type| is the major type as specified in RFC 7049 Section 2.1.
-// |value| is the payload (e.g. for MajorType::UNSIGNED) or is the size
-// (e.g. for BYTE_STRING).
-// If successful, returns the number of bytes read. Otherwise returns -1.
-int8_t ReadTokenStart(span<uint8_t> bytes, cbor::MajorType* type,
-                      uint64_t* value);
-
-// Writes the start of a token with |type|. The |value| may indicate the size,
-// or it may be the payload if the value is an unsigned integer.
-void WriteTokenStart(cbor::MajorType type, uint64_t value,
-                     std::vector<uint8_t>* encoded);
-}  // namespace cbor_internals
-
-// ===== encoding/cbor.h =====
-
-
-namespace cbor {
-
-// The major types from RFC 7049 Section 2.1.
-enum class MajorType {
-  UNSIGNED = 0,
-  NEGATIVE = 1,
-  BYTE_STRING = 2,
-  STRING = 3,
-  ARRAY = 4,
-  MAP = 5,
-  TAG = 6,
-  SIMPLE_VALUE = 7
-};
-
-// Indicates the number of bits the "initial byte" needs to be shifted to the
-// right after applying |kMajorTypeMask| to produce the major type in the
-// lowermost bits.
-static constexpr uint8_t kMajorTypeBitShift = 5u;
-// Mask selecting the low-order 5 bits of the "initial byte", which is where
-// the additional information is encoded.
-static constexpr uint8_t kAdditionalInformationMask = 0x1f;
-// Mask selecting the high-order 3 bits of the "initial byte", which indicates
-// the major type of the encoded value.
-static constexpr uint8_t kMajorTypeMask = 0xe0;
-// Indicates the integer is in the following byte.
-static constexpr uint8_t kAdditionalInformation1Byte = 24u;
-// Indicates the integer is in the next 2 bytes.
-static constexpr uint8_t kAdditionalInformation2Bytes = 25u;
-// Indicates the integer is in the next 4 bytes.
-static constexpr uint8_t kAdditionalInformation4Bytes = 26u;
-// Indicates the integer is in the next 8 bytes.
-static constexpr uint8_t kAdditionalInformation8Bytes = 27u;
-
-// Encodes the initial byte, consisting of the |type| in the first 3 bits
-// followed by 5 bits of |additional_info|.
-constexpr uint8_t EncodeInitialByte(MajorType type, uint8_t additional_info) {
-  return (static_cast<uint8_t>(type) << kMajorTypeBitShift) |
-         (additional_info & kAdditionalInformationMask);
-}
-
-// TAG 24 indicates that what follows is a byte string which is
-// encoded in CBOR format. We use this as a wrapper for
-// maps and arrays, allowing us to skip them, because the
-// byte string carries its size (byte length).
-// https://tools.ietf.org/html/rfc7049#section-2.4.4.1
-static constexpr uint8_t kInitialByteForEnvelope =
-    EncodeInitialByte(MajorType::TAG, 24);
-// The initial byte for a byte string with at most 2^32 bytes
-// of payload. This is used for envelope encoding, even if
-// the byte string is shorter.
-static constexpr uint8_t kInitialByteFor32BitLengthByteString =
-    EncodeInitialByte(MajorType::BYTE_STRING, 26);
-
-// See RFC 7049 Section 2.2.1, indefinite length arrays / maps have additional
-// info = 31.
-static constexpr uint8_t kInitialByteIndefiniteLengthArray =
-    EncodeInitialByte(MajorType::ARRAY, 31);
-static constexpr uint8_t kInitialByteIndefiniteLengthMap =
-    EncodeInitialByte(MajorType::MAP, 31);
-// See RFC 7049 Section 2.3, Table 1; this is used for finishing indefinite
-// length maps / arrays.
-static constexpr uint8_t kStopByte =
-    EncodeInitialByte(MajorType::SIMPLE_VALUE, 31);
-
-}  // namespace cbor
-
 // The binary encoding for the inspector protocol follows the CBOR specification
 // (RFC 7049). Additional constraints:
 // - Only indefinite length maps and arrays are supported.
@@ -239,12 +154,38 @@
 //   as CBOR BYTE_STRING (major type 2). For such strings, the number of
 //   bytes encoded must be even.
 // - UTF8 strings (major type 3) are supported.
-// - 7 bit US-ASCII strings must always be encoded as UTF8 strings, not
+// - 7 bit US-ASCII strings must always be encoded as UTF8 strings, never
 //   as UTF16 strings.
 // - Arbitrary byte arrays, in the inspector protocol called 'binary',
 //   are encoded as BYTE_STRING (major type 2), prefixed with a byte
 //   indicating base64 when rendered as JSON.
 
+// =============================================================================
+// Detecting CBOR content
+// =============================================================================
+
+// The first byte for an envelope, which we use for wrapping dictionaries
+// and arrays; and the byte that indicates a byte string with 32 bit length.
+// These two bytes start an envelope, and thereby also any CBOR message
+// produced or consumed by this protocol. See also |EnvelopeEncoder| below.
+uint8_t InitialByteForEnvelope();
+uint8_t InitialByteFor32BitLengthByteString();
+
+// Checks whether |msg| is a cbor message.
+bool IsCBORMessage(span<uint8_t> msg);
+
+// =============================================================================
+// Encoding individual CBOR items
+// =============================================================================
+
+// Some constants for CBOR tokens that only take a single byte on the wire.
+uint8_t EncodeTrue();
+uint8_t EncodeFalse();
+uint8_t EncodeNull();
+uint8_t EncodeIndefiniteLengthArrayStart();
+uint8_t EncodeIndefiniteLengthMapStart();
+uint8_t EncodeStop();
+
 // Encodes |value| as |UNSIGNED| (major type 0) iff >= 0, or |NEGATIVE|
 // (major type 1) iff < 0.
 void EncodeInt32(int32_t value, std::vector<uint8_t>* out);
@@ -275,13 +216,9 @@
 // with additional info = 27, followed by 8 bytes in big endian.
 void EncodeDouble(double value, std::vector<uint8_t>* out);
 
-// Some constants for CBOR tokens that only take a single byte on the wire.
-uint8_t EncodeTrue();
-uint8_t EncodeFalse();
-uint8_t EncodeNull();
-uint8_t EncodeIndefiniteLengthArrayStart();
-uint8_t EncodeIndefiniteLengthMapStart();
-uint8_t EncodeStop();
+// =============================================================================
+// cbor::EnvelopeEncoder - for wrapping submessages
+// =============================================================================
 
 // An envelope indicates the byte length of a wrapped item.
 // We use this for maps and array, which allows the decoder
@@ -304,20 +241,23 @@
   std::size_t byte_size_pos_ = 0;
 };
 
-// This can be used to convert from JSON to CBOR, by passing the
-// return value to the routines in json_parser.h.  The handler will encode into
-// |out|, and iff an error occurs it will set |status| to an error and clear
-// |out|. Otherwise, |status.ok()| will be |true|.
-std::unique_ptr<JSONParserHandler> NewJSONToCBOREncoder(
-    std::vector<uint8_t>* out, Status* status);
+// =============================================================================
+// cbor::NewCBOREncoder - for encoding from a streaming parser
+// =============================================================================
 
-// Parses a CBOR encoded message from |bytes|, sending JSON events to
-// |json_out|. If an error occurs, sends |out->HandleError|, and parsing stops.
-// The client is responsible for discarding the already received information in
-// that case.
-void ParseCBOR(span<uint8_t> bytes, JSONParserHandler* json_out);
+// This can be used to convert to CBOR, by passing the return value to a parser
+// that drives it. The handler will encode into |out|, and iff an error occurs
+// it will set |status| to an error and clear |out|. Otherwise, |status.ok()|
+// will be |true|.
+std::unique_ptr<StreamingParserHandler> NewCBOREncoder(
+    std::vector<uint8_t>* out,
+    Status* status);
 
-// Tags for the tokens within a CBOR message that CBORStream understands.
+// =============================================================================
+// cbor::CBORTokenizer - for parsing individual CBOR items
+// =============================================================================
+
+// Tags for the tokens within a CBOR message that CBORTokenizer understands.
 // Note that this is not the same terminology as the CBOR spec (RFC 7049),
 // but rather, our adaptation. For instance, we lump unsigned and signed
 // major type into INT32 here (and disallow values outside the int32_t range).
@@ -357,6 +297,18 @@
   DONE,
 };
 
+// The major types from RFC 7049 Section 2.1.
+enum class MajorType {
+  UNSIGNED = 0,
+  NEGATIVE = 1,
+  BYTE_STRING = 2,
+  STRING = 3,
+  ARRAY = 4,
+  MAP = 5,
+  TAG = 6,
+  SIMPLE_VALUE = 7
+};
+
 // CBORTokenizer segments a CBOR message, presenting the tokens therein as
 // numbers, strings, etc. This is not a complete CBOR parser, but makes it much
 // easier to implement one (e.g. ParseCBOR, above). It can also be used to parse
@@ -403,6 +355,9 @@
   // To be called only if ::TokenTag() == CBORTokenTag::BINARY.
   span<uint8_t> GetBinary() const;
 
+  // To be called only if ::TokenTag() == CBORTokenTag::ENVELOPE.
+  span<uint8_t> GetEnvelopeContents() const;
+
  private:
   void ReadNextToken(bool enter_envelope);
   void SetToken(CBORTokenTag token, std::ptrdiff_t token_byte_length);
@@ -412,14 +367,70 @@
   CBORTokenTag token_tag_;
   struct Status status_;
   std::ptrdiff_t token_byte_length_;
-  cbor::MajorType token_start_type_;
+  MajorType token_start_type_;
   uint64_t token_start_internal_value_;
 };
 
-void DumpCBOR(span<uint8_t> cbor);
+// =============================================================================
+// cbor::ParseCBOR - for receiving streaming parser events for CBOR messages
+// =============================================================================
 
+// Parses a CBOR encoded message from |bytes|, sending events to
+// |out|. If an error occurs, sends |out->HandleError|, and parsing stops.
+// The client is responsible for discarding the already received information in
+// that case.
+void ParseCBOR(span<uint8_t> bytes, StreamingParserHandler* out);
 
-{% for namespace in config.protocol.namespace %}
-} // namespace {{namespace}}
-{% endfor %}
-#endif // !defined({{"_".join(config.protocol.namespace)}}_CBOR_h)
+namespace internals {  // Exposed only for writing tests.
+int8_t ReadTokenStart(span<uint8_t> bytes,
+                      cbor::MajorType* type,
+                      uint64_t* value);
+
+void WriteTokenStart(cbor::MajorType type,
+                     uint64_t value,
+                     std::vector<uint8_t>* encoded);
+}  // namespace internals
+}  // namespace cbor
+
+namespace json {
+// Client code must provide an instance. Implementation should delegate
+// to whatever is appropriate.
+class Platform {
+ public:
+  virtual ~Platform() = default;
+  // Parses |str| into |result|. Returns false iff there are
+  // leftover characters or parsing errors.
+  virtual bool StrToD(const char* str, double* result) const = 0;
+
+  // Prints |value| in a format suitable for JSON.
+  virtual std::unique_ptr<char[]> DToStr(double value) const = 0;
+};
+
+// =============================================================================
+// json::NewJSONEncoder - for encoding streaming parser events as JSON
+// =============================================================================
+
+// Returns a handler object which will write ascii characters to |out|.
+// |status->ok()| will be false iff the handler routine HandleError() is called.
+// In that case, we'll stop emitting output.
+// Except for calling the HandleError routine at any time, the client
+// code must call the Handle* methods in an order in which they'd occur
+// in valid JSON; otherwise we may crash (the code uses assert).
+std::unique_ptr<StreamingParserHandler> NewJSONEncoder(const Platform* platform,
+                                                       std::string* out,
+                                                       Status* status);
+
+// =============================================================================
+// json::ParseJSON - for receiving streaming parser events for JSON
+// =============================================================================
+
+void ParseJSON(const Platform* platform,
+               span<uint8_t> chars,
+               StreamingParserHandler* handler);
+void ParseJSON(const Platform* platform,
+               span<uint16_t> chars,
+               StreamingParserHandler* handler);
+}  // namespace json
+}  // namespace inspector_protocol_encoding
+
+#endif  // INSPECTOR_PROTOCOL_ENCODING_ENCODING_H_
diff --git a/third_party/inspector_protocol/encoding/encoding_test.cc b/third_party/inspector_protocol/encoding/encoding_test.cc
new file mode 100644
index 0000000..a03c7fc
--- /dev/null
+++ b/third_party/inspector_protocol/encoding/encoding_test.cc
@@ -0,0 +1,1595 @@
+// 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 "encoding.h"
+
+#include <array>
+#include <clocale>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::ElementsAreArray;
+
+namespace inspector_protocol_encoding {
+
+std::string UTF16ToUTF8(span<uint16_t> in) {
+  std::string out;
+  bool success = base::UTF16ToUTF8(
+      reinterpret_cast<const base::char16*>(in.data()), in.size(), &out);
+  CHECK(success);
+  return out;
+}
+
+std::vector<uint16_t> UTF8ToUTF16(span<uint8_t> in) {
+  base::string16 tmp;
+  bool success = base::UTF8ToUTF16(reinterpret_cast<const char*>(in.data()),
+                                   in.size(), &tmp);
+  CHECK(success);
+  return std::vector<uint16_t>(tmp.begin(), tmp.end());
+}
+
+class TestPlatform : public json::Platform {
+  bool StrToD(const char* str, double* result) const override {
+    // This is not thread-safe
+    // (see https://en.cppreference.com/w/cpp/locale/setlocale)
+    // but good enough for a unittest.
+    const char* saved_locale = std::setlocale(LC_NUMERIC, nullptr);
+    char* end;
+    *result = std::strtod(str, &end);
+    std::setlocale(LC_NUMERIC, saved_locale);
+    if (errno == ERANGE) {
+      // errno must be reset, e.g. see the example here:
+      // https://en.cppreference.com/w/cpp/string/byte/strtof
+      errno = 0;
+      return false;
+    }
+    return end == str + strlen(str);
+  }
+
+  std::unique_ptr<char[]> DToStr(double value) const override {
+    std::stringstream ss;
+    ss.imbue(std::locale("C"));
+    ss << value;
+    std::string str = ss.str();
+    std::unique_ptr<char[]> result(new char[str.size() + 1]);
+    memcpy(result.get(), str.c_str(), str.size() + 1);
+    return result;
+  }
+};
+
+json::Platform* GetTestPlatform() {
+  static TestPlatform* platform = new TestPlatform;
+  return platform;
+}
+
+// =============================================================================
+// span - sequence of bytes
+// =============================================================================
+
+template <typename T>
+class SpanTest : public ::testing::Test {};
+
+using TestTypes = ::testing::Types<uint8_t, uint16_t>;
+TYPED_TEST_SUITE(SpanTest, TestTypes);
+
+TYPED_TEST(SpanTest, Empty) {
+  span<TypeParam> empty;
+  EXPECT_TRUE(empty.empty());
+  EXPECT_EQ(0, empty.size());
+  EXPECT_EQ(0, empty.size_bytes());
+  EXPECT_EQ(empty.begin(), empty.end());
+}
+
+TYPED_TEST(SpanTest, SingleItem) {
+  TypeParam single_item = 42;
+  span<TypeParam> singular(&single_item, 1);
+  EXPECT_FALSE(singular.empty());
+  EXPECT_EQ(1, singular.size());
+  EXPECT_EQ(sizeof(TypeParam), static_cast<size_t>(singular.size_bytes()));
+  EXPECT_EQ(singular.begin() + 1, singular.end());
+  EXPECT_EQ(42, singular[0]);
+}
+
+TYPED_TEST(SpanTest, FiveItems) {
+  std::vector<TypeParam> test_input = {31, 32, 33, 34, 35};
+  span<TypeParam> five_items(test_input.data(), 5);
+  EXPECT_FALSE(five_items.empty());
+  EXPECT_EQ(5, five_items.size());
+  EXPECT_EQ(sizeof(TypeParam) * 5,
+            static_cast<size_t>(five_items.size_bytes()));
+  EXPECT_EQ(five_items.begin() + 5, five_items.end());
+  EXPECT_EQ(31, five_items[0]);
+  EXPECT_EQ(32, five_items[1]);
+  EXPECT_EQ(33, five_items[2]);
+  EXPECT_EQ(34, five_items[3]);
+  EXPECT_EQ(35, five_items[4]);
+  span<TypeParam> three_items = five_items.subspan(2);
+  EXPECT_EQ(3, three_items.size());
+  EXPECT_EQ(33, three_items[0]);
+  EXPECT_EQ(34, three_items[1]);
+  EXPECT_EQ(35, three_items[2]);
+  span<TypeParam> two_items = five_items.subspan(2, 2);
+  EXPECT_EQ(2, two_items.size());
+  EXPECT_EQ(33, two_items[0]);
+  EXPECT_EQ(34, two_items[1]);
+}
+
+namespace cbor {
+
+// =============================================================================
+// Detecting CBOR content
+// =============================================================================
+
+TEST(IsCBORMessage, SomeSmokeTests) {
+  std::vector<uint8_t> empty;
+  EXPECT_FALSE(IsCBORMessage(SpanFromVector(empty)));
+  std::vector<uint8_t> hello = {'H', 'e', 'l', 'o', ' ', 't',
+                                'h', 'e', 'r', 'e', '!'};
+  EXPECT_FALSE(IsCBORMessage(SpanFromVector(hello)));
+  std::vector<uint8_t> example = {0xd8, 0x5a, 0, 0, 0, 0};
+  EXPECT_TRUE(IsCBORMessage(SpanFromVector(example)));
+  std::vector<uint8_t> one = {0xd8, 0x5a, 0, 0, 0, 1, 1};
+  EXPECT_TRUE(IsCBORMessage(SpanFromVector(one)));
+}
+
+// =============================================================================
+// Encoding individual CBOR items
+// cbor::CBORTokenizer - for parsing individual CBOR items
+// =============================================================================
+
+//
+// EncodeInt32 / CBORTokenTag::INT32
+//
+TEST(EncodeDecodeInt32Test, Roundtrips23) {
+  // This roundtrips the int32_t value 23 through the pair of EncodeInt32 /
+  // CBORTokenizer; this is interesting since 23 is encoded as a single byte.
+  std::vector<uint8_t> encoded;
+  EncodeInt32(23, &encoded);
+  // first three bits: major type = 0; remaining five bits: additional info =
+  // value 23.
+  EXPECT_THAT(encoded, ElementsAreArray(std::array<uint8_t, 1>{{23}}));
+
+  // Reverse direction: decode with CBORTokenizer.
+  CBORTokenizer tokenizer(SpanFromVector(encoded));
+  EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag());
+  EXPECT_EQ(23, tokenizer.GetInt32());
+  tokenizer.Next();
+  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
+}
+
+TEST(EncodeDecodeInt32Test, RoundtripsUint8) {
+  // This roundtrips the int32_t value 42 through the pair of EncodeInt32 /
+  // CBORTokenizer. This is different from Roundtrip23 because 42 is encoded
+  // in an extra byte after the initial one.
+  std::vector<uint8_t> encoded;
+  EncodeInt32(42, &encoded);
+  // first three bits: major type = 0;
+  // remaining five bits: additional info = 24, indicating payload is uint8.
+  EXPECT_THAT(encoded, ElementsAreArray(std::array<uint8_t, 2>{{24, 42}}));
+
+  // Reverse direction: decode with CBORTokenizer.
+  CBORTokenizer tokenizer(SpanFromVector(encoded));
+  EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag());
+  EXPECT_EQ(42, tokenizer.GetInt32());
+  tokenizer.Next();
+  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
+}
+
+TEST(EncodeDecodeInt32Test, RoundtripsUint16) {
+  // 500 is encoded as a uint16 after the initial byte.
+  std::vector<uint8_t> encoded;
+  EncodeInt32(500, &encoded);
+  // 1 for initial byte, 2 for uint16.
+  EXPECT_EQ(static_cast<std::size_t>(3), encoded.size());
+  // first three bits: major type = 0;
+  // remaining five bits: additional info = 25, indicating payload is uint16.
+  EXPECT_EQ(25, encoded[0]);
+  EXPECT_EQ(0x01, encoded[1]);
+  EXPECT_EQ(0xf4, encoded[2]);
+
+  // Reverse direction: decode with CBORTokenizer.
+  CBORTokenizer tokenizer(SpanFromVector(encoded));
+  EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag());
+  EXPECT_EQ(500, tokenizer.GetInt32());
+  tokenizer.Next();
+  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
+}
+
+TEST(EncodeDecodeInt32Test, RoundtripsInt32Max) {
+  // std::numeric_limits<int32_t> is encoded as a uint32 after the initial byte.
+  std::vector<uint8_t> encoded;
+  EncodeInt32(std::numeric_limits<int32_t>::max(), &encoded);
+  // 1 for initial byte, 4 for the uint32.
+  // first three bits: major type = 0;
+  // remaining five bits: additional info = 26, indicating payload is uint32.
+  EXPECT_THAT(
+      encoded,
+      ElementsAreArray(std::array<uint8_t, 5>{{26, 0x7f, 0xff, 0xff, 0xff}}));
+
+  // Reverse direction: decode with CBORTokenizer.
+  CBORTokenizer tokenizer(SpanFromVector(encoded));
+  EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag());
+  EXPECT_EQ(std::numeric_limits<int32_t>::max(), tokenizer.GetInt32());
+  tokenizer.Next();
+  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
+}
+
+TEST(EncodeDecodeInt32Test, CantRoundtripUint32) {
+  // 0xdeadbeef is a value which does not fit below
+  // std::numerical_limits<int32_t>::max(), so we can't encode
+  // it with EncodeInt32. However, CBOR does support this, so we
+  // encode it here manually with the internal routine, just to observe
+  // that it's considered an invalid int32 by CBORTokenizer.
+  std::vector<uint8_t> encoded;
+  internals::WriteTokenStart(MajorType::UNSIGNED, 0xdeadbeef, &encoded);
+  // 1 for initial byte, 4 for the uint32.
+  // first three bits: major type = 0;
+  // remaining five bits: additional info = 26, indicating payload is uint32.
+  EXPECT_THAT(
+      encoded,
+      ElementsAreArray(std::array<uint8_t, 5>{{26, 0xde, 0xad, 0xbe, 0xef}}));
+
+  // Now try to decode; we treat this as an invalid INT32.
+  CBORTokenizer tokenizer(SpanFromVector(encoded));
+  // 0xdeadbeef is > std::numerical_limits<int32_t>::max().
+  EXPECT_EQ(CBORTokenTag::ERROR_VALUE, tokenizer.TokenTag());
+  EXPECT_EQ(Error::CBOR_INVALID_INT32, tokenizer.Status().error);
+}
+
+TEST(EncodeDecodeInt32Test, DecodeErrorCases) {
+  struct TestCase {
+    std::vector<uint8_t> data;
+    std::string msg;
+  };
+  std::vector<TestCase> tests{
+      {TestCase{
+           {24},
+           "additional info = 24 would require 1 byte of payload (but it's 0)"},
+       TestCase{{27, 0xaa, 0xbb, 0xcc},
+                "additional info = 27 would require 8 bytes of payload (but "
+                "it's 3)"},
+       TestCase{{29}, "additional info = 29 isn't recognized"}}};
+
+  for (const TestCase& test : tests) {
+    SCOPED_TRACE(test.msg);
+    CBORTokenizer tokenizer(SpanFromVector(test.data));
+    EXPECT_EQ(CBORTokenTag::ERROR_VALUE, tokenizer.TokenTag());
+    EXPECT_EQ(Error::CBOR_INVALID_INT32, tokenizer.Status().error);
+  }
+}
+
+TEST(EncodeDecodeInt32Test, RoundtripsMinus24) {
+  // This roundtrips the int32_t value -24 through the pair of EncodeInt32 /
+  // CBORTokenizer; this is interesting since -24 is encoded as
+  // a single byte as NEGATIVE, and it tests the specific encoding
+  // (note how for unsigned the single byte covers values up to 23).
+  // Additional examples are covered in RoundtripsAdditionalExamples.
+  std::vector<uint8_t> encoded;
+  EncodeInt32(-24, &encoded);
+  // first three bits: major type = 1; remaining five bits: additional info =
+  // value 23.
+  EXPECT_THAT(encoded, ElementsAreArray(std::array<uint8_t, 1>{{1 << 5 | 23}}));
+
+  // Reverse direction: decode with CBORTokenizer.
+  CBORTokenizer tokenizer(SpanFromVector(encoded));
+  EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag());
+  EXPECT_EQ(-24, tokenizer.GetInt32());
+  tokenizer.Next();
+  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
+}
+
+TEST(EncodeDecodeInt32Test, RoundtripsAdditionalNegativeExamples) {
+  std::vector<int32_t> examples = {-1,
+                                   -10,
+                                   -24,
+                                   -25,
+                                   -300,
+                                   -30000,
+                                   -300 * 1000,
+                                   -1000 * 1000,
+                                   -1000 * 1000 * 1000,
+                                   std::numeric_limits<int32_t>::min()};
+  for (int32_t example : examples) {
+    SCOPED_TRACE(std::string("example ") + std::to_string(example));
+    std::vector<uint8_t> encoded;
+    EncodeInt32(example, &encoded);
+    CBORTokenizer tokenizer(SpanFromVector(encoded));
+    EXPECT_EQ(CBORTokenTag::INT32, tokenizer.TokenTag());
+    EXPECT_EQ(example, tokenizer.GetInt32());
+    tokenizer.Next();
+    EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
+  }
+}
+
+//
+// EncodeString16 / CBORTokenTag::STRING16
+//
+TEST(EncodeDecodeString16Test, RoundtripsEmpty) {
+  // This roundtrips the empty utf16 string through the pair of EncodeString16 /
+  // CBORTokenizer.
+  std::vector<uint8_t> encoded;
+  EncodeString16(span<uint16_t>(), &encoded);
+  EXPECT_EQ(static_cast<std::size_t>(1), encoded.size());
+  // first three bits: major type = 2; remaining five bits: additional info =
+  // size 0.
+  EXPECT_EQ(2 << 5, encoded[0]);
+
+  // Reverse direction: decode with CBORTokenizer.
+  CBORTokenizer tokenizer(SpanFromVector(encoded));
+  EXPECT_EQ(CBORTokenTag::STRING16, tokenizer.TokenTag());
+  span<uint8_t> decoded_string16_wirerep = tokenizer.GetString16WireRep();
+  EXPECT_TRUE(decoded_string16_wirerep.empty());
+  tokenizer.Next();
+  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
+}
+
+// On the wire, we STRING16 is encoded as little endian (least
+// significant byte first). The host may or may not be little endian,
+// so this routine follows the advice in
+// https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html.
+std::vector<uint16_t> String16WireRepToHost(span<uint8_t> in) {
+  CHECK_EQ(in.size() & 1, 0);  // must be even number of bytes.
+  std::vector<uint16_t> host_out;
+  for (std::ptrdiff_t ii = 0; ii < in.size(); ii += 2)
+    host_out.push_back(in[ii + 1] << 8 | in[ii]);
+  return host_out;
+}
+
+TEST(EncodeDecodeString16Test, RoundtripsHelloWorld) {
+  // This roundtrips the hello world message which is given here in utf16
+  // characters. 0xd83c, 0xdf0e: UTF16 encoding for the "Earth Globe Americas"
+  // character, 🌎.
+  std::array<uint16_t, 10> msg{
+      {'H', 'e', 'l', 'l', 'o', ',', ' ', 0xd83c, 0xdf0e, '.'}};
+  std::vector<uint8_t> encoded;
+  EncodeString16(span<uint16_t>(msg.data(), msg.size()), &encoded);
+  // This will be encoded as BYTE_STRING of length 20, so the 20 is encoded in
+  // the additional info part of the initial byte. Payload is two bytes for each
+  // UTF16 character.
+  uint8_t initial_byte = /*major type=*/2 << 5 | /*additional info=*/20;
+  std::array<uint8_t, 21> encoded_expected = {
+      {initial_byte, 'H', 0,   'e', 0,    'l',  0,    'l',  0,   'o', 0,
+       ',',          0,   ' ', 0,   0x3c, 0xd8, 0x0e, 0xdf, '.', 0}};
+  EXPECT_THAT(encoded, ElementsAreArray(encoded_expected));
+
+  // Now decode to complete the roundtrip.
+  CBORTokenizer tokenizer(SpanFromVector(encoded));
+  EXPECT_EQ(CBORTokenTag::STRING16, tokenizer.TokenTag());
+  std::vector<uint16_t> decoded =
+      String16WireRepToHost(tokenizer.GetString16WireRep());
+  EXPECT_THAT(decoded, ElementsAreArray(msg));
+  tokenizer.Next();
+  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
+
+  // For bonus points, we look at the decoded message in UTF8 as well so we can
+  // easily see it on the terminal screen.
+  std::string utf8_decoded = UTF16ToUTF8(SpanFromVector(decoded));
+  EXPECT_EQ("Hello, 🌎.", utf8_decoded);
+}
+
+TEST(EncodeDecodeString16Test, Roundtrips500) {
+  // We roundtrip a message that has 250 16 bit values. Each of these are just
+  // set to their index. 250 is interesting because the cbor spec uses a
+  // BYTE_STRING of length 500 for one of their examples of how to encode the
+  // start of it (section 2.1) so it's easy for us to look at the first three
+  // bytes closely.
+  std::vector<uint16_t> two_fifty;
+  for (uint16_t ii = 0; ii < 250; ++ii)
+    two_fifty.push_back(ii);
+  std::vector<uint8_t> encoded;
+  EncodeString16(span<uint16_t>(two_fifty.data(), two_fifty.size()), &encoded);
+  EXPECT_EQ(static_cast<std::size_t>(3 + 250 * 2), encoded.size());
+  // Now check the first three bytes:
+  // Major type: 2 (BYTE_STRING)
+  // Additional information: 25, indicating size is represented by 2 bytes.
+  // Bytes 1 and 2 encode 500 (0x01f4).
+  EXPECT_EQ(2 << 5 | 25, encoded[0]);
+  EXPECT_EQ(0x01, encoded[1]);
+  EXPECT_EQ(0xf4, encoded[2]);
+
+  // Now decode to complete the roundtrip.
+  CBORTokenizer tokenizer(SpanFromVector(encoded));
+  EXPECT_EQ(CBORTokenTag::STRING16, tokenizer.TokenTag());
+  std::vector<uint16_t> decoded =
+      String16WireRepToHost(tokenizer.GetString16WireRep());
+  EXPECT_THAT(decoded, ElementsAreArray(two_fifty));
+  tokenizer.Next();
+  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
+}
+
+TEST(EncodeDecodeString16Test, ErrorCases) {
+  struct TestCase {
+    std::vector<uint8_t> data;
+    std::string msg;
+  };
+  std::vector<TestCase> tests{
+      {TestCase{{2 << 5 | 1, 'a'},
+                "length must be divisible by 2 (but it's 1)"},
+       TestCase{{2 << 5 | 29}, "additional info = 29 isn't recognized"}}};
+  for (const TestCase& test : tests) {
+    SCOPED_TRACE(test.msg);
+    CBORTokenizer tokenizer(SpanFromVector(test.data));
+    EXPECT_EQ(CBORTokenTag::ERROR_VALUE, tokenizer.TokenTag());
+    EXPECT_EQ(Error::CBOR_INVALID_STRING16, tokenizer.Status().error);
+  }
+}
+
+//
+// EncodeString8 / CBORTokenTag::STRING8
+//
+TEST(EncodeDecodeString8Test, RoundtripsHelloWorld) {
+  // This roundtrips the hello world message which is given here in utf8
+  // characters. 🌎 is a four byte utf8 character.
+  std::string utf8_msg = "Hello, 🌎.";
+  std::vector<uint8_t> msg(utf8_msg.begin(), utf8_msg.end());
+  std::vector<uint8_t> encoded;
+  EncodeString8(SpanFromStdString(utf8_msg), &encoded);
+  // This will be encoded as STRING of length 12, so the 12 is encoded in
+  // the additional info part of the initial byte. Payload is one byte per
+  // utf8 byte.
+  uint8_t initial_byte = /*major type=*/3 << 5 | /*additional info=*/12;
+  std::array<uint8_t, 13> encoded_expected = {{initial_byte, 'H', 'e', 'l', 'l',
+                                               'o', ',', ' ', 0xF0, 0x9f, 0x8c,
+                                               0x8e, '.'}};
+  EXPECT_THAT(encoded, ElementsAreArray(encoded_expected));
+
+  // Now decode to complete the roundtrip.
+  CBORTokenizer tokenizer(SpanFromVector(encoded));
+  EXPECT_EQ(CBORTokenTag::STRING8, tokenizer.TokenTag());
+  std::vector<uint8_t> decoded(tokenizer.GetString8().begin(),
+                               tokenizer.GetString8().end());
+  EXPECT_THAT(decoded, ElementsAreArray(msg));
+  tokenizer.Next();
+  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
+}
+
+TEST(EncodeFromLatin1Test, ConvertsToUTF8IfNeeded) {
+  std::vector<std::pair<std::string, std::string>> examples = {
+      {"Hello, world.", "Hello, world."},
+      {"Above: \xDC"
+       "ber",
+       "Above: Über"},
+      {"\xA5 500 are about \xA3 3.50; a y with umlaut is \xFF",
+       "¥ 500 are about £ 3.50; a y with umlaut is ÿ"}};
+
+  for (const auto& example : examples) {
+    const std::string& latin1 = example.first;
+    const std::string& expected_utf8 = example.second;
+    std::vector<uint8_t> encoded;
+    EncodeFromLatin1(SpanFromStdString(latin1), &encoded);
+    CBORTokenizer tokenizer(SpanFromVector(encoded));
+    EXPECT_EQ(CBORTokenTag::STRING8, tokenizer.TokenTag());
+    std::vector<uint8_t> decoded(tokenizer.GetString8().begin(),
+                                 tokenizer.GetString8().end());
+    std::string decoded_str(decoded.begin(), decoded.end());
+    EXPECT_THAT(decoded_str, testing::Eq(expected_utf8));
+  }
+}
+
+TEST(EncodeFromUTF16Test, ConvertsToUTF8IfEasy) {
+  std::vector<uint16_t> ascii = {'e', 'a', 's', 'y'};
+  std::vector<uint8_t> encoded;
+  EncodeFromUTF16(span<uint16_t>(ascii.data(), ascii.size()), &encoded);
+
+  CBORTokenizer tokenizer(SpanFromVector(encoded));
+  EXPECT_EQ(CBORTokenTag::STRING8, tokenizer.TokenTag());
+  std::vector<uint8_t> decoded(tokenizer.GetString8().begin(),
+                               tokenizer.GetString8().end());
+  std::string decoded_str(decoded.begin(), decoded.end());
+  EXPECT_THAT(decoded_str, testing::Eq("easy"));
+}
+
+TEST(EncodeFromUTF16Test, EncodesAsString16IfNeeded) {
+  // Since this message contains non-ASCII characters, the routine is
+  // forced to encode as UTF16. We see this below by checking that the
+  // token tag is STRING16.
+  std::vector<uint16_t> msg = {'H', 'e', 'l',    'l',    'o',
+                               ',', ' ', 0xd83c, 0xdf0e, '.'};
+  std::vector<uint8_t> encoded;
+  EncodeFromUTF16(span<uint16_t>(msg.data(), msg.size()), &encoded);
+
+  CBORTokenizer tokenizer(SpanFromVector(encoded));
+  EXPECT_EQ(CBORTokenTag::STRING16, tokenizer.TokenTag());
+  std::vector<uint16_t> decoded =
+      String16WireRepToHost(tokenizer.GetString16WireRep());
+  std::string utf8_decoded = UTF16ToUTF8(SpanFromVector(decoded));
+  EXPECT_EQ("Hello, 🌎.", utf8_decoded);
+}
+
+//
+// EncodeBinary / CBORTokenTag::BINARY
+//
+TEST(EncodeDecodeBinaryTest, RoundtripsHelloWorld) {
+  std::vector<uint8_t> binary = {'H', 'e', 'l', 'l', 'o', ',', ' ',
+                                 'w', 'o', 'r', 'l', 'd', '.'};
+  std::vector<uint8_t> encoded;
+  EncodeBinary(span<uint8_t>(binary.data(), binary.size()), &encoded);
+  // So, on the wire we see that the binary blob travels unmodified.
+  EXPECT_THAT(
+      encoded,
+      ElementsAreArray(std::array<uint8_t, 15>{
+          {(6 << 5 | 22),  // tag 22 indicating base64 interpretation in JSON
+           (2 << 5 | 13),  // BYTE_STRING (type 2) of length 13
+           'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.'}}));
+  std::vector<uint8_t> decoded;
+  CBORTokenizer tokenizer(SpanFromVector(encoded));
+  EXPECT_EQ(CBORTokenTag::BINARY, tokenizer.TokenTag());
+  EXPECT_EQ(0, int(tokenizer.Status().error));
+  decoded = std::vector<uint8_t>(tokenizer.GetBinary().begin(),
+                                 tokenizer.GetBinary().end());
+  EXPECT_THAT(decoded, ElementsAreArray(binary));
+  tokenizer.Next();
+  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
+}
+
+//
+// EncodeDouble / CBORTokenTag::DOUBLE
+//
+TEST(EncodeDecodeDoubleTest, RoundtripsWikipediaExample) {
+  // https://en.wikipedia.org/wiki/Double-precision_floating-point_format
+  // provides the example of a hex representation 3FD5 5555 5555 5555, which
+  // approximates 1/3.
+
+  const double kOriginalValue = 1.0 / 3;
+  std::vector<uint8_t> encoded;
+  EncodeDouble(kOriginalValue, &encoded);
+  // first three bits: major type = 7; remaining five bits: additional info =
+  // value 27. This is followed by 8 bytes of payload (which match Wikipedia).
+  EXPECT_THAT(
+      encoded,
+      ElementsAreArray(std::array<uint8_t, 9>{
+          {7 << 5 | 27, 0x3f, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}}));
+
+  // Reverse direction: decode and compare with original value.
+  CBORTokenizer tokenizer(SpanFromVector(encoded));
+  EXPECT_EQ(CBORTokenTag::DOUBLE, tokenizer.TokenTag());
+  EXPECT_THAT(tokenizer.GetDouble(), testing::DoubleEq(kOriginalValue));
+  tokenizer.Next();
+  EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
+}
+
+TEST(EncodeDecodeDoubleTest, RoundtripsAdditionalExamples) {
+  std::vector<double> examples = {0.0,
+                                  1.0,
+                                  -1.0,
+                                  3.1415,
+                                  std::numeric_limits<double>::min(),
+                                  std::numeric_limits<double>::max(),
+                                  std::numeric_limits<double>::infinity(),
+                                  std::numeric_limits<double>::quiet_NaN()};
+  for (double example : examples) {
+    SCOPED_TRACE(std::string("example ") + std::to_string(example));
+    std::vector<uint8_t> encoded;
+    EncodeDouble(example, &encoded);
+    CBORTokenizer tokenizer(SpanFromVector(encoded));
+    EXPECT_EQ(CBORTokenTag::DOUBLE, tokenizer.TokenTag());
+    if (std::isnan(example))
+      EXPECT_TRUE(std::isnan(tokenizer.GetDouble()));
+    else
+      EXPECT_THAT(tokenizer.GetDouble(), testing::DoubleEq(example));
+    tokenizer.Next();
+    EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
+  }
+}
+
+// =============================================================================
+// cbor::NewCBOREncoder - for encoding from a streaming parser
+// =============================================================================
+
+void EncodeUTF8ForTest(const std::string& key, std::vector<uint8_t>* out) {
+  EncodeString8(SpanFromStdString(key), out);
+}
+TEST(JSONToCBOREncoderTest, SevenBitStrings) {
+  // When a string can be represented as 7 bit ASCII, the encoder will use the
+  // STRING (major Type 3) type, so the actual characters end up as bytes on the
+  // wire.
+  std::vector<uint8_t> encoded;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> encoder =
+      NewCBOREncoder(&encoded, &status);
+  std::vector<uint16_t> utf16 = {'f', 'o', 'o'};
+  encoder->HandleString16(span<uint16_t>(utf16.data(), utf16.size()));
+  EXPECT_EQ(Error::OK, status.error);
+  // Here we assert that indeed, seven bit strings are represented as
+  // bytes on the wire, "foo" is just "foo".
+  EXPECT_THAT(encoded,
+              ElementsAreArray(std::array<uint8_t, 4>{
+                  {/*major type 3*/ 3 << 5 | /*length*/ 3, 'f', 'o', 'o'}}));
+}
+
+TEST(JsonCborRoundtrip, EncodingDecoding) {
+  // Hits all the cases except binary and error in StreamingParserHandler, first
+  // parsing a JSON message into CBOR, then parsing it back from CBOR into JSON.
+  std::string json =
+      "{"
+      "\"string\":\"Hello, \\ud83c\\udf0e.\","
+      "\"double\":3.1415,"
+      "\"int\":1,"
+      "\"negative int\":-1,"
+      "\"bool\":true,"
+      "\"null\":null,"
+      "\"array\":[1,2,3]"
+      "}";
+  std::vector<uint8_t> encoded;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> encoder =
+      NewCBOREncoder(&encoded, &status);
+  span<uint8_t> ascii_in = SpanFromStdString(json);
+  json::ParseJSON(GetTestPlatform(), ascii_in, encoder.get());
+  std::vector<uint8_t> expected = {
+      0xd8,            // envelope
+      0x5a,            // byte string with 32 bit length
+      0,    0, 0, 94,  // length is 94 bytes
+  };
+  expected.push_back(0xbf);  // indef length map start
+  EncodeString8(SpanFromStdString("string"), &expected);
+  // This is followed by the encoded string for "Hello, 🌎."
+  // So, it's the same bytes that we tested above in
+  // EncodeDecodeString16Test.RoundtripsHelloWorld.
+  expected.push_back(/*major type=*/2 << 5 | /*additional info=*/20);
+  for (uint8_t ch : std::array<uint8_t, 20>{
+           {'H', 0, 'e', 0, 'l',  0,    'l',  0,    'o', 0,
+            ',', 0, ' ', 0, 0x3c, 0xd8, 0x0e, 0xdf, '.', 0}})
+    expected.push_back(ch);
+  EncodeString8(SpanFromStdString("double"), &expected);
+  EncodeDouble(3.1415, &expected);
+  EncodeString8(SpanFromStdString("int"), &expected);
+  EncodeInt32(1, &expected);
+  EncodeString8(SpanFromStdString("negative int"), &expected);
+  EncodeInt32(-1, &expected);
+  EncodeString8(SpanFromStdString("bool"), &expected);
+  expected.push_back(7 << 5 | 21);  // RFC 7049 Section 2.3, Table 2: true
+  EncodeString8(SpanFromStdString("null"), &expected);
+  expected.push_back(7 << 5 | 22);  // RFC 7049 Section 2.3, Table 2: null
+  EncodeString8(SpanFromStdString("array"), &expected);
+  expected.push_back(0xd8);  // envelope
+  expected.push_back(0x5a);  // byte string with 32 bit length
+  // the length is 5 bytes (that's up to end indef length array below).
+  for (uint8_t ch : std::array<uint8_t, 4>{{0, 0, 0, 5}})
+    expected.push_back(ch);
+  expected.push_back(0x9f);  // RFC 7049 Section 2.2.1, indef length array start
+  expected.push_back(1);     // Three UNSIGNED values (easy since Major Type 0)
+  expected.push_back(2);
+  expected.push_back(3);
+  expected.push_back(0xff);  // End indef length array
+  expected.push_back(0xff);  // End indef length map
+  EXPECT_TRUE(status.ok());
+  EXPECT_THAT(encoded, ElementsAreArray(expected));
+
+  // And now we roundtrip, decoding the message we just encoded.
+  std::string decoded;
+  std::unique_ptr<StreamingParserHandler> json_encoder =
+      NewJSONEncoder(GetTestPlatform(), &decoded, &status);
+  ParseCBOR(span<uint8_t>(encoded.data(), encoded.size()), json_encoder.get());
+  EXPECT_EQ(Error::OK, status.error);
+  EXPECT_EQ(json, decoded);
+}
+
+TEST(JsonCborRoundtrip, MoreRoundtripExamples) {
+  std::vector<std::string> examples = {
+      // Tests that after closing a nested objects, additional key/value pairs
+      // are considered.
+      "{\"foo\":{\"bar\":1},\"baz\":2}", "{\"foo\":[1,2,3],\"baz\":2}"};
+  for (const std::string& json : examples) {
+    SCOPED_TRACE(std::string("example: ") + json);
+    std::vector<uint8_t> encoded;
+    Status status;
+    std::unique_ptr<StreamingParserHandler> encoder =
+        NewCBOREncoder(&encoded, &status);
+    span<uint8_t> ascii_in = SpanFromStdString(json);
+    ParseJSON(GetTestPlatform(), ascii_in, encoder.get());
+    std::string decoded;
+    std::unique_ptr<StreamingParserHandler> json_writer =
+        NewJSONEncoder(GetTestPlatform(), &decoded, &status);
+    ParseCBOR(span<uint8_t>(encoded.data(), encoded.size()), json_writer.get());
+    EXPECT_EQ(Error::OK, status.error);
+    EXPECT_EQ(json, decoded);
+  }
+}
+
+TEST(JSONToCBOREncoderTest, HelloWorldBinary_WithTripToJson) {
+  // The StreamingParserHandler::HandleBinary is a special case: The JSON parser
+  // will never call this method, because JSON does not natively support the
+  // binary type. So, we can't fully roundtrip. However, the other direction
+  // works: binary will be rendered in JSON, as a base64 string. So, we make
+  // calls to the encoder directly here, to construct a message, and one of
+  // these calls is ::HandleBinary, to which we pass a "binary" string
+  // containing "Hello, world.".
+  std::vector<uint8_t> encoded;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> encoder =
+      NewCBOREncoder(&encoded, &status);
+  encoder->HandleMapBegin();
+  // Emit a key.
+  std::vector<uint16_t> key = {'f', 'o', 'o'};
+  encoder->HandleString16(SpanFromVector(key));
+  // Emit the binary payload, an arbitrary array of bytes that happens to
+  // be the ascii message "Hello, world.".
+  encoder->HandleBinary(SpanFromVector(std::vector<uint8_t>{
+      'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.'}));
+  encoder->HandleMapEnd();
+  EXPECT_EQ(Error::OK, status.error);
+
+  // Now drive the json writer via the CBOR decoder.
+  std::string decoded;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &decoded, &status);
+  ParseCBOR(SpanFromVector(encoded), json_writer.get());
+  EXPECT_EQ(Error::OK, status.error);
+  EXPECT_EQ(Status::npos(), status.pos);
+  // "Hello, world." in base64 is "SGVsbG8sIHdvcmxkLg==".
+  EXPECT_EQ("{\"foo\":\"SGVsbG8sIHdvcmxkLg==\"}", decoded);
+}
+
+// =============================================================================
+// cbor::ParseCBOR - for receiving streaming parser events for CBOR messages
+// =============================================================================
+
+TEST(ParseCBORTest, ParseEmptyCBORMessage) {
+  // An envelope starting with 0xd8, 0x5a, with the byte length
+  // of 2, containing a map that's empty (0xbf for map
+  // start, and 0xff for map end).
+  std::vector<uint8_t> in = {0xd8, 0x5a, 0, 0, 0, 2, 0xbf, 0xff};
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  ParseCBOR(span<uint8_t>(in.data(), in.size()), json_writer.get());
+  EXPECT_EQ(Error::OK, status.error);
+  EXPECT_EQ("{}", out);
+}
+
+TEST(ParseCBORTest, ParseCBORHelloWorld) {
+  const uint8_t kPayloadLen = 27;
+  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen};
+  bytes.push_back(0xbf);                            // start indef length map.
+  EncodeString8(SpanFromStdString("msg"), &bytes);  // key: msg
+  // Now write the value, the familiar "Hello, 🌎." where the globe is expressed
+  // as two utf16 chars.
+  bytes.push_back(/*major type=*/2 << 5 | /*additional info=*/20);
+  for (uint8_t ch : std::array<uint8_t, 20>{
+           {'H', 0, 'e', 0, 'l',  0,    'l',  0,    'o', 0,
+            ',', 0, ' ', 0, 0x3c, 0xd8, 0x0e, 0xdf, '.', 0}})
+    bytes.push_back(ch);
+  bytes.push_back(0xff);  // stop byte
+  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
+
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+  EXPECT_EQ(Error::OK, status.error);
+  EXPECT_EQ("{\"msg\":\"Hello, \\ud83c\\udf0e.\"}", out);
+}
+
+TEST(ParseCBORTest, UTF8IsSupportedInKeys) {
+  const uint8_t kPayloadLen = 11;
+  std::vector<uint8_t> bytes = {cbor::InitialByteForEnvelope(),
+                                cbor::InitialByteFor32BitLengthByteString(),
+                                0,
+                                0,
+                                0,
+                                kPayloadLen};
+  bytes.push_back(cbor::EncodeIndefiniteLengthMapStart());
+  // Two UTF16 chars.
+  EncodeString8(SpanFromStdString("🌎"), &bytes);
+  // Can be encoded as a single UTF16 char.
+  EncodeString8(SpanFromStdString("☾"), &bytes);
+  bytes.push_back(cbor::EncodeStop());
+  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
+
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+  EXPECT_EQ(Error::OK, status.error);
+  EXPECT_EQ("{\"\\ud83c\\udf0e\":\"\\u263e\"}", out);
+}
+
+TEST(ParseCBORTest, NoInputError) {
+  std::vector<uint8_t> in = {};
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  ParseCBOR(span<uint8_t>(in.data(), in.size()), json_writer.get());
+  EXPECT_EQ(Error::CBOR_NO_INPUT, status.error);
+  EXPECT_EQ("", out);
+}
+
+TEST(ParseCBORTest, InvalidStartByteError) {
+  // Here we test that some actual json, which usually starts with {,
+  // is not considered CBOR. CBOR messages must start with 0x5a, the
+  // envelope start byte.
+  std::string json = "{\"msg\": \"Hello, world.\"}";
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  ParseCBOR(SpanFromStdString(json), json_writer.get());
+  EXPECT_EQ(Error::CBOR_INVALID_START_BYTE, status.error);
+  EXPECT_EQ("", out);
+}
+
+TEST(ParseCBORTest, UnexpectedEofExpectedValueError) {
+  constexpr uint8_t kPayloadLen = 5;
+  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
+                                0xbf};                             // map start
+  // A key; so value would be next.
+  EncodeString8(SpanFromStdString("key"), &bytes);
+  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+  EXPECT_EQ(Error::CBOR_UNEXPECTED_EOF_EXPECTED_VALUE, status.error);
+  EXPECT_EQ(static_cast<int64_t>(bytes.size()), status.pos);
+  EXPECT_EQ("", out);
+}
+
+TEST(ParseCBORTest, UnexpectedEofInArrayError) {
+  constexpr uint8_t kPayloadLen = 8;
+  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
+                                0xbf};  // The byte for starting a map.
+  // A key; so value would be next.
+  EncodeString8(SpanFromStdString("array"), &bytes);
+  bytes.push_back(0x9f);  // byte for indefinite length array start.
+  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+  EXPECT_EQ(Error::CBOR_UNEXPECTED_EOF_IN_ARRAY, status.error);
+  EXPECT_EQ(static_cast<int64_t>(bytes.size()), status.pos);
+  EXPECT_EQ("", out);
+}
+
+TEST(ParseCBORTest, UnexpectedEofInMapError) {
+  constexpr uint8_t kPayloadLen = 1;
+  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
+                                0xbf};  // The byte for starting a map.
+  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+  EXPECT_EQ(Error::CBOR_UNEXPECTED_EOF_IN_MAP, status.error);
+  EXPECT_EQ(7, status.pos);
+  EXPECT_EQ("", out);
+}
+
+TEST(ParseCBORTest, InvalidMapKeyError) {
+  constexpr uint8_t kPayloadLen = 2;
+  std::vector<uint8_t> bytes = {0xd8,       0x5a, 0,
+                                0,          0,    kPayloadLen,  // envelope
+                                0xbf,                           // map start
+                                7 << 5 | 22};  // null (not a valid map key)
+  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+  EXPECT_EQ(Error::CBOR_INVALID_MAP_KEY, status.error);
+  EXPECT_EQ(7, status.pos);
+  EXPECT_EQ("", out);
+}
+
+std::vector<uint8_t> MakeNestedCBOR(int depth) {
+  std::vector<uint8_t> bytes;
+  std::vector<EnvelopeEncoder> envelopes;
+  for (int ii = 0; ii < depth; ++ii) {
+    envelopes.emplace_back();
+    envelopes.back().EncodeStart(&bytes);
+    bytes.push_back(0xbf);  // indef length map start
+    EncodeString8(SpanFromStdString("key"), &bytes);
+  }
+  EncodeString8(SpanFromStdString("innermost_value"), &bytes);
+  for (int ii = 0; ii < depth; ++ii) {
+    bytes.push_back(0xff);  // stop byte, finishes map.
+    envelopes.back().EncodeStop(&bytes);
+    envelopes.pop_back();
+  }
+  return bytes;
+}
+
+TEST(ParseCBORTest, StackLimitExceededError) {
+  {  // Depth 3: no stack limit exceeded error and is easy to inspect.
+    std::vector<uint8_t> bytes = MakeNestedCBOR(3);
+    std::string out;
+    Status status;
+    std::unique_ptr<StreamingParserHandler> json_writer =
+        NewJSONEncoder(GetTestPlatform(), &out, &status);
+    ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+    EXPECT_EQ(Error::OK, status.error);
+    EXPECT_EQ(Status::npos(), status.pos);
+    EXPECT_EQ("{\"key\":{\"key\":{\"key\":\"innermost_value\"}}}", out);
+  }
+  {  // Depth 200: no stack limit exceeded.
+    std::vector<uint8_t> bytes = MakeNestedCBOR(200);
+    std::string out;
+    Status status;
+    std::unique_ptr<StreamingParserHandler> json_writer =
+        NewJSONEncoder(GetTestPlatform(), &out, &status);
+    ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+    EXPECT_EQ(Error::OK, status.error);
+    EXPECT_EQ(Status::npos(), status.pos);
+  }
+
+  // We just want to know the length of one opening map so we can compute
+  // where the error is encountered. So we look at a small example and find
+  // the second envelope start.
+  std::vector<uint8_t> small_example = MakeNestedCBOR(3);
+  int64_t opening_segment_size = 1;  // Start after the first envelope start.
+  while (opening_segment_size < static_cast<int64_t>(small_example.size()) &&
+         small_example[opening_segment_size] != 0xd8)
+    opening_segment_size++;
+
+  {  // Depth 201: limit exceeded.
+    std::vector<uint8_t> bytes = MakeNestedCBOR(201);
+    std::string out;
+    Status status;
+    std::unique_ptr<StreamingParserHandler> json_writer =
+        NewJSONEncoder(GetTestPlatform(), &out, &status);
+    ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+    EXPECT_EQ(Error::CBOR_STACK_LIMIT_EXCEEDED, status.error);
+    EXPECT_EQ(opening_segment_size * 201, status.pos);
+  }
+  {  // Depth 220: still limit exceeded, and at the same pos as for 1001
+    std::vector<uint8_t> bytes = MakeNestedCBOR(220);
+    std::string out;
+    Status status;
+    std::unique_ptr<StreamingParserHandler> json_writer =
+        NewJSONEncoder(GetTestPlatform(), &out, &status);
+    ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+    EXPECT_EQ(Error::CBOR_STACK_LIMIT_EXCEEDED, status.error);
+    EXPECT_EQ(opening_segment_size * 201, status.pos);
+  }
+}
+
+TEST(ParseCBORTest, UnsupportedValueError) {
+  constexpr uint8_t kPayloadLen = 6;
+  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
+                                0xbf};                             // map start
+  EncodeString8(SpanFromStdString("key"), &bytes);
+  int64_t error_pos = bytes.size();
+  bytes.push_back(6 << 5 | 5);  // tags aren't supported yet.
+  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
+
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+  EXPECT_EQ(Error::CBOR_UNSUPPORTED_VALUE, status.error);
+  EXPECT_EQ(error_pos, status.pos);
+  EXPECT_EQ("", out);
+}
+
+TEST(ParseCBORTest, InvalidString16Error) {
+  constexpr uint8_t kPayloadLen = 11;
+  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
+                                0xbf};                             // map start
+  EncodeString8(SpanFromStdString("key"), &bytes);
+  int64_t error_pos = bytes.size();
+  // a BYTE_STRING of length 5 as value; since we interpret these as string16,
+  // it's going to be invalid as each character would need two bytes, but
+  // 5 isn't divisible by 2.
+  bytes.push_back(2 << 5 | 5);
+  for (int ii = 0; ii < 5; ++ii)
+    bytes.push_back(' ');
+  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+  EXPECT_EQ(Error::CBOR_INVALID_STRING16, status.error);
+  EXPECT_EQ(error_pos, status.pos);
+  EXPECT_EQ("", out);
+}
+
+TEST(ParseCBORTest, InvalidString8Error) {
+  constexpr uint8_t kPayloadLen = 6;
+  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
+                                0xbf};                             // map start
+  EncodeString8(SpanFromStdString("key"), &bytes);
+  int64_t error_pos = bytes.size();
+  // a STRING of length 5 as value, but we're at the end of the bytes array
+  // so it can't be decoded successfully.
+  bytes.push_back(3 << 5 | 5);
+  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+  EXPECT_EQ(Error::CBOR_INVALID_STRING8, status.error);
+  EXPECT_EQ(error_pos, status.pos);
+  EXPECT_EQ("", out);
+}
+
+TEST(ParseCBORTest, InvalidBinaryError) {
+  constexpr uint8_t kPayloadLen = 9;
+  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
+                                0xbf};                             // map start
+  EncodeString8(SpanFromStdString("key"), &bytes);
+  int64_t error_pos = bytes.size();
+  bytes.push_back(6 << 5 | 22);  // base64 hint for JSON; indicates binary
+  bytes.push_back(2 << 5 | 10);  // BYTE_STRING (major type 2) of length 10
+  // Just two garbage bytes, not enough for the binary.
+  bytes.push_back(0x31);
+  bytes.push_back(0x23);
+  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+  EXPECT_EQ(Error::CBOR_INVALID_BINARY, status.error);
+  EXPECT_EQ(error_pos, status.pos);
+  EXPECT_EQ("", out);
+}
+
+TEST(ParseCBORTest, InvalidDoubleError) {
+  constexpr uint8_t kPayloadLen = 8;
+  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
+                                0xbf};                             // map start
+  EncodeString8(SpanFromStdString("key"), &bytes);
+  int64_t error_pos = bytes.size();
+  bytes.push_back(7 << 5 | 27);  // initial byte for double
+  // Just two garbage bytes, not enough to represent an actual double.
+  bytes.push_back(0x31);
+  bytes.push_back(0x23);
+  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+  EXPECT_EQ(Error::CBOR_INVALID_DOUBLE, status.error);
+  EXPECT_EQ(error_pos, status.pos);
+  EXPECT_EQ("", out);
+}
+
+TEST(ParseCBORTest, InvalidSignedError) {
+  constexpr uint8_t kPayloadLen = 14;
+  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
+                                0xbf};                             // map start
+  EncodeString8(SpanFromStdString("key"), &bytes);
+  int64_t error_pos = bytes.size();
+  // uint64_t max is a perfectly fine value to encode as CBOR unsigned,
+  // but we don't support this since we only cover the int32_t range.
+  internals::WriteTokenStart(MajorType::UNSIGNED,
+                             std::numeric_limits<uint64_t>::max(), &bytes);
+  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+  EXPECT_EQ(Error::CBOR_INVALID_INT32, status.error);
+  EXPECT_EQ(error_pos, status.pos);
+  EXPECT_EQ("", out);
+}
+
+TEST(ParseCBORTest, TrailingJunk) {
+  constexpr uint8_t kPayloadLen = 35;
+  std::vector<uint8_t> bytes = {0xd8, 0x5a, 0, 0, 0, kPayloadLen,  // envelope
+                                0xbf};                             // map start
+  EncodeString8(SpanFromStdString("key"), &bytes);
+  EncodeString8(SpanFromStdString("value"), &bytes);
+  bytes.push_back(0xff);  // Up to here, it's a perfectly fine msg.
+  int64_t error_pos = bytes.size();
+  EncodeString8(SpanFromStdString("trailing junk"), &bytes);
+
+  internals::WriteTokenStart(MajorType::UNSIGNED,
+                             std::numeric_limits<uint64_t>::max(), &bytes);
+  EXPECT_EQ(kPayloadLen, bytes.size() - 6);
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> json_writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  ParseCBOR(span<uint8_t>(bytes.data(), bytes.size()), json_writer.get());
+  EXPECT_EQ(Error::CBOR_TRAILING_JUNK, status.error);
+  EXPECT_EQ(error_pos, status.pos);
+  EXPECT_EQ("", out);
+}
+}  // namespace cbor
+
+namespace json {
+
+// =============================================================================
+// json::NewJSONEncoder - for encoding streaming parser events as JSON
+// =============================================================================
+
+void WriteUTF8AsUTF16(StreamingParserHandler* writer, const std::string& utf8) {
+  writer->HandleString16(SpanFromVector(UTF8ToUTF16(SpanFromStdString(utf8))));
+}
+
+TEST(JsonStdStringWriterTest, HelloWorld) {
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  writer->HandleMapBegin();
+  WriteUTF8AsUTF16(writer.get(), "msg1");
+  WriteUTF8AsUTF16(writer.get(), "Hello, 🌎.");
+  std::string key = "msg1-as-utf8";
+  std::string value = "Hello, 🌎.";
+  writer->HandleString8(SpanFromStdString(key));
+  writer->HandleString8(SpanFromStdString(value));
+  WriteUTF8AsUTF16(writer.get(), "msg2");
+  WriteUTF8AsUTF16(writer.get(), "\\\b\r\n\t\f\"");
+  WriteUTF8AsUTF16(writer.get(), "nested");
+  writer->HandleMapBegin();
+  WriteUTF8AsUTF16(writer.get(), "double");
+  writer->HandleDouble(3.1415);
+  WriteUTF8AsUTF16(writer.get(), "int");
+  writer->HandleInt32(-42);
+  WriteUTF8AsUTF16(writer.get(), "bool");
+  writer->HandleBool(false);
+  WriteUTF8AsUTF16(writer.get(), "null");
+  writer->HandleNull();
+  writer->HandleMapEnd();
+  WriteUTF8AsUTF16(writer.get(), "array");
+  writer->HandleArrayBegin();
+  writer->HandleInt32(1);
+  writer->HandleInt32(2);
+  writer->HandleInt32(3);
+  writer->HandleArrayEnd();
+  writer->HandleMapEnd();
+  EXPECT_TRUE(status.ok());
+  EXPECT_EQ(
+      "{\"msg1\":\"Hello, \\ud83c\\udf0e.\","
+      "\"msg1-as-utf8\":\"Hello, \\ud83c\\udf0e.\","
+      "\"msg2\":\"\\\\\\b\\r\\n\\t\\f\\\"\","
+      "\"nested\":{\"double\":3.1415,\"int\":-42,"
+      "\"bool\":false,\"null\":null},\"array\":[1,2,3]}",
+      out);
+}
+
+TEST(JsonStdStringWriterTest, BinaryEncodedAsJsonString) {
+  // The encoder emits binary submitted to StreamingParserHandler::HandleBinary
+  // as base64. The following three examples are taken from
+  // https://en.wikipedia.org/wiki/Base64.
+  {
+    std::string out;
+    Status status;
+    std::unique_ptr<StreamingParserHandler> writer =
+        NewJSONEncoder(GetTestPlatform(), &out, &status);
+    writer->HandleBinary(SpanFromVector(std::vector<uint8_t>({'M', 'a', 'n'})));
+    EXPECT_TRUE(status.ok());
+    EXPECT_EQ("\"TWFu\"", out);
+  }
+  {
+    std::string out;
+    Status status;
+    std::unique_ptr<StreamingParserHandler> writer =
+        NewJSONEncoder(GetTestPlatform(), &out, &status);
+    writer->HandleBinary(SpanFromVector(std::vector<uint8_t>({'M', 'a'})));
+    EXPECT_TRUE(status.ok());
+    EXPECT_EQ("\"TWE=\"", out);
+  }
+  {
+    std::string out;
+    Status status;
+    std::unique_ptr<StreamingParserHandler> writer =
+        NewJSONEncoder(GetTestPlatform(), &out, &status);
+    writer->HandleBinary(SpanFromVector(std::vector<uint8_t>({'M'})));
+    EXPECT_TRUE(status.ok());
+    EXPECT_EQ("\"TQ==\"", out);
+  }
+  {  // "Hello, world.", verified with base64decode.org.
+    std::string out;
+    Status status;
+    std::unique_ptr<StreamingParserHandler> writer =
+        NewJSONEncoder(GetTestPlatform(), &out, &status);
+    writer->HandleBinary(SpanFromVector(std::vector<uint8_t>(
+        {'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.'})));
+    EXPECT_TRUE(status.ok());
+    EXPECT_EQ("\"SGVsbG8sIHdvcmxkLg==\"", out);
+  }
+}
+
+TEST(JsonStdStringWriterTest, HandlesErrors) {
+  // When an error is sent via HandleError, it saves it in the provided
+  // status and clears the output.
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> writer =
+      NewJSONEncoder(GetTestPlatform(), &out, &status);
+  writer->HandleMapBegin();
+  WriteUTF8AsUTF16(writer.get(), "msg1");
+  writer->HandleError(Status{Error::JSON_PARSER_VALUE_EXPECTED, 42});
+  EXPECT_EQ(Error::JSON_PARSER_VALUE_EXPECTED, status.error);
+  EXPECT_EQ(42, status.pos);
+  EXPECT_EQ("", out);
+}
+
+// We'd use Gmock but unfortunately it only handles copyable return types.
+class MockPlatform : public Platform {
+ public:
+  // Not implemented.
+  bool StrToD(const char* str, double* result) const override { return false; }
+
+  // A map with pre-registered responses for DToSTr.
+  std::map<double, std::string> dtostr_responses;
+
+  std::unique_ptr<char[]> DToStr(double value) const override {
+    auto it = dtostr_responses.find(value);
+    CHECK(it != dtostr_responses.end());
+    const std::string& str = it->second;
+    std::unique_ptr<char[]> response(new char[str.size() + 1]);
+    memcpy(response.get(), str.c_str(), str.size() + 1);
+    return response;
+  }
+};
+
+TEST(JsonStdStringWriterTest, DoubleToString) {
+  // This "broken" platform responds without the leading 0 before the
+  // decimal dot, so it'd be invalid JSON.
+  MockPlatform platform;
+  platform.dtostr_responses[.1] = ".1";
+  platform.dtostr_responses[-.7] = "-.7";
+
+  std::string out;
+  Status status;
+  std::unique_ptr<StreamingParserHandler> writer =
+      NewJSONEncoder(&platform, &out, &status);
+  writer->HandleArrayBegin();
+  writer->HandleDouble(.1);
+  writer->HandleDouble(-.7);
+  writer->HandleArrayEnd();
+  EXPECT_EQ("[0.1,-0.7]", out);
+}
+
+// =============================================================================
+// json::ParseJSON - for receiving streaming parser events for JSON
+// =============================================================================
+
+class Log : public StreamingParserHandler {
+ public:
+  void HandleMapBegin() override { log_ << "map begin\n"; }
+
+  void HandleMapEnd() override { log_ << "map end\n"; }
+
+  void HandleArrayBegin() override { log_ << "array begin\n"; }
+
+  void HandleArrayEnd() override { log_ << "array end\n"; }
+
+  void HandleString8(span<uint8_t> chars) override {
+    log_ << "string8: " << std::string(chars.begin(), chars.end()) << "\n";
+  }
+
+  void HandleString16(span<uint16_t> chars) override {
+    log_ << "string16: " << UTF16ToUTF8(chars) << "\n";
+  }
+
+  void HandleBinary(span<uint8_t> bytes) override {
+    // JSON doesn't have native support for arbitrary bytes, so our parser will
+    // never call this.
+    CHECK(false);
+  }
+
+  void HandleDouble(double value) override {
+    log_ << "double: " << value << "\n";
+  }
+
+  void HandleInt32(int32_t value) override { log_ << "int: " << value << "\n"; }
+
+  void HandleBool(bool value) override { log_ << "bool: " << value << "\n"; }
+
+  void HandleNull() override { log_ << "null\n"; }
+
+  void HandleError(Status status) override { status_ = status; }
+
+  std::string str() const { return status_.ok() ? log_.str() : ""; }
+
+  Status status() const { return status_; }
+
+ private:
+  std::ostringstream log_;
+  Status status_;
+};
+
+class JsonParserTest : public ::testing::Test {
+ protected:
+  Log log_;
+};
+
+TEST_F(JsonParserTest, SimpleDictionary) {
+  std::string json = "{\"foo\": 42}";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_TRUE(log_.status().ok());
+  EXPECT_EQ(
+      "map begin\n"
+      "string16: foo\n"
+      "int: 42\n"
+      "map end\n",
+      log_.str());
+}
+
+TEST_F(JsonParserTest, Whitespace) {
+  std::string json = "\n  {\n\"msg\"\n: \v\"Hello, world.\"\t\r}\t";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_TRUE(log_.status().ok());
+  EXPECT_EQ(
+      "map begin\n"
+      "string16: msg\n"
+      "string16: Hello, world.\n"
+      "map end\n",
+      log_.str());
+}
+
+TEST_F(JsonParserTest, NestedDictionary) {
+  std::string json = "{\"foo\": {\"bar\": {\"baz\": 1}, \"bar2\": 2}}";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_TRUE(log_.status().ok());
+  EXPECT_EQ(
+      "map begin\n"
+      "string16: foo\n"
+      "map begin\n"
+      "string16: bar\n"
+      "map begin\n"
+      "string16: baz\n"
+      "int: 1\n"
+      "map end\n"
+      "string16: bar2\n"
+      "int: 2\n"
+      "map end\n"
+      "map end\n",
+      log_.str());
+}
+
+TEST_F(JsonParserTest, Doubles) {
+  std::string json = "{\"foo\": 3.1415, \"bar\": 31415e-4}";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_TRUE(log_.status().ok());
+  EXPECT_EQ(
+      "map begin\n"
+      "string16: foo\n"
+      "double: 3.1415\n"
+      "string16: bar\n"
+      "double: 3.1415\n"
+      "map end\n",
+      log_.str());
+}
+
+TEST_F(JsonParserTest, Unicode) {
+  // Globe character. 0xF0 0x9F 0x8C 0x8E in utf8, 0xD83C 0xDF0E in utf16.
+  std::string json = "{\"msg\": \"Hello, \\uD83C\\uDF0E.\"}";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_TRUE(log_.status().ok());
+  EXPECT_EQ(
+      "map begin\n"
+      "string16: msg\n"
+      "string16: Hello, 🌎.\n"
+      "map end\n",
+      log_.str());
+}
+
+TEST_F(JsonParserTest, Unicode_ParseUtf16) {
+  // Globe character. utf8: 0xF0 0x9F 0x8C 0x8E; utf16: 0xD83C 0xDF0E.
+  // Crescent moon character. utf8: 0xF0 0x9F 0x8C 0x99; utf16: 0xD83C 0xDF19.
+
+  // We provide the moon with json escape, but the earth as utf16 input.
+  // Either way they arrive as utf8 (after decoding in log_.str()).
+  std::vector<uint16_t> json =
+      UTF8ToUTF16(SpanFromStdString("{\"space\": \"🌎 \\uD83C\\uDF19.\"}"));
+  ParseJSON(GetTestPlatform(), SpanFromVector(json), &log_);
+  EXPECT_TRUE(log_.status().ok());
+  EXPECT_EQ(
+      "map begin\n"
+      "string16: space\n"
+      "string16: 🌎 🌙.\n"
+      "map end\n",
+      log_.str());
+}
+
+TEST_F(JsonParserTest, Unicode_ParseUtf8) {
+  // Used below:
+  // гласность - example for 2 byte utf8, Russian word "glasnost"
+  // 屋 - example for 3 byte utf8, Chinese word for "house"
+  // 🌎 - example for 4 byte utf8: 0xF0 0x9F 0x8C 0x8E; utf16: 0xD83C 0xDF0E.
+  // 🌙 - example for escapes: utf8: 0xF0 0x9F 0x8C 0x99; utf16: 0xD83C 0xDF19.
+
+  // We provide the moon with json escape, but the earth as utf8 input.
+  // Either way they arrive as utf8 (after decoding in log_.str()).
+  std::string json =
+      "{"
+      "\"escapes\": \"\\uD83C\\uDF19\","
+      "\"2 byte\":\"гласность\","
+      "\"3 byte\":\"屋\","
+      "\"4 byte\":\"🌎\""
+      "}";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_TRUE(log_.status().ok());
+  EXPECT_EQ(
+      "map begin\n"
+      "string16: escapes\n"
+      "string16: 🌙\n"
+      "string16: 2 byte\n"
+      "string16: гласность\n"
+      "string16: 3 byte\n"
+      "string16: 屋\n"
+      "string16: 4 byte\n"
+      "string16: 🌎\n"
+      "map end\n",
+      log_.str());
+}
+
+TEST_F(JsonParserTest, UnprocessedInputRemainsError) {
+  // Trailing junk after the valid JSON.
+  std::string json = "{\"foo\": 3.1415} junk";
+  int64_t junk_idx = json.find("junk");
+  EXPECT_GT(junk_idx, 0);
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_EQ(Error::JSON_PARSER_UNPROCESSED_INPUT_REMAINS, log_.status().error);
+  EXPECT_EQ(junk_idx, log_.status().pos);
+  EXPECT_EQ("", log_.str());
+}
+
+std::string MakeNestedJson(int depth) {
+  std::string json;
+  for (int ii = 0; ii < depth; ++ii)
+    json += "{\"foo\":";
+  json += "42";
+  for (int ii = 0; ii < depth; ++ii)
+    json += "}";
+  return json;
+}
+
+TEST_F(JsonParserTest, StackLimitExceededError) {
+  // kStackLimit is 1000 (see json_parser.cc). First let's
+  // try with a small nested example.
+  std::string json_3 = MakeNestedJson(3);
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json_3), &log_);
+  EXPECT_TRUE(log_.status().ok());
+  EXPECT_EQ(
+      "map begin\n"
+      "string16: foo\n"
+      "map begin\n"
+      "string16: foo\n"
+      "map begin\n"
+      "string16: foo\n"
+      "int: 42\n"
+      "map end\n"
+      "map end\n"
+      "map end\n",
+      log_.str());
+
+  // Now with kStackLimit (200).
+  log_ = Log();
+  std::string json_limit = MakeNestedJson(200);
+  ParseJSON(GetTestPlatform(),
+            span<uint8_t>(reinterpret_cast<const uint8_t*>(json_limit.data()),
+                          json_limit.size()),
+            &log_);
+  EXPECT_TRUE(log_.status().ok());
+  // Now with kStackLimit + 1 (1001) - it exceeds in the innermost instance.
+  log_ = Log();
+  std::string exceeded = MakeNestedJson(1001);
+  ParseJSON(GetTestPlatform(), SpanFromStdString(exceeded), &log_);
+  EXPECT_EQ(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, log_.status().error);
+  EXPECT_EQ(static_cast<std::ptrdiff_t>(strlen("{\"foo\":") * 201),
+            log_.status().pos);
+  // Now way past the limit. Still, the point of exceeding is 201.
+  log_ = Log();
+  std::string far_out = MakeNestedJson(220);
+  ParseJSON(GetTestPlatform(), SpanFromStdString(far_out), &log_);
+  EXPECT_EQ(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, log_.status().error);
+  EXPECT_EQ(static_cast<std::ptrdiff_t>(strlen("{\"foo\":") * 201),
+            log_.status().pos);
+}
+
+TEST_F(JsonParserTest, NoInputError) {
+  std::string json = "";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_EQ(Error::JSON_PARSER_NO_INPUT, log_.status().error);
+  EXPECT_EQ(0, log_.status().pos);
+  EXPECT_EQ("", log_.str());
+}
+
+TEST_F(JsonParserTest, InvalidTokenError) {
+  std::string json = "|";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_EQ(Error::JSON_PARSER_INVALID_TOKEN, log_.status().error);
+  EXPECT_EQ(0, log_.status().pos);
+  EXPECT_EQ("", log_.str());
+}
+
+TEST_F(JsonParserTest, InvalidNumberError) {
+  // Mantissa exceeds max (the constant used here is int64_t max).
+  std::string json = "1E9223372036854775807";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_EQ(Error::JSON_PARSER_INVALID_NUMBER, log_.status().error);
+  EXPECT_EQ(0, log_.status().pos);
+  EXPECT_EQ("", log_.str());
+}
+
+TEST_F(JsonParserTest, InvalidStringError) {
+  // \x22 is an unsupported escape sequence
+  std::string json = "\"foo\\x22\"";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_EQ(Error::JSON_PARSER_INVALID_STRING, log_.status().error);
+  EXPECT_EQ(0, log_.status().pos);
+  EXPECT_EQ("", log_.str());
+}
+
+TEST_F(JsonParserTest, UnexpectedArrayEndError) {
+  std::string json = "[1,2,]";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_EQ(Error::JSON_PARSER_UNEXPECTED_ARRAY_END, log_.status().error);
+  EXPECT_EQ(5, log_.status().pos);
+  EXPECT_EQ("", log_.str());
+}
+
+TEST_F(JsonParserTest, CommaOrArrayEndExpectedError) {
+  std::string json = "[1,2 2";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_EQ(Error::JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED,
+            log_.status().error);
+  EXPECT_EQ(5, log_.status().pos);
+  EXPECT_EQ("", log_.str());
+}
+
+TEST_F(JsonParserTest, StringLiteralExpectedError) {
+  // There's an error because the key bar, a string, is not terminated.
+  std::string json = "{\"foo\": 3.1415, \"bar: 31415e-4}";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_EQ(Error::JSON_PARSER_STRING_LITERAL_EXPECTED, log_.status().error);
+  EXPECT_EQ(16, log_.status().pos);
+  EXPECT_EQ("", log_.str());
+}
+
+TEST_F(JsonParserTest, ColonExpectedError) {
+  std::string json = "{\"foo\", 42}";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_EQ(Error::JSON_PARSER_COLON_EXPECTED, log_.status().error);
+  EXPECT_EQ(6, log_.status().pos);
+  EXPECT_EQ("", log_.str());
+}
+
+TEST_F(JsonParserTest, UnexpectedMapEndError) {
+  std::string json = "{\"foo\": 42, }";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_EQ(Error::JSON_PARSER_UNEXPECTED_MAP_END, log_.status().error);
+  EXPECT_EQ(12, log_.status().pos);
+  EXPECT_EQ("", log_.str());
+}
+
+TEST_F(JsonParserTest, CommaOrMapEndExpectedError) {
+  // The second separator should be a comma.
+  std::string json = "{\"foo\": 3.1415: \"bar\": 0}";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_EQ(Error::JSON_PARSER_COMMA_OR_MAP_END_EXPECTED, log_.status().error);
+  EXPECT_EQ(14, log_.status().pos);
+  EXPECT_EQ("", log_.str());
+}
+
+TEST_F(JsonParserTest, ValueExpectedError) {
+  std::string json = "}";
+  ParseJSON(GetTestPlatform(), SpanFromStdString(json), &log_);
+  EXPECT_EQ(Error::JSON_PARSER_VALUE_EXPECTED, log_.status().error);
+  EXPECT_EQ(0, log_.status().pos);
+  EXPECT_EQ("", log_.str());
+}
+}  // namespace json
+}  // namespace inspector_protocol_encoding
diff --git a/third_party/inspector_protocol/encoding/json_parser.cc b/third_party/inspector_protocol/encoding/json_parser.cc
deleted file mode 100644
index 27a1f23..0000000
--- a/third_party/inspector_protocol/encoding/json_parser.cc
+++ /dev/null
@@ -1,588 +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 "json_parser.h"
-
-#include <cassert>
-#include <limits>
-#include <string>
-#include "status.h"
-
-namespace inspector_protocol {
-namespace {
-const int kStackLimit = 1000;
-
-enum Token {
-  ObjectBegin,
-  ObjectEnd,
-  ArrayBegin,
-  ArrayEnd,
-  StringLiteral,
-  Number,
-  BoolTrue,
-  BoolFalse,
-  NullToken,
-  ListSeparator,
-  ObjectPairSeparator,
-  InvalidToken,
-  NoInput
-};
-
-const char* const kNullString = "null";
-const char* const kTrueString = "true";
-const char* const kFalseString = "false";
-
-template <typename Char>
-class JsonParser {
- public:
-  JsonParser(const Platform* platform, JSONParserHandler* handler)
-      : platform_(platform), handler_(handler) {}
-
-  void Parse(const Char* start, std::size_t length) {
-    start_pos_ = start;
-    const Char* end = start + length;
-    const Char* tokenEnd;
-    ParseValue(start, end, &tokenEnd, 0);
-    if (tokenEnd != end) {
-      HandleError(Error::JSON_PARSER_UNPROCESSED_INPUT_REMAINS, tokenEnd);
-    }
-  }
-
- private:
-  bool CharsToDouble(const uint16_t* chars,
-                     std::size_t length,
-                     double* result) {
-    std::string buffer;
-    buffer.reserve(length + 1);
-    for (std::size_t ii = 0; ii < length; ++ii) {
-      bool is_ascii = !(chars[ii] & ~0x7F);
-      if (!is_ascii) return false;
-      buffer.push_back(static_cast<char>(chars[ii]));
-    }
-    return platform_->StrToD(buffer.c_str(), result);
-  }
-
-  bool CharsToDouble(const uint8_t* chars, std::size_t length, double* result) {
-    std::string buffer(reinterpret_cast<const char*>(chars), length);
-    return platform_->StrToD(buffer.c_str(), result);
-  }
-
-  static bool ParseConstToken(const Char* start, const Char* end,
-                              const Char** token_end, const char* token) {
-    // |token| is \0 terminated, it's one of the constants at top of the file.
-    while (start < end && *token != '\0' && *start++ == *token++) {
-    }
-    if (*token != '\0') return false;
-    *token_end = start;
-    return true;
-  }
-
-  static bool ReadInt(const Char* start, const Char* end,
-                      const Char** token_end, bool allow_leading_zeros) {
-    if (start == end) return false;
-    bool has_leading_zero = '0' == *start;
-    int length = 0;
-    while (start < end && '0' <= *start && *start <= '9') {
-      ++start;
-      ++length;
-    }
-    if (!length) return false;
-    if (!allow_leading_zeros && length > 1 && has_leading_zero) return false;
-    *token_end = start;
-    return true;
-  }
-
-  static bool ParseNumberToken(const Char* start, const Char* end,
-                               const Char** token_end) {
-    // We just grab the number here. We validate the size in DecodeNumber.
-    // According to RFC4627, a valid number is: [minus] int [frac] [exp]
-    if (start == end) return false;
-    Char c = *start;
-    if ('-' == c) ++start;
-
-    if (!ReadInt(start, end, &start, /*allow_leading_zeros=*/false))
-      return false;
-    if (start == end) {
-      *token_end = start;
-      return true;
-    }
-
-    // Optional fraction part
-    c = *start;
-    if ('.' == c) {
-      ++start;
-      if (!ReadInt(start, end, &start, /*allow_leading_zeros=*/true))
-        return false;
-      if (start == end) {
-        *token_end = start;
-        return true;
-      }
-      c = *start;
-    }
-
-    // Optional exponent part
-    if ('e' == c || 'E' == c) {
-      ++start;
-      if (start == end) return false;
-      c = *start;
-      if ('-' == c || '+' == c) {
-        ++start;
-        if (start == end) return false;
-      }
-      if (!ReadInt(start, end, &start, /*allow_leading_zeros=*/true))
-        return false;
-    }
-
-    *token_end = start;
-    return true;
-  }
-
-  static bool ReadHexDigits(const Char* start, const Char* end,
-                            const Char** token_end, int digits) {
-    if (end - start < digits) return false;
-    for (int i = 0; i < digits; ++i) {
-      Char c = *start++;
-      if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') ||
-            ('A' <= c && c <= 'F')))
-        return false;
-    }
-    *token_end = start;
-    return true;
-  }
-
-  static bool ParseStringToken(const Char* start, const Char* end,
-                               const Char** token_end) {
-    while (start < end) {
-      Char c = *start++;
-      if ('\\' == c) {
-        if (start == end) return false;
-        c = *start++;
-        // Make sure the escaped char is valid.
-        switch (c) {
-          case 'x':
-            if (!ReadHexDigits(start, end, &start, 2)) return false;
-            break;
-          case 'u':
-            if (!ReadHexDigits(start, end, &start, 4)) return false;
-            break;
-          case '\\':
-          case '/':
-          case 'b':
-          case 'f':
-          case 'n':
-          case 'r':
-          case 't':
-          case 'v':
-          case '"':
-            break;
-          default:
-            return false;
-        }
-      } else if ('"' == c) {
-        *token_end = start;
-        return true;
-      }
-    }
-    return false;
-  }
-
-  static bool SkipComment(const Char* start, const Char* end,
-                          const Char** comment_end) {
-    if (start == end) return false;
-
-    if (*start != '/' || start + 1 >= end) return false;
-    ++start;
-
-    if (*start == '/') {
-      // Single line comment, read to newline.
-      for (++start; start < end; ++start) {
-        if (*start == '\n' || *start == '\r') {
-          *comment_end = start + 1;
-          return true;
-        }
-      }
-      *comment_end = end;
-      // Comment reaches end-of-input, which is fine.
-      return true;
-    }
-
-    if (*start == '*') {
-      Char previous = '\0';
-      // Block comment, read until end marker.
-      for (++start; start < end; previous = *start++) {
-        if (previous == '*' && *start == '/') {
-          *comment_end = start + 1;
-          return true;
-        }
-      }
-      // Block comment must close before end-of-input.
-      return false;
-    }
-
-    return false;
-  }
-
-  static bool IsSpaceOrNewLine(Char c) {
-    // \v = vertial tab; \f = form feed page break.
-    return c == ' ' || c == '\n' || c == '\v' || c == '\f' || c == '\r' ||
-           c == '\t';
-  }
-
-  static void SkipWhitespaceAndComments(const Char* start, const Char* end,
-                                        const Char** whitespace_end) {
-    while (start < end) {
-      if (IsSpaceOrNewLine(*start)) {
-        ++start;
-      } else if (*start == '/') {
-        const Char* comment_end;
-        if (!SkipComment(start, end, &comment_end)) break;
-        start = comment_end;
-      } else {
-        break;
-      }
-    }
-    *whitespace_end = start;
-  }
-
-  static Token ParseToken(const Char* start, const Char* end,
-                          const Char** tokenStart, const Char** token_end) {
-    SkipWhitespaceAndComments(start, end, tokenStart);
-    start = *tokenStart;
-
-    if (start == end) return NoInput;
-
-    switch (*start) {
-      case 'n':
-        if (ParseConstToken(start, end, token_end, kNullString))
-          return NullToken;
-        break;
-      case 't':
-        if (ParseConstToken(start, end, token_end, kTrueString))
-          return BoolTrue;
-        break;
-      case 'f':
-        if (ParseConstToken(start, end, token_end, kFalseString))
-          return BoolFalse;
-        break;
-      case '[':
-        *token_end = start + 1;
-        return ArrayBegin;
-      case ']':
-        *token_end = start + 1;
-        return ArrayEnd;
-      case ',':
-        *token_end = start + 1;
-        return ListSeparator;
-      case '{':
-        *token_end = start + 1;
-        return ObjectBegin;
-      case '}':
-        *token_end = start + 1;
-        return ObjectEnd;
-      case ':':
-        *token_end = start + 1;
-        return ObjectPairSeparator;
-      case '0':
-      case '1':
-      case '2':
-      case '3':
-      case '4':
-      case '5':
-      case '6':
-      case '7':
-      case '8':
-      case '9':
-      case '-':
-        if (ParseNumberToken(start, end, token_end)) return Number;
-        break;
-      case '"':
-        if (ParseStringToken(start + 1, end, token_end)) return StringLiteral;
-        break;
-    }
-    return InvalidToken;
-  }
-
-  static int HexToInt(Char c) {
-    if ('0' <= c && c <= '9') return c - '0';
-    if ('A' <= c && c <= 'F') return c - 'A' + 10;
-    if ('a' <= c && c <= 'f') return c - 'a' + 10;
-    assert(false);  // Unreachable.
-    return 0;
-  }
-
-  static bool DecodeString(const Char* start, const Char* end,
-                           std::vector<uint16_t>* output) {
-    if (start == end) return true;
-    if (start > end) return false;
-    output->reserve(end - start);
-    while (start < end) {
-      uint16_t c = *start++;
-      // If the |Char| we're dealing with is really a byte, then
-      // we have utf8 here, and we need to check for multibyte characters
-      // and transcode them to utf16 (either one or two utf16 chars).
-      if (sizeof(Char) == sizeof(uint8_t) && c >= 0x7f) {
-        // Inspect the leading byte to figure out how long the utf8
-        // byte sequence is; while doing this initialize |codepoint|
-        // with the first few bits.
-        // See table in: https://en.wikipedia.org/wiki/UTF-8
-        // byte one is 110x xxxx -> 2 byte utf8 sequence
-        // byte one is 1110 xxxx -> 3 byte utf8 sequence
-        // byte one is 1111 0xxx -> 4 byte utf8 sequence
-        uint32_t codepoint;
-        int num_bytes_left;
-        if ((c & 0xe0) == 0xc0) {  // 2 byte utf8 sequence
-          num_bytes_left = 1;
-          codepoint = c & 0x1f;
-        } else if ((c & 0xf0) == 0xe0) {  // 3 byte utf8 sequence
-          num_bytes_left = 2;
-          codepoint = c & 0x0f;
-        } else if ((c & 0xf8) == 0xf0) {  // 4 byte utf8 sequence
-          codepoint = c & 0x07;
-          num_bytes_left = 3;
-        } else {
-          return false;  // invalid leading byte
-        }
-
-        // If we have enough bytes in our inpput, decode the remaining ones
-        // belonging to this Unicode character into |codepoint|.
-        if (start + num_bytes_left > end) return false;
-        while (num_bytes_left > 0) {
-          c = *start++;
-          --num_bytes_left;
-          // Check the next byte is a continuation byte, that is 10xx xxxx.
-          if ((c & 0xc0) != 0x80) return false;
-          codepoint = (codepoint << 6) | (c & 0x3f);
-        }
-
-        // Disallow overlong encodings for ascii characters, as these
-        // would include " and other characters significant to JSON
-        // string termination / control.
-        if (codepoint < 0x7f) return false;
-        // Invalid in UTF8, and can't be represented in UTF16 anyway.
-        if (codepoint > 0x10ffff) return false;
-
-        // So, now we transcode to UTF16,
-        // using the math described at https://en.wikipedia.org/wiki/UTF-16,
-        // for either one or two 16 bit characters.
-        if (codepoint < 0xffff) {
-          output->push_back(codepoint);
-          continue;
-        }
-        codepoint -= 0x10000;
-        output->push_back((codepoint >> 10) + 0xd800);    // high surrogate
-        output->push_back((codepoint & 0x3ff) + 0xdc00);  // low surrogate
-        continue;
-      }
-      if ('\\' != c) {
-        output->push_back(c);
-        continue;
-      }
-      if (start == end) return false;
-      c = *start++;
-
-      if (c == 'x') {
-        // \x is not supported.
-        return false;
-      }
-
-      switch (c) {
-        case '"':
-        case '/':
-        case '\\':
-          break;
-        case 'b':
-          c = '\b';
-          break;
-        case 'f':
-          c = '\f';
-          break;
-        case 'n':
-          c = '\n';
-          break;
-        case 'r':
-          c = '\r';
-          break;
-        case 't':
-          c = '\t';
-          break;
-        case 'v':
-          c = '\v';
-          break;
-        case 'u':
-          c = (HexToInt(*start) << 12) + (HexToInt(*(start + 1)) << 8) +
-              (HexToInt(*(start + 2)) << 4) + HexToInt(*(start + 3));
-          start += 4;
-          break;
-        default:
-          return false;
-      }
-      output->push_back(c);
-    }
-    return true;
-  }
-
-  void ParseValue(const Char* start, const Char* end,
-                  const Char** value_token_end, int depth) {
-    if (depth > kStackLimit) {
-      HandleError(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, start);
-      return;
-    }
-    const Char* token_start;
-    const Char* token_end;
-    Token token = ParseToken(start, end, &token_start, &token_end);
-    switch (token) {
-      case NoInput:
-        HandleError(Error::JSON_PARSER_NO_INPUT, token_start);
-        return;
-      case InvalidToken:
-        HandleError(Error::JSON_PARSER_INVALID_TOKEN, token_start);
-        return;
-      case NullToken:
-        handler_->HandleNull();
-        break;
-      case BoolTrue:
-        handler_->HandleBool(true);
-        break;
-      case BoolFalse:
-        handler_->HandleBool(false);
-        break;
-      case Number: {
-        double value;
-        if (!CharsToDouble(token_start, token_end - token_start, &value)) {
-          HandleError(Error::JSON_PARSER_INVALID_NUMBER, token_start);
-          return;
-        }
-        if (value >= std::numeric_limits<int32_t>::min() &&
-            value <= std::numeric_limits<int32_t>::max() &&
-            static_cast<int32_t>(value) == value)
-          handler_->HandleInt32(static_cast<int32_t>(value));
-        else
-          handler_->HandleDouble(value);
-        break;
-      }
-      case StringLiteral: {
-        std::vector<uint16_t> value;
-        bool ok = DecodeString(token_start + 1, token_end - 1, &value);
-        if (!ok) {
-          HandleError(Error::JSON_PARSER_INVALID_STRING, token_start);
-          return;
-        }
-        handler_->HandleString16(span<uint16_t>(value.data(), value.size()));
-        break;
-      }
-      case ArrayBegin: {
-        handler_->HandleArrayBegin();
-        start = token_end;
-        token = ParseToken(start, end, &token_start, &token_end);
-        while (token != ArrayEnd) {
-          ParseValue(start, end, &token_end, depth + 1);
-          if (error_) return;
-
-          // After a list value, we expect a comma or the end of the list.
-          start = token_end;
-          token = ParseToken(start, end, &token_start, &token_end);
-          if (token == ListSeparator) {
-            start = token_end;
-            token = ParseToken(start, end, &token_start, &token_end);
-            if (token == ArrayEnd) {
-              HandleError(Error::JSON_PARSER_UNEXPECTED_ARRAY_END, token_start);
-              return;
-            }
-          } else if (token != ArrayEnd) {
-            // Unexpected value after list value. Bail out.
-            HandleError(Error::JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED,
-                        token_start);
-            return;
-          }
-        }
-        handler_->HandleArrayEnd();
-        break;
-      }
-      case ObjectBegin: {
-        handler_->HandleObjectBegin();
-        start = token_end;
-        token = ParseToken(start, end, &token_start, &token_end);
-        while (token != ObjectEnd) {
-          if (token != StringLiteral) {
-            HandleError(Error::JSON_PARSER_STRING_LITERAL_EXPECTED,
-                        token_start);
-            return;
-          }
-          std::vector<uint16_t> key;
-          if (!DecodeString(token_start + 1, token_end - 1, &key)) {
-            HandleError(Error::JSON_PARSER_INVALID_STRING, token_start);
-            return;
-          }
-          handler_->HandleString16(span<uint16_t>(key.data(), key.size()));
-          start = token_end;
-
-          token = ParseToken(start, end, &token_start, &token_end);
-          if (token != ObjectPairSeparator) {
-            HandleError(Error::JSON_PARSER_COLON_EXPECTED, token_start);
-            return;
-          }
-          start = token_end;
-
-          ParseValue(start, end, &token_end, depth + 1);
-          if (error_) return;
-          start = token_end;
-
-          // After a key/value pair, we expect a comma or the end of the
-          // object.
-          token = ParseToken(start, end, &token_start, &token_end);
-          if (token == ListSeparator) {
-            start = token_end;
-            token = ParseToken(start, end, &token_start, &token_end);
-            if (token == ObjectEnd) {
-              HandleError(Error::JSON_PARSER_UNEXPECTED_OBJECT_END,
-                          token_start);
-              return;
-            }
-          } else if (token != ObjectEnd) {
-            // Unexpected value after last object value. Bail out.
-            HandleError(Error::JSON_PARSER_COMMA_OR_OBJECT_END_EXPECTED,
-                        token_start);
-            return;
-          }
-        }
-        handler_->HandleObjectEnd();
-        break;
-      }
-
-      default:
-        // We got a token that's not a value.
-        HandleError(Error::JSON_PARSER_VALUE_EXPECTED, token_start);
-        return;
-    }
-
-    SkipWhitespaceAndComments(token_end, end, value_token_end);
-  }
-
-  void HandleError(Error error, const Char* pos) {
-    assert(error != Error::OK);
-    if (!error_) {
-      handler_->HandleError(Status{error, pos - start_pos_});
-      error_ = true;
-    }
-  }
-
-  const Char* start_pos_ = nullptr;
-  bool error_ = false;
-  const Platform* platform_;
-  JSONParserHandler* handler_;
-};
-}  // namespace
-
-void ParseJSONChars(const Platform* platform, span<uint8_t> chars,
-                    JSONParserHandler* handler) {
-  JsonParser<uint8_t> parser(platform, handler);
-  parser.Parse(chars.data(), chars.size());
-}
-
-void ParseJSONChars(const Platform* platform, span<uint16_t> chars,
-                    JSONParserHandler* handler) {
-  JsonParser<uint16_t> parser(platform, handler);
-  parser.Parse(chars.data(), chars.size());
-}
-}  // namespace inspector_protocol
diff --git a/third_party/inspector_protocol/encoding/json_parser.h b/third_party/inspector_protocol/encoding/json_parser.h
deleted file mode 100644
index 55384be..0000000
--- a/third_party/inspector_protocol/encoding/json_parser.h
+++ /dev/null
@@ -1,22 +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 INSPECTOR_PROTOCOL_ENCODING_JSON_PARSER_H_
-#define INSPECTOR_PROTOCOL_ENCODING_JSON_PARSER_H_
-
-#include <cstdint>
-#include <vector>
-#include "json_parser_handler.h"
-#include "platform.h"
-#include "span.h"
-
-namespace inspector_protocol {
-// JSON parsing routines.
-void ParseJSONChars(const Platform* platform, span<uint8_t> chars,
-                    JSONParserHandler* handler);
-void ParseJSONChars(const Platform* platform, span<uint16_t> chars,
-                    JSONParserHandler* handler);
-}  // namespace inspector_protocol
-
-#endif  // INSPECTOR_PROTOCOL_ENCODING_JSON_PARSER_H_
diff --git a/third_party/inspector_protocol/encoding/json_parser_handler.h b/third_party/inspector_protocol/encoding/json_parser_handler.h
deleted file mode 100644
index d90b65f7..0000000
--- a/third_party/inspector_protocol/encoding/json_parser_handler.h
+++ /dev/null
@@ -1,38 +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 INSPECTOR_PROTOCOL_ENCODING_JSON_PARSER_HANDLER_H_
-#define INSPECTOR_PROTOCOL_ENCODING_JSON_PARSER_HANDLER_H_
-
-#include <cstdint>
-#include <vector>
-#include "span.h"
-#include "status.h"
-
-namespace inspector_protocol {
-// Handler interface for JSON parser events. See also json_parser.h.
-class JSONParserHandler {
- public:
-  virtual ~JSONParserHandler() = default;
-  virtual void HandleObjectBegin() = 0;
-  virtual void HandleObjectEnd() = 0;
-  virtual void HandleArrayBegin() = 0;
-  virtual void HandleArrayEnd() = 0;
-  virtual void HandleString8(span<uint8_t> chars) = 0;
-  virtual void HandleString16(span<uint16_t> chars) = 0;
-  virtual void HandleBinary(std::vector<uint8_t> bytes) = 0;
-  virtual void HandleDouble(double value) = 0;
-  virtual void HandleInt32(int32_t value) = 0;
-  virtual void HandleBool(bool value) = 0;
-  virtual void HandleNull() = 0;
-
-  // The parser may send one error even after other events have already
-  // been received. Client code is reponsible to then discard the
-  // already processed events.
-  // |error| must be an eror, as in, |error.is_ok()| can't be true.
-  virtual void HandleError(Status error) = 0;
-};
-}  // namespace inspector_protocol
-
-#endif  // INSPECTOR_PROTOCOL_ENCODING_JSON_PARSER_HANDLER_H_
diff --git a/third_party/inspector_protocol/encoding/json_parser_test.cc b/third_party/inspector_protocol/encoding/json_parser_test.cc
deleted file mode 100644
index 2e63129..0000000
--- a/third_party/inspector_protocol/encoding/json_parser_test.cc
+++ /dev/null
@@ -1,413 +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 "json_parser.h"
-
-#include <iostream>
-#include <sstream>
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "gtest/gtest.h"
-#include "linux_dev_platform.h"
-
-namespace inspector_protocol {
-class Log : public JSONParserHandler {
- public:
-  void HandleObjectBegin() override { log_ << "object begin\n"; }
-
-  void HandleObjectEnd() override { log_ << "object end\n"; }
-
-  void HandleArrayBegin() override { log_ << "array begin\n"; }
-
-  void HandleArrayEnd() override { log_ << "array end\n"; }
-
-  void HandleString8(span<uint8_t> chars) override {
-    base::StringPiece foo(reinterpret_cast<const char*>(chars.data()),
-                          chars.size());
-    log_ << "string8: " << foo << "\n";
-  }
-
-  void HandleString16(span<uint16_t> chars) override {
-    base::StringPiece16 foo(reinterpret_cast<const base::char16*>(chars.data()),
-                            chars.size());
-    log_ << "string16: " << base::UTF16ToUTF8(foo) << "\n";
-  }
-
-  void HandleBinary(std::vector<uint8_t> bytes) override {
-    // JSON doesn't have native support for arbitrary bytes, so our parser will
-    // never call this.
-    assert(false);
-  }
-
-  void HandleDouble(double value) override {
-    log_ << "double: " << value << "\n";
-  }
-
-  void HandleInt32(int32_t value) override { log_ << "int: " << value << "\n"; }
-
-  void HandleBool(bool value) override { log_ << "bool: " << value << "\n"; }
-
-  void HandleNull() override { log_ << "null\n"; }
-
-  void HandleError(Status status) override { status_ = status; }
-
-  std::string str() const { return status_.ok() ? log_.str() : ""; }
-
-  Status status() const { return status_; }
-
- private:
-  std::ostringstream log_;
-  Status status_;
-};
-
-class JsonParserTest : public ::testing::Test {
- protected:
-  Log log_;
-};
-
-TEST_F(JsonParserTest, SimpleDictionary) {
-  std::string json = "{\"foo\": 42}";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_TRUE(log_.status().ok());
-  EXPECT_EQ(
-      "object begin\n"
-      "string16: foo\n"
-      "int: 42\n"
-      "object end\n",
-      log_.str());
-}
-
-TEST_F(JsonParserTest, Whitespace) {
-  std::string json = "\n  {\n\"msg\"\n: \v\"Hello, world.\"\t\r}\t";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_TRUE(log_.status().ok());
-  EXPECT_EQ(
-      "object begin\n"
-      "string16: msg\n"
-      "string16: Hello, world.\n"
-      "object end\n",
-      log_.str());
-}
-
-TEST_F(JsonParserTest, NestedDictionary) {
-  std::string json = "{\"foo\": {\"bar\": {\"baz\": 1}, \"bar2\": 2}}";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_TRUE(log_.status().ok());
-  EXPECT_EQ(
-      "object begin\n"
-      "string16: foo\n"
-      "object begin\n"
-      "string16: bar\n"
-      "object begin\n"
-      "string16: baz\n"
-      "int: 1\n"
-      "object end\n"
-      "string16: bar2\n"
-      "int: 2\n"
-      "object end\n"
-      "object end\n",
-      log_.str());
-}
-
-TEST_F(JsonParserTest, Doubles) {
-  std::string json = "{\"foo\": 3.1415, \"bar\": 31415e-4}";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_TRUE(log_.status().ok());
-  EXPECT_EQ(
-      "object begin\n"
-      "string16: foo\n"
-      "double: 3.1415\n"
-      "string16: bar\n"
-      "double: 3.1415\n"
-      "object end\n",
-      log_.str());
-}
-
-TEST_F(JsonParserTest, Unicode) {
-  // Globe character. 0xF0 0x9F 0x8C 0x8E in utf8, 0xD83C 0xDF0E in utf16.
-  std::string json = "{\"msg\": \"Hello, \\uD83C\\uDF0E.\"}";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_TRUE(log_.status().ok());
-  EXPECT_EQ(
-      "object begin\n"
-      "string16: msg\n"
-      "string16: Hello, 🌎.\n"
-      "object end\n",
-      log_.str());
-}
-
-TEST_F(JsonParserTest, Unicode_ParseUtf16) {
-  // Globe character. utf8: 0xF0 0x9F 0x8C 0x8E; utf16: 0xD83C 0xDF0E.
-  // Crescent moon character. utf8: 0xF0 0x9F 0x8C 0x99; utf16: 0xD83C 0xDF19.
-
-  // We provide the moon with json escape, but the earth as utf16 input.
-  // Either way they arrive as utf8 (after decoding in log_.str()).
-  base::string16 json = base::UTF8ToUTF16("{\"space\": \"🌎 \\uD83C\\uDF19.\"}");
-  ParseJSONChars(GetLinuxDevPlatform(),
-                 span<uint16_t>(reinterpret_cast<const uint16_t*>(json.data()),
-                                json.size()),
-                 &log_);
-  EXPECT_TRUE(log_.status().ok());
-  EXPECT_EQ(
-      "object begin\n"
-      "string16: space\n"
-      "string16: 🌎 🌙.\n"
-      "object end\n",
-      log_.str());
-}
-
-TEST_F(JsonParserTest, Unicode_ParseUtf8) {
-  // Used below:
-  // гласность - example for 2 byte utf8, Russian word "glasnost"
-  // 屋 - example for 3 byte utf8, Chinese word for "house"
-  // 🌎 - example for 4 byte utf8: 0xF0 0x9F 0x8C 0x8E; utf16: 0xD83C 0xDF0E.
-  // 🌙 - example for escapes: utf8: 0xF0 0x9F 0x8C 0x99; utf16: 0xD83C 0xDF19.
-
-  // We provide the moon with json escape, but the earth as utf8 input.
-  // Either way they arrive as utf8 (after decoding in log_.str()).
-  std::string json =
-      "{"
-      "\"escapes\": \"\\uD83C\\uDF19\","
-      "\"2 byte\":\"гласность\","
-      "\"3 byte\":\"屋\","
-      "\"4 byte\":\"🌎\""
-      "}";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_TRUE(log_.status().ok());
-  EXPECT_EQ(
-      "object begin\n"
-      "string16: escapes\n"
-      "string16: 🌙\n"
-      "string16: 2 byte\n"
-      "string16: гласность\n"
-      "string16: 3 byte\n"
-      "string16: 屋\n"
-      "string16: 4 byte\n"
-      "string16: 🌎\n"
-      "object end\n",
-      log_.str());
-}
-
-TEST_F(JsonParserTest, UnprocessedInputRemainsError) {
-  // Trailing junk after the valid JSON.
-  std::string json = "{\"foo\": 3.1415} junk";
-  int64_t junk_idx = json.find("junk");
-  EXPECT_GT(junk_idx, 0);
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_EQ(Error::JSON_PARSER_UNPROCESSED_INPUT_REMAINS, log_.status().error);
-  EXPECT_EQ(junk_idx, log_.status().pos);
-  EXPECT_EQ("", log_.str());
-}
-
-std::string MakeNestedJson(int depth) {
-  std::string json;
-  for (int ii = 0; ii < depth; ++ii) json += "{\"foo\":";
-  json += "42";
-  for (int ii = 0; ii < depth; ++ii) json += "}";
-  return json;
-}
-
-TEST_F(JsonParserTest, StackLimitExceededError) {
-  // kStackLimit is 1000 (see json_parser.cc). First let's
-  // try with a small nested example.
-  std::string json_3 = MakeNestedJson(3);
-  ParseJSONChars(GetLinuxDevPlatform(),
-                 span<uint8_t>(reinterpret_cast<const uint8_t*>(json_3.data()),
-                               json_3.size()),
-                 &log_);
-  EXPECT_TRUE(log_.status().ok());
-  EXPECT_EQ(
-      "object begin\n"
-      "string16: foo\n"
-      "object begin\n"
-      "string16: foo\n"
-      "object begin\n"
-      "string16: foo\n"
-      "int: 42\n"
-      "object end\n"
-      "object end\n"
-      "object end\n",
-      log_.str());
-
-  // Now with kStackLimit (1000).
-  log_ = Log();
-  std::string json_limit = MakeNestedJson(1000);
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json_limit.data()),
-                    json_limit.size()),
-      &log_);
-  EXPECT_TRUE(log_.status().ok());
-  // Now with kStackLimit + 1 (1001) - it exceeds in the innermost instance.
-  log_ = Log();
-  std::string exceeded = MakeNestedJson(1001);
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(exceeded.data()),
-                    exceeded.size()),
-      &log_);
-  EXPECT_EQ(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, log_.status().error);
-  EXPECT_EQ(static_cast<std::ptrdiff_t>(strlen("{\"foo\":") * 1001),
-            log_.status().pos);
-  // Now way past the limit. Still, the point of exceeding is 1001.
-  log_ = Log();
-  std::string far_out = MakeNestedJson(10000);
-  ParseJSONChars(GetLinuxDevPlatform(),
-                 span<uint8_t>(reinterpret_cast<const uint8_t*>(far_out.data()),
-                               far_out.size()),
-                 &log_);
-  EXPECT_EQ(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, log_.status().error);
-  EXPECT_EQ(static_cast<std::ptrdiff_t>(strlen("{\"foo\":") * 1001),
-            log_.status().pos);
-}
-
-TEST_F(JsonParserTest, NoInputError) {
-  std::string json = "";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_EQ(Error::JSON_PARSER_NO_INPUT, log_.status().error);
-  EXPECT_EQ(0, log_.status().pos);
-  EXPECT_EQ("", log_.str());
-}
-
-TEST_F(JsonParserTest, InvalidTokenError) {
-  std::string json = "|";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_EQ(Error::JSON_PARSER_INVALID_TOKEN, log_.status().error);
-  EXPECT_EQ(0, log_.status().pos);
-  EXPECT_EQ("", log_.str());
-}
-
-TEST_F(JsonParserTest, InvalidNumberError) {
-  // Mantissa exceeds max (the constant used here is int64_t max).
-  std::string json = "1E9223372036854775807";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_EQ(Error::JSON_PARSER_INVALID_NUMBER, log_.status().error);
-  EXPECT_EQ(0, log_.status().pos);
-  EXPECT_EQ("", log_.str());
-}
-
-TEST_F(JsonParserTest, InvalidStringError) {
-  // \x22 is an unsupported escape sequence
-  std::string json = "\"foo\\x22\"";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_EQ(Error::JSON_PARSER_INVALID_STRING, log_.status().error);
-  EXPECT_EQ(0, log_.status().pos);
-  EXPECT_EQ("", log_.str());
-}
-
-TEST_F(JsonParserTest, UnexpectedArrayEndError) {
-  std::string json = "[1,2,]";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_EQ(Error::JSON_PARSER_UNEXPECTED_ARRAY_END, log_.status().error);
-  EXPECT_EQ(5, log_.status().pos);
-  EXPECT_EQ("", log_.str());
-}
-
-TEST_F(JsonParserTest, CommaOrArrayEndExpectedError) {
-  std::string json = "[1,2 2";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_EQ(Error::JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED,
-            log_.status().error);
-  EXPECT_EQ(5, log_.status().pos);
-  EXPECT_EQ("", log_.str());
-}
-
-TEST_F(JsonParserTest, StringLiteralExpectedError) {
-  // There's an error because the key bar, a string, is not terminated.
-  std::string json = "{\"foo\": 3.1415, \"bar: 31415e-4}";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_EQ(Error::JSON_PARSER_STRING_LITERAL_EXPECTED, log_.status().error);
-  EXPECT_EQ(16, log_.status().pos);
-  EXPECT_EQ("", log_.str());
-}
-
-TEST_F(JsonParserTest, ColonExpectedError) {
-  std::string json = "{\"foo\", 42}";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_EQ(Error::JSON_PARSER_COLON_EXPECTED, log_.status().error);
-  EXPECT_EQ(6, log_.status().pos);
-  EXPECT_EQ("", log_.str());
-}
-
-TEST_F(JsonParserTest, UnexpectedObjectEndError) {
-  std::string json = "{\"foo\": 42, }";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_EQ(Error::JSON_PARSER_UNEXPECTED_OBJECT_END, log_.status().error);
-  EXPECT_EQ(12, log_.status().pos);
-  EXPECT_EQ("", log_.str());
-}
-
-TEST_F(JsonParserTest, CommaOrObjectEndExpectedError) {
-  // The second separator should be a comma.
-  std::string json = "{\"foo\": 3.1415: \"bar\": 0}";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_EQ(Error::JSON_PARSER_COMMA_OR_OBJECT_END_EXPECTED,
-            log_.status().error);
-  EXPECT_EQ(14, log_.status().pos);
-  EXPECT_EQ("", log_.str());
-}
-
-TEST_F(JsonParserTest, ValueExpectedError) {
-  std::string json = "}";
-  ParseJSONChars(
-      GetLinuxDevPlatform(),
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(json.data()), json.size()),
-      &log_);
-  EXPECT_EQ(Error::JSON_PARSER_VALUE_EXPECTED, log_.status().error);
-  EXPECT_EQ(0, log_.status().pos);
-  EXPECT_EQ("", log_.str());
-}
-
-}  // namespace inspector_protocol
diff --git a/third_party/inspector_protocol/encoding/json_std_string_writer.cc b/third_party/inspector_protocol/encoding/json_std_string_writer.cc
deleted file mode 100644
index 1c849cc..0000000
--- a/third_party/inspector_protocol/encoding/json_std_string_writer.cc
+++ /dev/null
@@ -1,306 +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 "json_std_string_writer.h"
-#include <cassert>
-#include <stack>
-
-namespace inspector_protocol {
-namespace {
-// Prints |value| to |out| with 4 hex digits, most significant chunk first.
-void PrintHex(uint16_t value, std::string* out) {
-  for (int ii = 3; ii >= 0; --ii) {
-    int four_bits = 0xf & (value >> (4 * ii));
-    out->append(1, four_bits + ((four_bits <= 9) ? '0' : ('a' - 10)));
-  }
-}
-
-// In the writer below, we maintain a stack of State instances.
-// It is just enough to emit the appropriate delimiters and brackets
-// in JSON.
-enum class Container {
-  // Used for the top-level, initial state.
-  NONE,
-  // Inside a JSON object.
-  OBJECT,
-  // Inside a JSON array.
-  ARRAY
-};
-class State {
- public:
-  explicit State(Container container) : container_(container) {}
-  void StartElement(std::string* out) {
-    assert(container_ != Container::NONE || size_ == 0);
-    if (size_ != 0) {
-      char delim = (!(size_ & 1) || container_ == Container::ARRAY) ? ',' : ':';
-      out->append(1, delim);
-    }
-    ++size_;
-  }
-  Container container() const { return container_; }
-
- private:
-  Container container_ = Container::NONE;
-  int size_ = 0;
-};
-
-constexpr char kBase64Table[] =
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-    "abcdefghijklmnopqrstuvwxyz0123456789+/";
-
-void Base64Encode(const std::vector<uint8_t>& in, std::string* out) {
-  // The following three cases are based on the tables in the example
-  // section in https://en.wikipedia.org/wiki/Base64. We process three
-  // input bytes at a time, emitting 4 output bytes at a time.
-  std::size_t ii = 0;
-
-  // While possible, process three input bytes.
-  for (; ii + 3 <= in.size(); ii += 3) {
-    uint32_t twentyfour_bits = (in[ii] << 16) | (in[ii + 1] << 8) | in[ii + 2];
-    out->push_back(kBase64Table[(twentyfour_bits >> 18)]);
-    out->push_back(kBase64Table[(twentyfour_bits >> 12) & 0x3f]);
-    out->push_back(kBase64Table[(twentyfour_bits >> 6) & 0x3f]);
-    out->push_back(kBase64Table[twentyfour_bits & 0x3f]);
-  }
-  if (ii + 2 <= in.size()) {  // Process two input bytes.
-    uint32_t twentyfour_bits = (in[ii] << 16) | (in[ii + 1] << 8);
-    out->push_back(kBase64Table[(twentyfour_bits >> 18)]);
-    out->push_back(kBase64Table[(twentyfour_bits >> 12) & 0x3f]);
-    out->push_back(kBase64Table[(twentyfour_bits >> 6) & 0x3f]);
-    out->push_back('=');  // Emit padding.
-    return;
-  }
-  if (ii + 1 <= in.size()) {  // Process a single input byte.
-    uint32_t twentyfour_bits = (in[ii] << 16);
-    out->push_back(kBase64Table[(twentyfour_bits >> 18)]);
-    out->push_back(kBase64Table[(twentyfour_bits >> 12) & 0x3f]);
-    out->push_back('=');  // Emit padding.
-    out->push_back('=');  // Emit padding.
-  }
-}
-
-// Implements a handler for JSON parser events to emit a JSON string.
-class Writer : public JSONParserHandler {
- public:
-  Writer(Platform* platform, std::string* out, Status* status)
-      : platform_(platform), out_(out), status_(status) {
-    *status_ = Status();
-    state_.emplace(Container::NONE);
-  }
-
-  void HandleObjectBegin() override {
-    if (!status_->ok()) return;
-    assert(!state_.empty());
-    state_.top().StartElement(out_);
-    state_.emplace(Container::OBJECT);
-    out_->append("{");
-  }
-
-  void HandleObjectEnd() override {
-    if (!status_->ok()) return;
-    assert(state_.size() >= 2 && state_.top().container() == Container::OBJECT);
-    state_.pop();
-    out_->append("}");
-  }
-
-  void HandleArrayBegin() override {
-    if (!status_->ok()) return;
-    state_.top().StartElement(out_);
-    state_.emplace(Container::ARRAY);
-    out_->append("[");
-  }
-
-  void HandleArrayEnd() override {
-    if (!status_->ok()) return;
-    assert(state_.size() >= 2 && state_.top().container() == Container::ARRAY);
-    state_.pop();
-    out_->append("]");
-  }
-
-  void HandleString16(span<uint16_t> chars) override {
-    if (!status_->ok()) return;
-    state_.top().StartElement(out_);
-    out_->append("\"");
-    for (const uint16_t ch : chars) {
-      if (ch == '"') {
-        out_->append("\\\"");
-      } else if (ch == '\\') {
-        out_->append("\\\\");
-      } else if (ch == '\b') {
-        out_->append("\\b");
-      } else if (ch == '\f') {
-        out_->append("\\f");
-      } else if (ch == '\n') {
-        out_->append("\\n");
-      } else if (ch == '\r') {
-        out_->append("\\r");
-      } else if (ch == '\t') {
-        out_->append("\\t");
-      } else if (ch >= 32 && ch <= 126) {
-        out_->append(1, ch);
-      } else {
-        out_->append("\\u");
-        PrintHex(ch, out_);
-      }
-    }
-    out_->append("\"");
-  }
-
-  void HandleString8(span<uint8_t> chars) override {
-    if (!status_->ok())
-      return;
-    state_.top().StartElement(out_);
-    out_->append("\"");
-    for (std::ptrdiff_t ii = 0; ii < chars.size(); ++ii) {
-      uint8_t c = chars[ii];
-      if (c == '"') {
-        out_->append("\\\"");
-      } else if (c == '\\') {
-        out_->append("\\\\");
-      } else if (c == '\b') {
-        out_->append("\\b");
-      } else if (c == '\f') {
-        out_->append("\\f");
-      } else if (c == '\n') {
-        out_->append("\\n");
-      } else if (c == '\r') {
-        out_->append("\\r");
-      } else if (c == '\t') {
-        out_->append("\\t");
-      } else if (c >= 32 && c <= 126) {
-        out_->append(1, c);
-      } else if (c < 32) {
-        out_->append("\\u");
-        PrintHex(static_cast<uint16_t>(c), out_);
-      } else {
-        // Inspect the leading byte to figure out how long the utf8
-        // byte sequence is; while doing this initialize |codepoint|
-        // with the first few bits.
-        // See table in: https://en.wikipedia.org/wiki/UTF-8
-        // byte one is 110x xxxx -> 2 byte utf8 sequence
-        // byte one is 1110 xxxx -> 3 byte utf8 sequence
-        // byte one is 1111 0xxx -> 4 byte utf8 sequence
-        uint32_t codepoint;
-        int num_bytes_left;
-        if ((c & 0xe0) == 0xc0) {  // 2 byte utf8 sequence
-          num_bytes_left = 1;
-          codepoint = c & 0x1f;
-        } else if ((c & 0xf0) == 0xe0) {  // 3 byte utf8 sequence
-          num_bytes_left = 2;
-          codepoint = c & 0x0f;
-        } else if ((c & 0xf8) == 0xf0) {  // 4 byte utf8 sequence
-          codepoint = c & 0x07;
-          num_bytes_left = 3;
-        } else {
-          continue;  // invalid leading byte
-        }
-
-        // If we have enough bytes in our input, decode the remaining ones
-        // belonging to this Unicode character into |codepoint|.
-        if (ii + num_bytes_left > chars.size())
-          continue;
-        while (num_bytes_left > 0) {
-          c = chars[++ii];
-          --num_bytes_left;
-          // Check the next byte is a continuation byte, that is 10xx xxxx.
-          if ((c & 0xc0) != 0x80)
-            continue;
-          codepoint = (codepoint << 6) | (c & 0x3f);
-        }
-
-        // Disallow overlong encodings for ascii characters, as these
-        // would include " and other characters significant to JSON
-        // string termination / control.
-        if (codepoint < 0x7f)
-          continue;
-        // Invalid in UTF8, and can't be represented in UTF16 anyway.
-        if (codepoint > 0x10ffff)
-          continue;
-
-        // So, now we transcode to UTF16,
-        // using the math described at https://en.wikipedia.org/wiki/UTF-16,
-        // for either one or two 16 bit characters.
-        if (codepoint < 0xffff) {
-          out_->append("\\u");
-          PrintHex(static_cast<uint16_t>(codepoint), out_);
-          continue;
-        }
-        codepoint -= 0x10000;
-        // high surrogate
-        out_->append("\\u");
-        PrintHex(static_cast<uint16_t>((codepoint >> 10) + 0xd800), out_);
-        // low surrogate
-        out_->append("\\u");
-        PrintHex(static_cast<uint16_t>((codepoint & 0x3ff) + 0xdc00), out_);
-      }
-    }
-    out_->append("\"");
-  }
-
-  void HandleBinary(std::vector<uint8_t> bytes) override {
-    if (!status_->ok()) return;
-    state_.top().StartElement(out_);
-    out_->append("\"");
-    Base64Encode(bytes, out_);
-    out_->append("\"");
-  }
-
-  void HandleDouble(double value) override {
-    if (!status_->ok()) return;
-    state_.top().StartElement(out_);
-    std::unique_ptr<char[]> str_value = platform_->DToStr(value);
-
-    // DToStr may fail to emit a 0 before the decimal dot. E.g. this is
-    // the case in base::NumberToString in Chromium (which is based on
-    // dmg_fp). So, much like
-    // https://cs.chromium.org/chromium/src/base/json/json_writer.cc
-    // we probe for this and emit the leading 0 anyway if necessary.
-    const char* chars = str_value.get();
-    if (chars[0] == '.') {
-      out_->append("0");
-    } else if (chars[0] == '-' && chars[1] == '.') {
-      out_->append("-0");
-      ++chars;
-    }
-    out_->append(chars);
-  }
-
-  void HandleInt32(int32_t value) override {
-    if (!status_->ok()) return;
-    state_.top().StartElement(out_);
-    out_->append(std::to_string(value));
-  }
-
-  void HandleBool(bool value) override {
-    if (!status_->ok()) return;
-    state_.top().StartElement(out_);
-    out_->append(value ? "true" : "false");
-  }
-
-  void HandleNull() override {
-    if (!status_->ok()) return;
-    state_.top().StartElement(out_);
-    out_->append("null");
-  }
-
-  void HandleError(Status error) override {
-    assert(!error.ok());
-    *status_ = error;
-    out_->clear();
-  }
-
- private:
-  Platform* platform_;
-  std::string* out_;
-  Status* status_;
-  std::stack<State> state_;
-};
-}  // namespace
-
-std::unique_ptr<JSONParserHandler> NewJSONWriter(Platform* platform,
-                                                 std::string* out,
-                                                 Status* status) {
-  return std::unique_ptr<Writer>(new Writer(platform, out, status));
-}
-}  // namespace inspector_protocol
diff --git a/third_party/inspector_protocol/encoding/json_std_string_writer.h b/third_party/inspector_protocol/encoding/json_std_string_writer.h
deleted file mode 100644
index b2c9b634..0000000
--- a/third_party/inspector_protocol/encoding/json_std_string_writer.h
+++ /dev/null
@@ -1,25 +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 INSPECTOR_PROTOCOL_ENCODING_JSON_STD_STRING_WRITER_H_
-#define INSPECTOR_PROTOCOL_ENCODING_JSON_STD_STRING_WRITER_H_
-
-#include <memory>
-#include <string>
-#include "json_parser_handler.h"
-#include "platform.h"
-
-namespace inspector_protocol {
-// Returns a handler object which will write ascii characters to |out|.
-// |status->ok()| will be false iff the handler routine HandleError() is called.
-// In that case, we'll stop emitting output.
-// Except for calling the HandleError routine at any time, the client
-// code must call the Handle* methods in an order in which they'd occur
-// in valid JSON; otherwise we may crash (the code uses assert).
-std::unique_ptr<JSONParserHandler> NewJSONWriter(Platform* platform,
-                                                 std::string* out,
-                                                 Status* status);
-}  // namespace inspector_protocol
-
-#endif  // INSPECTOR_PROTOCOL_ENCODING_JSON_STD_STRING_WRITER_H_
diff --git a/third_party/inspector_protocol/encoding/json_std_string_writer_test.cc b/third_party/inspector_protocol/encoding/json_std_string_writer_test.cc
deleted file mode 100644
index 553f8b2..0000000
--- a/third_party/inspector_protocol/encoding/json_std_string_writer_test.cc
+++ /dev/null
@@ -1,162 +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 "json_std_string_writer.h"
-
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "gtest/gtest.h"
-#include "linux_dev_platform.h"
-
-namespace inspector_protocol {
-std::vector<uint16_t> UTF16String(const std::string& utf8) {
-  base::string16 string16 = base::UTF8ToUTF16(utf8);
-  return std::vector<uint16_t>(string16.data(),
-                               string16.data() + string16.size());
-}
-
-void WriteUTF8AsUTF16(JSONParserHandler* writer, const std::string& utf8) {
-  std::vector<uint16_t> utf16 = UTF16String(utf8);
-  writer->HandleString16(span<uint16_t>(utf16.data(), utf16.size()));
-}
-
-TEST(JsonStdStringWriterTest, HelloWorld) {
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  writer->HandleObjectBegin();
-  WriteUTF8AsUTF16(writer.get(), "msg1");
-  WriteUTF8AsUTF16(writer.get(), "Hello, 🌎.");
-  std::string key = "msg1-as-utf8";
-  std::string value = "Hello, 🌎.";
-  writer->HandleString8(
-      span<uint8_t>(reinterpret_cast<const uint8_t*>(key.data()), key.size()));
-  writer->HandleString8(span<uint8_t>(
-      reinterpret_cast<const uint8_t*>(value.data()), value.size()));
-  WriteUTF8AsUTF16(writer.get(), "msg2");
-  WriteUTF8AsUTF16(writer.get(), "\\\b\r\n\t\f\"");
-  WriteUTF8AsUTF16(writer.get(), "nested");
-  writer->HandleObjectBegin();
-  WriteUTF8AsUTF16(writer.get(), "double");
-  writer->HandleDouble(3.1415);
-  WriteUTF8AsUTF16(writer.get(), "int");
-  writer->HandleInt32(-42);
-  WriteUTF8AsUTF16(writer.get(), "bool");
-  writer->HandleBool(false);
-  WriteUTF8AsUTF16(writer.get(), "null");
-  writer->HandleNull();
-  writer->HandleObjectEnd();
-  WriteUTF8AsUTF16(writer.get(), "array");
-  writer->HandleArrayBegin();
-  writer->HandleInt32(1);
-  writer->HandleInt32(2);
-  writer->HandleInt32(3);
-  writer->HandleArrayEnd();
-  writer->HandleObjectEnd();
-  EXPECT_TRUE(status.ok());
-  EXPECT_EQ(
-      "{\"msg1\":\"Hello, \\ud83c\\udf0e.\","
-      "\"msg1-as-utf8\":\"Hello, \\ud83c\\udf0e.\","
-      "\"msg2\":\"\\\\\\b\\r\\n\\t\\f\\\"\","
-      "\"nested\":{\"double\":3.1415,\"int\":-42,"
-      "\"bool\":false,\"null\":null},\"array\":[1,2,3]}",
-      out);
-}
-
-TEST(JsonStdStringWriterTest, BinaryEncodedAsJsonString) {
-  // The encoder emits binary submitted to JSONParserHandler::HandleBinary
-  // as base64. The following three examples are taken from
-  // https://en.wikipedia.org/wiki/Base64.
-  {
-    std::string out;
-    Status status;
-    std::unique_ptr<JSONParserHandler> writer =
-        NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-    writer->HandleBinary({'M', 'a', 'n'});
-    EXPECT_TRUE(status.ok());
-    EXPECT_EQ("\"TWFu\"", out);
-  }
-  {
-    std::string out;
-    Status status;
-    std::unique_ptr<JSONParserHandler> writer =
-        NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-    writer->HandleBinary({'M', 'a'});
-    EXPECT_TRUE(status.ok());
-    EXPECT_EQ("\"TWE=\"", out);
-  }
-  {
-    std::string out;
-    Status status;
-    std::unique_ptr<JSONParserHandler> writer =
-        NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-    writer->HandleBinary({'M'});
-    EXPECT_TRUE(status.ok());
-    EXPECT_EQ("\"TQ==\"", out);
-  }
-  {  // "Hello, world.", verified with base64decode.org.
-    std::string out;
-    Status status;
-    std::unique_ptr<JSONParserHandler> writer =
-        NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-    writer->HandleBinary(
-        {'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.'});
-    EXPECT_TRUE(status.ok());
-    EXPECT_EQ("\"SGVsbG8sIHdvcmxkLg==\"", out);
-  }
-}
-
-TEST(JsonStdStringWriterTest, HandlesErrors) {
-  // When an error is sent via HandleError, it saves it in the provided
-  // status and clears the output.
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> writer =
-      NewJSONWriter(GetLinuxDevPlatform(), &out, &status);
-  writer->HandleObjectBegin();
-  WriteUTF8AsUTF16(writer.get(), "msg1");
-  writer->HandleError(Status{Error::JSON_PARSER_VALUE_EXPECTED, 42});
-  EXPECT_EQ(Error::JSON_PARSER_VALUE_EXPECTED, status.error);
-  EXPECT_EQ(42, status.pos);
-  EXPECT_EQ("", out);
-}
-
-// We'd use Gmock but unfortunately it only handles copyable return types.
-class MockPlatform : public Platform {
- public:
-  // Not implemented.
-  bool StrToD(const char* str, double* result) const override { return false; }
-
-  // A map with pre-registered responses for DToSTr.
-  std::map<double, std::string> dtostr_responses;
-
-  std::unique_ptr<char[]> DToStr(double value) const override {
-    auto it = dtostr_responses.find(value);
-    assert(it != dtostr_responses.end());
-    const std::string& str = it->second;
-    std::unique_ptr<char[]> response(new char[str.size() + 1]);
-    memcpy(response.get(), str.c_str(), str.size() + 1);
-    return response;
-  }
-};
-
-TEST(JsonStdStringWriterTest, DoubleToString) {
-  // This "broken" platform responds without the leading 0 before the
-  // decimal dot, so it'd be invalid JSON.
-  MockPlatform platform;
-  platform.dtostr_responses[.1] = ".1";
-  platform.dtostr_responses[-.7] = "-.7";
-
-  std::string out;
-  Status status;
-  std::unique_ptr<JSONParserHandler> writer =
-      NewJSONWriter(&platform, &out, &status);
-  writer->HandleArrayBegin();
-  writer->HandleDouble(.1);
-  writer->HandleDouble(-.7);
-  writer->HandleArrayEnd();
-  EXPECT_EQ("[0.1,-0.7]", out);
-}
-}  // namespace inspector_protocol
diff --git a/third_party/inspector_protocol/encoding/linux_dev_platform.cc b/third_party/inspector_protocol/encoding/linux_dev_platform.cc
deleted file mode 100644
index 142ca086..0000000
--- a/third_party/inspector_protocol/encoding/linux_dev_platform.cc
+++ /dev/null
@@ -1,49 +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 "linux_dev_platform.h"
-
-#include <clocale>
-#include <cstdlib>
-#include <cstring>
-#include <iomanip>
-#include <sstream>
-
-namespace inspector_protocol {
-namespace {
-class LinuxDevPlatform : public Platform {
-  bool StrToD(const char* str, double* result) const override {
-    // This is not thread-safe
-    // (see https://en.cppreference.com/w/cpp/locale/setlocale)
-    // but good enough for a unittest.
-    const char* saved_locale = std::setlocale(LC_NUMERIC, nullptr);
-    char* end;
-    *result = std::strtod(str, &end);
-    std::setlocale(LC_NUMERIC, saved_locale);
-    if (errno == ERANGE) {
-      // errno must be reset, e.g. see the example here:
-      // https://en.cppreference.com/w/cpp/string/byte/strtof
-      errno = 0;
-      return false;
-    }
-    return end == str + strlen(str);
-  }
-
-  std::unique_ptr<char[]> DToStr(double value) const override {
-    std::stringstream ss;
-    ss.imbue(std::locale("C"));
-    ss << value;
-    std::string str = ss.str();
-    std::unique_ptr<char[]> result(new char[str.size() + 1]);
-    memcpy(result.get(), str.c_str(), str.size() + 1);
-    return result;
-  }
-};
-}  // namespace
-
-Platform* GetLinuxDevPlatform() {
-  static Platform* deps = new LinuxDevPlatform;
-  return deps;
-}
-}  // namespace inspector_protocol
diff --git a/third_party/inspector_protocol/encoding/linux_dev_platform.h b/third_party/inspector_protocol/encoding/linux_dev_platform.h
deleted file mode 100644
index cf5dfd5b..0000000
--- a/third_party/inspector_protocol/encoding/linux_dev_platform.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef INSPECTOR_PROTOCOL_ENCODING_LINUX_DEV_PLATFORM_H_
-#define INSPECTOR_PROTOCOL_ENCODING_LINUX_DEV_PLATFORM_H_
-
-#include "platform.h"
-
-namespace inspector_protocol {
-// Returns an instance of the platform implementation that we're using for
-// development on Linux. This is intended and appropriate for tests for this
-// package, for now.
-Platform* GetLinuxDevPlatform();
-}  // namespace inspector_protocol
-
-#endif  // INSPECTOR_PROTOCOL_ENCODING_LINUX_DEV_PLATFORM_H_
diff --git a/third_party/inspector_protocol/encoding/platform.h b/third_party/inspector_protocol/encoding/platform.h
deleted file mode 100644
index cfd2d5d..0000000
--- a/third_party/inspector_protocol/encoding/platform.h
+++ /dev/null
@@ -1,25 +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 INSPECTOR_PROTOCOL_ENCODING_PLATFORM_H_
-#define INSPECTOR_PROTOCOL_ENCODING_PLATFORM_H_
-
-#include <memory>
-
-namespace inspector_protocol {
-// Client code must provide an instance. Implementation should delegate
-// to whatever is appropriate.
-class Platform {
- public:
-  virtual ~Platform() = default;
-  // Parses |str| into |result|. Returns false iff there are
-  // leftover characters or parsing errors.
-  virtual bool StrToD(const char* str, double* result) const = 0;
-
-  // Prints |value| in a format suitable for JSON.
-  virtual std::unique_ptr<char[]> DToStr(double value) const = 0;
-};
-}  // namespace inspector_protocol
-
-#endif  // INSPECTOR_PROTOCOL_ENCODING_PLATFORM_H_
diff --git a/third_party/inspector_protocol/encoding/span.h b/third_party/inspector_protocol/encoding/span.h
deleted file mode 100644
index 052062cf..0000000
--- a/third_party/inspector_protocol/encoding/span.h
+++ /dev/null
@@ -1,47 +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 INSPECTOR_PROTOCOL_ENCODING_SPAN_H_
-#define INSPECTOR_PROTOCOL_ENCODING_SPAN_H_
-
-#include <cstddef>
-
-namespace inspector_protocol {
-// This template is similar to std::span, which will be included in C++20.  Like
-// std::span it uses ptrdiff_t, which is signed (and thus a bit annoying
-// sometimes when comparing with size_t), but other than this it's much simpler.
-template <typename T>
-class span {
- public:
-  using index_type = std::ptrdiff_t;
-
-  span() : data_(nullptr), size_(0) {}
-  span(const T* data, index_type size) : data_(data), size_(size) {}
-
-  const T* data() const { return data_; }
-
-  const T* begin() const { return data_; }
-  const T* end() const { return data_ + size_; }
-
-  const T& operator[](index_type idx) const { return data_[idx]; }
-
-  span<T> subspan(index_type offset, index_type count) const {
-    return span(data_ + offset, count);
-  }
-
-  span<T> subspan(index_type offset) const {
-    return span(data_ + offset, size_ - offset);
-  }
-
-  bool empty() const { return size_ == 0; }
-
-  index_type size() const { return size_; }
-  index_type size_bytes() const { return size_ * sizeof(T); }
-
- private:
-  const T* data_;
-  index_type size_;
-};
-}  // namespace inspector_protocol
-#endif  // INSPECTOR_PROTOCOL_ENCODING_SPAN_H_
diff --git a/third_party/inspector_protocol/encoding/span_test.cc b/third_party/inspector_protocol/encoding/span_test.cc
deleted file mode 100644
index 48ee76d..0000000
--- a/third_party/inspector_protocol/encoding/span_test.cc
+++ /dev/null
@@ -1,57 +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 "span.h"
-
-#include "gtest/gtest.h"
-
-namespace inspector_protocol {
-template <typename T>
-class SpanTest : public ::testing::Test {};
-
-using TestTypes = ::testing::Types<uint8_t, uint16_t>;
-TYPED_TEST_SUITE(SpanTest, TestTypes);
-
-TYPED_TEST(SpanTest, Empty) {
-  span<TypeParam> empty;
-  EXPECT_TRUE(empty.empty());
-  EXPECT_EQ(0, empty.size());
-  EXPECT_EQ(0, empty.size_bytes());
-  EXPECT_EQ(empty.begin(), empty.end());
-}
-
-TYPED_TEST(SpanTest, SingleItem) {
-  TypeParam single_item = 42;
-  span<TypeParam> singular(&single_item, 1);
-  EXPECT_FALSE(singular.empty());
-  EXPECT_EQ(1, singular.size());
-  EXPECT_EQ(sizeof(TypeParam), static_cast<size_t>(singular.size_bytes()));
-  EXPECT_EQ(singular.begin() + 1, singular.end());
-  EXPECT_EQ(42, singular[0]);
-}
-
-TYPED_TEST(SpanTest, FiveItems) {
-  std::vector<TypeParam> test_input = {31, 32, 33, 34, 35};
-  span<TypeParam> five_items(test_input.data(), 5);
-  EXPECT_FALSE(five_items.empty());
-  EXPECT_EQ(5, five_items.size());
-  EXPECT_EQ(sizeof(TypeParam) * 5,
-            static_cast<size_t>(five_items.size_bytes()));
-  EXPECT_EQ(five_items.begin() + 5, five_items.end());
-  EXPECT_EQ(31, five_items[0]);
-  EXPECT_EQ(32, five_items[1]);
-  EXPECT_EQ(33, five_items[2]);
-  EXPECT_EQ(34, five_items[3]);
-  EXPECT_EQ(35, five_items[4]);
-  span<TypeParam> three_items = five_items.subspan(2);
-  EXPECT_EQ(3, three_items.size());
-  EXPECT_EQ(33, three_items[0]);
-  EXPECT_EQ(34, three_items[1]);
-  EXPECT_EQ(35, three_items[2]);
-  span<TypeParam> two_items = five_items.subspan(2, 2);
-  EXPECT_EQ(2, two_items.size());
-  EXPECT_EQ(33, two_items[0]);
-  EXPECT_EQ(34, two_items[1]);
-}
-}  // namespace inspector_protocol
diff --git a/third_party/inspector_protocol/encoding/status.h b/third_party/inspector_protocol/encoding/status.h
deleted file mode 100644
index ea4a3da..0000000
--- a/third_party/inspector_protocol/encoding/status.h
+++ /dev/null
@@ -1,61 +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 INSPECTOR_PROTOCOL_ENCODING_STATUS_H_
-#define INSPECTOR_PROTOCOL_ENCODING_STATUS_H_
-
-#include <cstdint>
-
-namespace inspector_protocol {
-// Error codes.
-enum class Error {
-  OK = 0,
-  // JSON parsing errors - json_parser.{h,cc}.
-  JSON_PARSER_UNPROCESSED_INPUT_REMAINS = 0x01,
-  JSON_PARSER_STACK_LIMIT_EXCEEDED = 0x02,
-  JSON_PARSER_NO_INPUT = 0x03,
-  JSON_PARSER_INVALID_TOKEN = 0x04,
-  JSON_PARSER_INVALID_NUMBER = 0x05,
-  JSON_PARSER_INVALID_STRING = 0x06,
-  JSON_PARSER_UNEXPECTED_ARRAY_END = 0x07,
-  JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED = 0x08,
-  JSON_PARSER_STRING_LITERAL_EXPECTED = 0x09,
-  JSON_PARSER_COLON_EXPECTED = 0x0a,
-  JSON_PARSER_UNEXPECTED_OBJECT_END = 0x0b,
-  JSON_PARSER_COMMA_OR_OBJECT_END_EXPECTED = 0x0c,
-  JSON_PARSER_VALUE_EXPECTED = 0x0d,
-
-  CBOR_INVALID_INT32 = 0x0e,
-  CBOR_INVALID_DOUBLE = 0x0f,
-  CBOR_INVALID_ENVELOPE = 0x10,
-  CBOR_INVALID_STRING8 = 0x11,
-  CBOR_INVALID_STRING16 = 0x12,
-  CBOR_INVALID_BINARY = 0x13,
-  CBOR_UNSUPPORTED_VALUE = 0x14,
-  CBOR_NO_INPUT = 0x15,
-  CBOR_INVALID_START_BYTE = 0x16,
-  CBOR_UNEXPECTED_EOF_EXPECTED_VALUE = 0x17,
-  CBOR_UNEXPECTED_EOF_IN_ARRAY = 0x18,
-  CBOR_UNEXPECTED_EOF_IN_MAP = 0x19,
-  CBOR_INVALID_MAP_KEY = 0x1a,
-  CBOR_STACK_LIMIT_EXCEEDED = 0x1b,
-  CBOR_STRING8_MUST_BE_7BIT = 0x1c,
-  CBOR_TRAILING_JUNK = 0x1d,
-  CBOR_MAP_START_EXPECTED = 0x1e,
-};
-
-// A status value with position that can be copied. The default status
-// is OK. Usually, error status values should come with a valid position.
-struct Status {
-  static constexpr std::ptrdiff_t npos() { return -1; }
-
-  bool ok() const { return error == Error::OK; }
-
-  Error error = Error::OK;
-  std::ptrdiff_t pos = npos();
-  Status(Error error, std::ptrdiff_t pos) : error(error), pos(pos) {}
-  Status() = default;
-};
-}  // namespace inspector_protocol
-#endif  // INSPECTOR_PROTOCOL_ENCODING_STATUS_H_
diff --git a/third_party/inspector_protocol/encoding/str_util.cc b/third_party/inspector_protocol/encoding/str_util.cc
deleted file mode 100644
index 1f4be7c..0000000
--- a/third_party/inspector_protocol/encoding/str_util.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "str_util.h"
-
-#include <cstring>
-
-namespace inspector_protocol {
-bool StrEq(span<uint8_t> left, span<uint8_t> right) {
-  return left.size() == right.size() &&
-         0 == memcmp(left.data(), right.data(), left.size());
-}
-
-bool StrEq(span<uint8_t> left, const char* null_terminated_right) {
-  return static_cast<std::size_t>(left.size()) ==
-             strlen(null_terminated_right) &&
-         0 == memcmp(left.data(), null_terminated_right, left.size());
-}
-}  // namespace inspector_protocol
diff --git a/third_party/inspector_protocol/encoding/str_util.h b/third_party/inspector_protocol/encoding/str_util.h
deleted file mode 100644
index f377541..0000000
--- a/third_party/inspector_protocol/encoding/str_util.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef INSPECTOR_PROTOCOL_ENCODING_STR_UTIL_H_
-#define INSPECTOR_PROTOCOL_ENCODING_STR_UTIL_H_
-
-#include <cstdint>
-
-#include "span.h"
-
-namespace inspector_protocol {
-// Returns true iff |left| and right have the same contents, byte for byte.
-bool StrEq(span<uint8_t> left, span<uint8_t> right);
-bool StrEq(span<uint8_t> left, const char* null_terminated_right);
-}  // namespace inspector_protocol
-#endif  // INSPECTOR_PROTOCOL_ENCODING_STR_UTIL_H_
diff --git a/third_party/inspector_protocol/inspector_protocol.gni b/third_party/inspector_protocol/inspector_protocol.gni
index ecee942..d612fb6a 100644
--- a/third_party/inspector_protocol/inspector_protocol.gni
+++ b/third_party/inspector_protocol/inspector_protocol.gni
@@ -33,10 +33,10 @@
       invoker.config_file,
       "$inspector_protocol_dir/lib/base_string_adapter_cc.template",
       "$inspector_protocol_dir/lib/base_string_adapter_h.template",
+      "$inspector_protocol_dir/lib/encoding_h.template",
+      "$inspector_protocol_dir/lib/encoding_cpp.template",
       "$inspector_protocol_dir/lib/Allocator_h.template",
       "$inspector_protocol_dir/lib/Array_h.template",
-      "$inspector_protocol_dir/lib/CBOR_h.template",
-      "$inspector_protocol_dir/lib/CBOR_cpp.template",
       "$inspector_protocol_dir/lib/DispatcherBase_cpp.template",
       "$inspector_protocol_dir/lib/DispatcherBase_h.template",
       "$inspector_protocol_dir/lib/ErrorSupport_cpp.template",
diff --git a/third_party/inspector_protocol/inspector_protocol.gypi b/third_party/inspector_protocol/inspector_protocol.gypi
index 3d0a60e..d614474 100644
--- a/third_party/inspector_protocol/inspector_protocol.gypi
+++ b/third_party/inspector_protocol/inspector_protocol.gypi
@@ -5,10 +5,10 @@
 {
   'variables': {
     'inspector_protocol_files': [
+      'lib/encoding_h.template',
+      'lib/encoding_cpp.template',
       'lib/Allocator_h.template',
       'lib/Array_h.template',
-      'lib/CBOR_h.template',
-      'lib/CBOR_cpp.template',
       'lib/DispatcherBase_cpp.template',
       'lib/DispatcherBase_h.template',
       'lib/ErrorSupport_cpp.template',
diff --git a/third_party/inspector_protocol/lib/CBOR_cpp.template b/third_party/inspector_protocol/lib/CBOR_cpp.template
deleted file mode 100644
index d2375b6c..0000000
--- a/third_party/inspector_protocol/lib/CBOR_cpp.template
+++ /dev/null
@@ -1,828 +0,0 @@
-{# This template is generated by gen_cbor_templates.py. #}
-// Generated by lib/CBOR_cpp.template.
-
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-
-#include <cassert>
-#include <limits>
-
-{% for namespace in config.protocol.namespace %}
-namespace {{namespace}} {
-{% endfor %}
-
-// ===== encoding/cbor.cc =====
-
-using namespace cbor;
-
-namespace {
-
-// See RFC 7049 Section 2.3, Table 2.
-static constexpr uint8_t kEncodedTrue =
-    EncodeInitialByte(MajorType::SIMPLE_VALUE, 21);
-static constexpr uint8_t kEncodedFalse =
-    EncodeInitialByte(MajorType::SIMPLE_VALUE, 20);
-static constexpr uint8_t kEncodedNull =
-    EncodeInitialByte(MajorType::SIMPLE_VALUE, 22);
-static constexpr uint8_t kInitialByteForDouble =
-    EncodeInitialByte(MajorType::SIMPLE_VALUE, 27);
-
-}  // namespace
-
-uint8_t EncodeTrue() { return kEncodedTrue; }
-uint8_t EncodeFalse() { return kEncodedFalse; }
-uint8_t EncodeNull() { return kEncodedNull; }
-
-uint8_t EncodeIndefiniteLengthArrayStart() {
-  return kInitialByteIndefiniteLengthArray;
-}
-
-uint8_t EncodeIndefiniteLengthMapStart() {
-  return kInitialByteIndefiniteLengthMap;
-}
-
-uint8_t EncodeStop() { return kStopByte; }
-
-namespace {
-// See RFC 7049 Table 3 and Section 2.4.4.2. This is used as a prefix for
-// arbitrary binary data encoded as BYTE_STRING.
-static constexpr uint8_t kExpectedConversionToBase64Tag =
-    EncodeInitialByte(MajorType::TAG, 22);
-
-// When parsing CBOR, we limit recursion depth for objects and arrays
-// to this constant.
-static constexpr int kStackLimit = 1000;
-
-// Writes the bytes for |v| to |out|, starting with the most significant byte.
-// See also: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
-template <typename T>
-void WriteBytesMostSignificantByteFirst(T v, std::vector<uint8_t>* out) {
-  for (int shift_bytes = sizeof(T) - 1; shift_bytes >= 0; --shift_bytes)
-    out->push_back(0xff & (v >> (shift_bytes * 8)));
-}
-}  // namespace
-
-namespace cbor_internals {
-// Writes the start of a token with |type|. The |value| may indicate the size,
-// or it may be the payload if the value is an unsigned integer.
-void WriteTokenStart(MajorType type, uint64_t value,
-                     std::vector<uint8_t>* encoded) {
-  if (value < 24) {
-    // Values 0-23 are encoded directly into the additional info of the
-    // initial byte.
-    encoded->push_back(EncodeInitialByte(type, /*additional_info=*/value));
-    return;
-  }
-  if (value <= std::numeric_limits<uint8_t>::max()) {
-    // Values 24-255 are encoded with one initial byte, followed by the value.
-    encoded->push_back(EncodeInitialByte(type, kAdditionalInformation1Byte));
-    encoded->push_back(value);
-    return;
-  }
-  if (value <= std::numeric_limits<uint16_t>::max()) {
-    // Values 256-65535: 1 initial byte + 2 bytes payload.
-    encoded->push_back(EncodeInitialByte(type, kAdditionalInformation2Bytes));
-    WriteBytesMostSignificantByteFirst<uint16_t>(value, encoded);
-    return;
-  }
-  if (value <= std::numeric_limits<uint32_t>::max()) {
-    // 32 bit uint: 1 initial byte + 4 bytes payload.
-    encoded->push_back(EncodeInitialByte(type, kAdditionalInformation4Bytes));
-    WriteBytesMostSignificantByteFirst<uint32_t>(static_cast<uint32_t>(value),
-                                                 encoded);
-    return;
-  }
-  // 64 bit uint: 1 initial byte + 8 bytes payload.
-  encoded->push_back(EncodeInitialByte(type, kAdditionalInformation8Bytes));
-  WriteBytesMostSignificantByteFirst<uint64_t>(value, encoded);
-}
-}  // namespace cbor_internals
-
-namespace {
-// Extracts sizeof(T) bytes from |in| to extract a value of type T
-// (e.g. uint64_t, uint32_t, ...), most significant byte first.
-// See also: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
-template <typename T>
-T ReadBytesMostSignificantByteFirst(span<uint8_t> in) {
-  assert(static_cast<std::size_t>(in.size()) >= sizeof(T));
-  T result = 0;
-  for (std::size_t shift_bytes = 0; shift_bytes < sizeof(T); ++shift_bytes)
-    result |= T(in[sizeof(T) - 1 - shift_bytes]) << (shift_bytes * 8);
-  return result;
-}
-}  // namespace
-
-namespace cbor_internals {
-int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value) {
-  if (bytes.empty()) return -1;
-  uint8_t initial_byte = bytes[0];
-  *type = MajorType((initial_byte & kMajorTypeMask) >> kMajorTypeBitShift);
-
-  uint8_t additional_information = initial_byte & kAdditionalInformationMask;
-  if (additional_information < 24) {
-    // Values 0-23 are encoded directly into the additional info of the
-    // initial byte.
-    *value = additional_information;
-    return 1;
-  }
-  if (additional_information == kAdditionalInformation1Byte) {
-    // Values 24-255 are encoded with one initial byte, followed by the value.
-    if (bytes.size() < 2) return -1;
-    *value = ReadBytesMostSignificantByteFirst<uint8_t>(bytes.subspan(1));
-    return 2;
-  }
-  if (additional_information == kAdditionalInformation2Bytes) {
-    // Values 256-65535: 1 initial byte + 2 bytes payload.
-    if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint16_t))
-      return -1;
-    *value = ReadBytesMostSignificantByteFirst<uint16_t>(bytes.subspan(1));
-    return 3;
-  }
-  if (additional_information == kAdditionalInformation4Bytes) {
-    // 32 bit uint: 1 initial byte + 4 bytes payload.
-    if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint32_t))
-      return -1;
-    *value = ReadBytesMostSignificantByteFirst<uint32_t>(bytes.subspan(1));
-    return 5;
-  }
-  if (additional_information == kAdditionalInformation8Bytes) {
-    // 64 bit uint: 1 initial byte + 8 bytes payload.
-    if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint64_t))
-      return -1;
-    *value = ReadBytesMostSignificantByteFirst<uint64_t>(bytes.subspan(1));
-    return 9;
-  }
-  return -1;
-}
-}  // namespace cbor_internals
-
-using cbor_internals::WriteTokenStart;
-using cbor_internals::ReadTokenStart;
-
-void EncodeInt32(int32_t value, std::vector<uint8_t>* out) {
-  if (value >= 0) {
-    WriteTokenStart(MajorType::UNSIGNED, value, out);
-  } else {
-    uint64_t representation = static_cast<uint64_t>(-(value + 1));
-    WriteTokenStart(MajorType::NEGATIVE, representation, out);
-  }
-}
-
-void EncodeString16(span<uint16_t> in, std::vector<uint8_t>* out) {
-  uint64_t byte_length = static_cast<uint64_t>(in.size_bytes());
-  WriteTokenStart(MajorType::BYTE_STRING, byte_length, out);
-  // When emitting UTF16 characters, we always write the least significant byte
-  // first; this is because it's the native representation for X86.
-  // TODO(johannes): Implement a more efficient thing here later, e.g.
-  // casting *iff* the machine has this byte order.
-  // The wire format for UTF16 chars will probably remain the same
-  // (least significant byte first) since this way we can have
-  // golden files, unittests, etc. that port easily and universally.
-  // See also:
-  // https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
-  for (const uint16_t two_bytes : in) {
-    out->push_back(two_bytes);
-    out->push_back(two_bytes >> 8);
-  }
-}
-
-void EncodeString8(span<uint8_t> in, std::vector<uint8_t>* out) {
-  WriteTokenStart(MajorType::STRING, static_cast<uint64_t>(in.size_bytes()),
-                  out);
-  out->insert(out->end(), in.begin(), in.end());
-}
-
-void EncodeFromLatin1(span<uint8_t> latin1, std::vector<uint8_t>* out) {
-  for (std::ptrdiff_t ii = 0; ii < latin1.size(); ++ii) {
-    if (latin1[ii] <= 127) continue;
-    // If there's at least one non-ASCII char, convert to UTF8.
-    std::vector<uint8_t> utf8(latin1.begin(), latin1.begin() + ii);
-    for (; ii < latin1.size(); ++ii) {
-      if (latin1[ii] <= 127) {
-        utf8.push_back(latin1[ii]);
-      } else {
-        // 0xC0 means it's a UTF8 sequence with 2 bytes.
-        utf8.push_back((latin1[ii] >> 6) | 0xc0);
-        utf8.push_back((latin1[ii] | 0x80) & 0xbf);
-      }
-    }
-    EncodeString8(span<uint8_t>(utf8.data(), utf8.size()), out);
-    return;
-  }
-  EncodeString8(latin1, out);
-}
-
-void EncodeFromUTF16(span<uint16_t> utf16, std::vector<uint8_t>* out) {
-  // If there's at least one non-ASCII char, encode as STRING16 (UTF16).
-  for (uint16_t ch : utf16) {
-    if (ch <= 127) continue;
-    EncodeString16(utf16, out);
-    return;
-  }
-  // It's all US-ASCII, strip out every second byte and encode as UTF8.
-  WriteTokenStart(MajorType::STRING, static_cast<uint64_t>(utf16.size()), out);
-  out->insert(out->end(), utf16.begin(), utf16.end());
-}
-
-void EncodeBinary(span<uint8_t> in, std::vector<uint8_t>* out) {
-  out->push_back(kExpectedConversionToBase64Tag);
-  uint64_t byte_length = static_cast<uint64_t>(in.size_bytes());
-  WriteTokenStart(MajorType::BYTE_STRING, byte_length, out);
-  out->insert(out->end(), in.begin(), in.end());
-}
-
-// A double is encoded with a specific initial byte
-// (kInitialByteForDouble) plus the 64 bits of payload for its value.
-constexpr std::ptrdiff_t kEncodedDoubleSize = 1 + sizeof(uint64_t);
-
-// An envelope is encoded with a specific initial byte
-// (kInitialByteForEnvelope), plus the start byte for a BYTE_STRING with a 32
-// bit wide length, plus a 32 bit length for that string.
-constexpr std::ptrdiff_t kEncodedEnvelopeHeaderSize = 1 + 1 + sizeof(uint32_t);
-
-void EncodeDouble(double value, std::vector<uint8_t>* out) {
-  // The additional_info=27 indicates 64 bits for the double follow.
-  // See RFC 7049 Section 2.3, Table 1.
-  out->push_back(kInitialByteForDouble);
-  union {
-    double from_double;
-    uint64_t to_uint64;
-  } reinterpret;
-  reinterpret.from_double = value;
-  WriteBytesMostSignificantByteFirst<uint64_t>(reinterpret.to_uint64, out);
-}
-
-void EnvelopeEncoder::EncodeStart(std::vector<uint8_t>* out) {
-  assert(byte_size_pos_ == 0);
-  out->push_back(kInitialByteForEnvelope);
-  out->push_back(kInitialByteFor32BitLengthByteString);
-  byte_size_pos_ = out->size();
-  out->resize(out->size() + sizeof(uint32_t));
-}
-
-bool EnvelopeEncoder::EncodeStop(std::vector<uint8_t>* out) {
-  assert(byte_size_pos_ != 0);
-  // The byte size is the size of the payload, that is, all the
-  // bytes that were written past the byte size position itself.
-  uint64_t byte_size = out->size() - (byte_size_pos_ + sizeof(uint32_t));
-  // We store exactly 4 bytes, so at most INT32MAX, with most significant
-  // byte first.
-  if (byte_size > std::numeric_limits<uint32_t>::max()) return false;
-  for (int shift_bytes = sizeof(uint32_t) - 1; shift_bytes >= 0;
-       --shift_bytes) {
-    (*out)[byte_size_pos_++] = 0xff & (byte_size >> (shift_bytes * 8));
-  }
-  return true;
-}
-
-namespace {
-class JSONToCBOREncoder : public JSONParserHandler {
- public:
-  JSONToCBOREncoder(std::vector<uint8_t>* out, Status* status)
-      : out_(out), status_(status) {
-    *status_ = Status();
-  }
-
-  void HandleObjectBegin() override {
-    envelopes_.emplace_back();
-    envelopes_.back().EncodeStart(out_);
-    out_->push_back(kInitialByteIndefiniteLengthMap);
-  }
-
-  void HandleObjectEnd() override {
-    out_->push_back(kStopByte);
-    assert(!envelopes_.empty());
-    envelopes_.back().EncodeStop(out_);
-    envelopes_.pop_back();
-  }
-
-  void HandleArrayBegin() override {
-    envelopes_.emplace_back();
-    envelopes_.back().EncodeStart(out_);
-    out_->push_back(kInitialByteIndefiniteLengthArray);
-  }
-
-  void HandleArrayEnd() override {
-    out_->push_back(kStopByte);
-    assert(!envelopes_.empty());
-    envelopes_.back().EncodeStop(out_);
-    envelopes_.pop_back();
-  }
-
-  void HandleString8(span<uint8_t> chars) override {
-    EncodeString8(chars, out_);
-  }
-
-  void HandleString16(span<uint16_t> chars) override {
-    for (uint16_t ch : chars) {
-      if (ch >= 0x7f) {
-        // If there's at least one non-7bit character, we encode as UTF16.
-        EncodeString16(chars, out_);
-        return;
-      }
-    }
-    std::vector<uint8_t> sevenbit_chars(chars.begin(), chars.end());
-    EncodeString8(span<uint8_t>(sevenbit_chars.data(), sevenbit_chars.size()),
-                  out_);
-  }
-
-  void HandleBinary(std::vector<uint8_t> bytes) override {
-    EncodeBinary(span<uint8_t>(bytes.data(), bytes.size()), out_);
-  }
-
-  void HandleDouble(double value) override { EncodeDouble(value, out_); }
-
-  void HandleInt32(int32_t value) override { EncodeInt32(value, out_); }
-
-  void HandleBool(bool value) override {
-    // See RFC 7049 Section 2.3, Table 2.
-    out_->push_back(value ? kEncodedTrue : kEncodedFalse);
-  }
-
-  void HandleNull() override {
-    // See RFC 7049 Section 2.3, Table 2.
-    out_->push_back(kEncodedNull);
-  }
-
-  void HandleError(Status error) override {
-    assert(!error.ok());
-    *status_ = error;
-    out_->clear();
-  }
-
- private:
-  std::vector<uint8_t>* out_;
-  std::vector<EnvelopeEncoder> envelopes_;
-  Status* status_;
-};
-}  // namespace
-
-std::unique_ptr<JSONParserHandler> NewJSONToCBOREncoder(
-    std::vector<uint8_t>* out, Status* status) {
-  return std::unique_ptr<JSONParserHandler>(new JSONToCBOREncoder(out, status));
-}
-
-namespace {
-// Below are three parsing routines for CBOR, which cover enough
-// to roundtrip JSON messages.
-bool ParseMap(int32_t stack_depth, CBORTokenizer* tokenizer,
-              JSONParserHandler* out);
-bool ParseArray(int32_t stack_depth, CBORTokenizer* tokenizer,
-                JSONParserHandler* out);
-bool ParseValue(int32_t stack_depth, CBORTokenizer* tokenizer,
-                JSONParserHandler* out);
-
-void ParseUTF16String(CBORTokenizer* tokenizer, JSONParserHandler* out) {
-  std::vector<uint16_t> value;
-  span<uint8_t> rep = tokenizer->GetString16WireRep();
-  for (std::ptrdiff_t ii = 0; ii < rep.size(); ii += 2)
-    value.push_back((rep[ii + 1] << 8) | rep[ii]);
-  out->HandleString16(span<uint16_t>(value.data(), value.size()));
-  tokenizer->Next();
-}
-
-bool ParseUTF8String(CBORTokenizer* tokenizer, JSONParserHandler* out) {
-  assert(tokenizer->TokenTag() == CBORTokenTag::STRING8);
-  out->HandleString8(tokenizer->GetString8());
-  tokenizer->Next();
-  return true;
-}
-
-bool ParseValue(int32_t stack_depth, CBORTokenizer* tokenizer,
-                JSONParserHandler* out) {
-  if (stack_depth > kStackLimit) {
-    out->HandleError(
-        Status{Error::CBOR_STACK_LIMIT_EXCEEDED, tokenizer->Status().pos});
-    return false;
-  }
-  // Skip past the envelope to get to what's inside.
-  if (tokenizer->TokenTag() == CBORTokenTag::ENVELOPE)
-    tokenizer->EnterEnvelope();
-  switch (tokenizer->TokenTag()) {
-    case CBORTokenTag::ERROR_VALUE:
-      out->HandleError(tokenizer->Status());
-      return false;
-    case CBORTokenTag::DONE:
-      out->HandleError(Status{Error::CBOR_UNEXPECTED_EOF_EXPECTED_VALUE,
-                              tokenizer->Status().pos});
-      return false;
-    case CBORTokenTag::TRUE_VALUE:
-      out->HandleBool(true);
-      tokenizer->Next();
-      return true;
-    case CBORTokenTag::FALSE_VALUE:
-      out->HandleBool(false);
-      tokenizer->Next();
-      return true;
-    case CBORTokenTag::NULL_VALUE:
-      out->HandleNull();
-      tokenizer->Next();
-      return true;
-    case CBORTokenTag::INT32:
-      out->HandleInt32(tokenizer->GetInt32());
-      tokenizer->Next();
-      return true;
-    case CBORTokenTag::DOUBLE:
-      out->HandleDouble(tokenizer->GetDouble());
-      tokenizer->Next();
-      return true;
-    case CBORTokenTag::STRING8:
-      return ParseUTF8String(tokenizer, out);
-    case CBORTokenTag::STRING16:
-      ParseUTF16String(tokenizer, out);
-      return true;
-    case CBORTokenTag::BINARY: {
-      span<uint8_t> binary = tokenizer->GetBinary();
-      out->HandleBinary(std::vector<uint8_t>(binary.begin(), binary.end()));
-      tokenizer->Next();
-      return true;
-    }
-    case CBORTokenTag::MAP_START:
-      return ParseMap(stack_depth + 1, tokenizer, out);
-    case CBORTokenTag::ARRAY_START:
-      return ParseArray(stack_depth + 1, tokenizer, out);
-    default:
-      out->HandleError(
-          Status{Error::CBOR_UNSUPPORTED_VALUE, tokenizer->Status().pos});
-      return false;
-  }
-}
-
-// |bytes| must start with the indefinite length array byte, so basically,
-// ParseArray may only be called after an indefinite length array has been
-// detected.
-bool ParseArray(int32_t stack_depth, CBORTokenizer* tokenizer,
-                JSONParserHandler* out) {
-  assert(tokenizer->TokenTag() == CBORTokenTag::ARRAY_START);
-  tokenizer->Next();
-  out->HandleArrayBegin();
-  while (tokenizer->TokenTag() != CBORTokenTag::STOP) {
-    if (tokenizer->TokenTag() == CBORTokenTag::DONE) {
-      out->HandleError(
-          Status{Error::CBOR_UNEXPECTED_EOF_IN_ARRAY, tokenizer->Status().pos});
-      return false;
-    }
-    if (tokenizer->TokenTag() == CBORTokenTag::ERROR_VALUE) {
-      out->HandleError(tokenizer->Status());
-      return false;
-    }
-    // Parse value.
-    if (!ParseValue(stack_depth, tokenizer, out)) return false;
-  }
-  out->HandleArrayEnd();
-  tokenizer->Next();
-  return true;
-}
-
-// |bytes| must start with the indefinite length array byte, so basically,
-// ParseArray may only be called after an indefinite length array has been
-// detected.
-bool ParseMap(int32_t stack_depth, CBORTokenizer* tokenizer,
-              JSONParserHandler* out) {
-  assert(tokenizer->TokenTag() == CBORTokenTag::MAP_START);
-  out->HandleObjectBegin();
-  tokenizer->Next();
-  while (tokenizer->TokenTag() != CBORTokenTag::STOP) {
-    if (tokenizer->TokenTag() == CBORTokenTag::DONE) {
-      out->HandleError(
-          Status{Error::CBOR_UNEXPECTED_EOF_IN_MAP, tokenizer->Status().pos});
-      return false;
-    }
-    if (tokenizer->TokenTag() == CBORTokenTag::ERROR_VALUE) {
-      out->HandleError(tokenizer->Status());
-      return false;
-    }
-    // Parse key.
-    if (tokenizer->TokenTag() == CBORTokenTag::STRING8) {
-      if (!ParseUTF8String(tokenizer, out)) return false;
-    } else if (tokenizer->TokenTag() == CBORTokenTag::STRING16) {
-      ParseUTF16String(tokenizer, out);
-    } else {
-      out->HandleError(
-          Status{Error::CBOR_INVALID_MAP_KEY, tokenizer->Status().pos});
-      return false;
-    }
-    // Parse value.
-    if (!ParseValue(stack_depth, tokenizer, out)) return false;
-  }
-  out->HandleObjectEnd();
-  tokenizer->Next();
-  return true;
-}
-}  // namespace
-
-void ParseCBOR(span<uint8_t> bytes, JSONParserHandler* json_out) {
-  if (bytes.empty()) {
-    json_out->HandleError(Status{Error::CBOR_NO_INPUT, 0});
-    return;
-  }
-  if (bytes[0] != kInitialByteForEnvelope) {
-    json_out->HandleError(Status{Error::CBOR_INVALID_START_BYTE, 0});
-    return;
-  }
-  CBORTokenizer tokenizer(bytes);
-  if (tokenizer.TokenTag() == CBORTokenTag::ERROR_VALUE) {
-    json_out->HandleError(tokenizer.Status());
-    return;
-  }
-  // We checked for the envelope start byte above, so the tokenizer
-  // must agree here, since it's not an error.
-  assert(tokenizer.TokenTag() == CBORTokenTag::ENVELOPE);
-  tokenizer.EnterEnvelope();
-  if (tokenizer.TokenTag() != CBORTokenTag::MAP_START) {
-    json_out->HandleError(
-        Status{Error::CBOR_MAP_START_EXPECTED, tokenizer.Status().pos});
-    return;
-  }
-  if (!ParseMap(/*stack_depth=*/1, &tokenizer, json_out)) return;
-  if (tokenizer.TokenTag() == CBORTokenTag::DONE) return;
-  if (tokenizer.TokenTag() == CBORTokenTag::ERROR_VALUE) {
-    json_out->HandleError(tokenizer.Status());
-    return;
-  }
-  json_out->HandleError(
-      Status{Error::CBOR_TRAILING_JUNK, tokenizer.Status().pos});
-}
-
-CBORTokenizer::CBORTokenizer(span<uint8_t> bytes) : bytes_(bytes) {
-  ReadNextToken(/*enter_envelope=*/false);
-}
-CBORTokenizer::~CBORTokenizer() {}
-
-CBORTokenTag CBORTokenizer::TokenTag() const { return token_tag_; }
-
-void CBORTokenizer::Next() {
-  if (token_tag_ == CBORTokenTag::ERROR_VALUE || token_tag_ == CBORTokenTag::DONE)
-    return;
-  ReadNextToken(/*enter_envelope=*/false);
-}
-
-void CBORTokenizer::EnterEnvelope() {
-  assert(token_tag_ == CBORTokenTag::ENVELOPE);
-  ReadNextToken(/*enter_envelope=*/true);
-}
-
-Status CBORTokenizer::Status() const { return status_; }
-
-int32_t CBORTokenizer::GetInt32() const {
-  assert(token_tag_ == CBORTokenTag::INT32);
-  // The range checks happen in ::ReadNextToken().
-  return static_cast<uint32_t>(
-      token_start_type_ == MajorType::UNSIGNED
-          ? token_start_internal_value_
-          : -static_cast<int64_t>(token_start_internal_value_) - 1);
-}
-
-double CBORTokenizer::GetDouble() const {
-  assert(token_tag_ == CBORTokenTag::DOUBLE);
-  union {
-    uint64_t from_uint64;
-    double to_double;
-  } reinterpret;
-  reinterpret.from_uint64 = ReadBytesMostSignificantByteFirst<uint64_t>(
-      bytes_.subspan(status_.pos + 1));
-  return reinterpret.to_double;
-}
-
-span<uint8_t> CBORTokenizer::GetString8() const {
-  assert(token_tag_ == CBORTokenTag::STRING8);
-  auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
-  return bytes_.subspan(status_.pos + (token_byte_length_ - length), length);
-}
-
-span<uint8_t> CBORTokenizer::GetString16WireRep() const {
-  assert(token_tag_ == CBORTokenTag::STRING16);
-  auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
-  return bytes_.subspan(status_.pos + (token_byte_length_ - length), length);
-}
-
-span<uint8_t> CBORTokenizer::GetBinary() const {
-  assert(token_tag_ == CBORTokenTag::BINARY);
-  auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
-  return bytes_.subspan(status_.pos + (token_byte_length_ - length), length);
-}
-
-void CBORTokenizer::ReadNextToken(bool enter_envelope) {
-  if (enter_envelope) {
-    status_.pos += kEncodedEnvelopeHeaderSize;
-  } else {
-    status_.pos =
-        status_.pos == Status::npos() ? 0 : status_.pos + token_byte_length_;
-  }
-  status_.error = Error::OK;
-  if (status_.pos >= bytes_.size()) {
-    token_tag_ = CBORTokenTag::DONE;
-    return;
-  }
-  switch (bytes_[status_.pos]) {
-    case kStopByte:
-      SetToken(CBORTokenTag::STOP, 1);
-      return;
-    case kInitialByteIndefiniteLengthMap:
-      SetToken(CBORTokenTag::MAP_START, 1);
-      return;
-    case kInitialByteIndefiniteLengthArray:
-      SetToken(CBORTokenTag::ARRAY_START, 1);
-      return;
-    case kEncodedTrue:
-      SetToken(CBORTokenTag::TRUE_VALUE, 1);
-      return;
-    case kEncodedFalse:
-      SetToken(CBORTokenTag::FALSE_VALUE, 1);
-      return;
-    case kEncodedNull:
-      SetToken(CBORTokenTag::NULL_VALUE, 1);
-      return;
-    case kExpectedConversionToBase64Tag: {  // BINARY
-      int8_t bytes_read =
-          ReadTokenStart(bytes_.subspan(status_.pos + 1), &token_start_type_,
-                         &token_start_internal_value_);
-      int64_t token_byte_length = 1 + bytes_read + token_start_internal_value_;
-      if (-1 == bytes_read || token_start_type_ != MajorType::BYTE_STRING ||
-          status_.pos + token_byte_length > bytes_.size()) {
-        SetError(Error::CBOR_INVALID_BINARY);
-        return;
-      }
-      SetToken(CBORTokenTag::BINARY,
-               static_cast<std::ptrdiff_t>(token_byte_length));
-      return;
-    }
-    case kInitialByteForDouble: {  // DOUBLE
-      if (status_.pos + kEncodedDoubleSize > bytes_.size()) {
-        SetError(Error::CBOR_INVALID_DOUBLE);
-        return;
-      }
-      SetToken(CBORTokenTag::DOUBLE, kEncodedDoubleSize);
-      return;
-    }
-    case kInitialByteForEnvelope: {  // ENVELOPE
-      if (status_.pos + kEncodedEnvelopeHeaderSize > bytes_.size()) {
-        SetError(Error::CBOR_INVALID_ENVELOPE);
-        return;
-      }
-      // The envelope must be a byte string with 32 bit length.
-      if (bytes_[status_.pos + 1] != kInitialByteFor32BitLengthByteString) {
-        SetError(Error::CBOR_INVALID_ENVELOPE);
-        return;
-      }
-      // Read the length of the byte string.
-      token_start_internal_value_ = ReadBytesMostSignificantByteFirst<uint32_t>(
-          bytes_.subspan(status_.pos + 2));
-      // Make sure the payload is contained within the message.
-      if (token_start_internal_value_ + kEncodedEnvelopeHeaderSize +
-              status_.pos >
-          static_cast<std::size_t>(bytes_.size())) {
-        SetError(Error::CBOR_INVALID_ENVELOPE);
-        return;
-      }
-      auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
-      SetToken(CBORTokenTag::ENVELOPE,
-               kEncodedEnvelopeHeaderSize + length);
-      return;
-    }
-    default: {
-      span<uint8_t> remainder =
-          bytes_.subspan(status_.pos, bytes_.size() - status_.pos);
-      assert(!remainder.empty());
-      int8_t token_start_length = ReadTokenStart(remainder, &token_start_type_,
-                                                 &token_start_internal_value_);
-      bool success = token_start_length != -1;
-      switch (token_start_type_) {
-        case MajorType::UNSIGNED:  // INT32.
-          if (!success || std::numeric_limits<int32_t>::max() <
-                              token_start_internal_value_) {
-            SetError(Error::CBOR_INVALID_INT32);
-            return;
-          }
-          SetToken(CBORTokenTag::INT32, token_start_length);
-          return;
-        case MajorType::NEGATIVE:  // INT32.
-          if (!success ||
-              std::numeric_limits<int32_t>::min() >
-                  -static_cast<int64_t>(token_start_internal_value_) - 1) {
-            SetError(Error::CBOR_INVALID_INT32);
-            return;
-          }
-          SetToken(CBORTokenTag::INT32, token_start_length);
-          return;
-        case MajorType::STRING: {  // STRING8.
-          if (!success || remainder.size() < static_cast<int64_t>(
-                                                 token_start_internal_value_)) {
-            SetError(Error::CBOR_INVALID_STRING8);
-            return;
-          }
-          auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
-          SetToken(CBORTokenTag::STRING8, token_start_length + length);
-          return;
-        }
-        case MajorType::BYTE_STRING: {  // STRING16.
-          if (!success ||
-              remainder.size() <
-                  static_cast<int64_t>(token_start_internal_value_) ||
-              // Must be divisible by 2 since UTF16 is 2 bytes per character.
-              token_start_internal_value_ & 1) {
-            SetError(Error::CBOR_INVALID_STRING16);
-            return;
-          }
-          auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
-          SetToken(CBORTokenTag::STRING16, token_start_length + length);
-          return;
-        }
-        case MajorType::ARRAY:
-        case MajorType::MAP:
-        case MajorType::TAG:
-        case MajorType::SIMPLE_VALUE:
-          SetError(Error::CBOR_UNSUPPORTED_VALUE);
-          return;
-      }
-    }
-  }
-}
-
-void CBORTokenizer::SetToken(CBORTokenTag token_tag,
-                             std::ptrdiff_t token_byte_length) {
-  token_tag_ = token_tag;
-  token_byte_length_ = token_byte_length;
-}
-
-void CBORTokenizer::SetError(Error error) {
-  token_tag_ = CBORTokenTag::ERROR_VALUE;
-  status_.error = error;
-}
-
-#if 0
-void DumpCBOR(span<uint8_t> cbor) {
-  std::string indent;
-  CBORTokenizer tokenizer(cbor);
-  while (true) {
-    fprintf(stderr, "%s", indent.c_str());
-    switch (tokenizer.TokenTag()) {
-      case CBORTokenTag::ERROR_VALUE:
-        fprintf(stderr, "ERROR {status.error=%d, status.pos=%ld}\n",
-               tokenizer.Status().error, tokenizer.Status().pos);
-        return;
-      case CBORTokenTag::DONE:
-        fprintf(stderr, "DONE\n");
-        return;
-      case CBORTokenTag::TRUE_VALUE:
-        fprintf(stderr, "TRUE_VALUE\n");
-        break;
-      case CBORTokenTag::FALSE_VALUE:
-        fprintf(stderr, "FALSE_VALUE\n");
-        break;
-      case CBORTokenTag::NULL_VALUE:
-        fprintf(stderr, "NULL_VALUE\n");
-        break;
-      case CBORTokenTag::INT32:
-        fprintf(stderr, "INT32 [%d]\n", tokenizer.GetInt32());
-        break;
-      case CBORTokenTag::DOUBLE:
-        fprintf(stderr, "DOUBLE [%lf]\n", tokenizer.GetDouble());
-        break;
-      case CBORTokenTag::STRING8: {
-        span<uint8_t> v = tokenizer.GetString8();
-        std::string t(v.begin(), v.end());
-        fprintf(stderr, "STRING8 [%s]\n", t.c_str());
-        break;
-      }
-      case CBORTokenTag::STRING16: {
-        span<uint8_t> v = tokenizer.GetString16WireRep();
-        std::string t(v.begin(), v.end());
-        fprintf(stderr, "STRING16 [%s]\n", t.c_str());
-        break;
-      }
-      case CBORTokenTag::BINARY: {
-        span<uint8_t> v = tokenizer.GetBinary();
-        std::string t(v.begin(), v.end());
-        fprintf(stderr, "BINARY [%s]\n", t.c_str());
-        break;
-      }
-      case CBORTokenTag::MAP_START:
-        fprintf(stderr, "MAP_START\n");
-        indent += "  ";
-        break;
-      case CBORTokenTag::ARRAY_START:
-        fprintf(stderr, "ARRAY_START\n");
-        indent += "  ";
-        break;
-      case CBORTokenTag::STOP:
-        fprintf(stderr, "STOP\n");
-        indent.erase(0, 2);
-        break;
-      case CBORTokenTag::ENVELOPE:
-        fprintf(stderr, "ENVELOPE\n");
-        tokenizer.EnterEnvelope();
-        continue;
-    }
-    tokenizer.Next();
-  }
-}
-#endif
-
-
-{% for namespace in config.protocol.namespace %}
-} // namespace {{namespace}}
-{% endfor %}
-
diff --git a/third_party/inspector_protocol/lib/Values_cpp.template b/third_party/inspector_protocol/lib/Values_cpp.template
index 20899a3..2d4463e2 100644
--- a/third_party/inspector_protocol/lib/Values_cpp.template
+++ b/third_party/inspector_protocol/lib/Values_cpp.template
@@ -66,21 +66,21 @@
 
 // Below are three parsing routines for CBOR, which cover enough
 // to roundtrip JSON messages.
-std::unique_ptr<DictionaryValue> parseMap(int32_t stack_depth, CBORTokenizer* tokenizer);
-std::unique_ptr<ListValue> parseArray(int32_t stack_depth, CBORTokenizer* tokenizer);
-std::unique_ptr<Value> parseValue(int32_t stack_depth, CBORTokenizer* tokenizer);
+std::unique_ptr<DictionaryValue> parseMap(int32_t stack_depth, cbor::CBORTokenizer* tokenizer);
+std::unique_ptr<ListValue> parseArray(int32_t stack_depth, cbor::CBORTokenizer* tokenizer);
+std::unique_ptr<Value> parseValue(int32_t stack_depth, cbor::CBORTokenizer* tokenizer);
 
 // |bytes| must start with the indefinite length array byte, so basically,
 // ParseArray may only be called after an indefinite length array has been
 // detected.
-std::unique_ptr<ListValue> parseArray(int32_t stack_depth, CBORTokenizer* tokenizer) {
-  DCHECK(tokenizer->TokenTag() == CBORTokenTag::ARRAY_START);
+std::unique_ptr<ListValue> parseArray(int32_t stack_depth, cbor::CBORTokenizer* tokenizer) {
+  DCHECK(tokenizer->TokenTag() == cbor::CBORTokenTag::ARRAY_START);
   tokenizer->Next();
   auto list = ListValue::create();
-  while (tokenizer->TokenTag() != CBORTokenTag::STOP) {
+  while (tokenizer->TokenTag() != cbor::CBORTokenTag::STOP) {
     // Error::CBOR_UNEXPECTED_EOF_IN_ARRAY
-    if (tokenizer->TokenTag() == CBORTokenTag::DONE) return nullptr;
-    if (tokenizer->TokenTag() == CBORTokenTag::ERROR_VALUE) return nullptr;
+    if (tokenizer->TokenTag() == cbor::CBORTokenTag::DONE) return nullptr;
+    if (tokenizer->TokenTag() == cbor::CBORTokenTag::ERROR_VALUE) return nullptr;
     // Parse value.
     auto value = parseValue(stack_depth, tokenizer);
     if (!value) return nullptr;
@@ -91,51 +91,51 @@
 }
 
 std::unique_ptr<Value> parseValue(
-    int32_t stack_depth, CBORTokenizer* tokenizer) {
+    int32_t stack_depth, cbor::CBORTokenizer* tokenizer) {
   // Error::CBOR_STACK_LIMIT_EXCEEDED
   if (stack_depth > kStackLimitValues) return nullptr;
   // Skip past the envelope to get to what's inside.
-  if (tokenizer->TokenTag() == CBORTokenTag::ENVELOPE)
+  if (tokenizer->TokenTag() == cbor::CBORTokenTag::ENVELOPE)
     tokenizer->EnterEnvelope();
   switch (tokenizer->TokenTag()) {
-    case CBORTokenTag::ERROR_VALUE:
+    case cbor::CBORTokenTag::ERROR_VALUE:
       return nullptr;
-    case CBORTokenTag::DONE:
+    case cbor::CBORTokenTag::DONE:
       // Error::CBOR_UNEXPECTED_EOF_EXPECTED_VALUE
       return nullptr;
-    case CBORTokenTag::TRUE_VALUE: {
+    case cbor::CBORTokenTag::TRUE_VALUE: {
       std::unique_ptr<Value> value = FundamentalValue::create(true);
       tokenizer->Next();
       return value;
     }
-    case CBORTokenTag::FALSE_VALUE: {
+    case cbor::CBORTokenTag::FALSE_VALUE: {
       std::unique_ptr<Value> value = FundamentalValue::create(false);
       tokenizer->Next();
       return value;
     }
-    case CBORTokenTag::NULL_VALUE: {
+    case cbor::CBORTokenTag::NULL_VALUE: {
       std::unique_ptr<Value> value = FundamentalValue::null();
       tokenizer->Next();
       return value;
     }
-    case CBORTokenTag::INT32: {
+    case cbor::CBORTokenTag::INT32: {
       std::unique_ptr<Value> value = FundamentalValue::create(tokenizer->GetInt32());
       tokenizer->Next();
       return value;
     }
-    case CBORTokenTag::DOUBLE: {
+    case cbor::CBORTokenTag::DOUBLE: {
       std::unique_ptr<Value> value = FundamentalValue::create(tokenizer->GetDouble());
       tokenizer->Next();
       return value;
     }
-    case CBORTokenTag::STRING8: {
+    case cbor::CBORTokenTag::STRING8: {
       span<uint8_t> str = tokenizer->GetString8();
       std::unique_ptr<Value> value =
           StringValue::create(StringUtil::fromUTF8(str.data(), str.size()));
       tokenizer->Next();
       return value;
     }
-    case CBORTokenTag::STRING16: {
+    case cbor::CBORTokenTag::STRING16: {
       span<uint8_t> wire = tokenizer->GetString16WireRep();
       DCHECK_EQ(wire.size() & 1, 0);
       std::unique_ptr<Value> value = StringValue::create(StringUtil::fromUTF16(
@@ -143,14 +143,14 @@
       tokenizer->Next();
       return value;
     }
-    case CBORTokenTag::BINARY: {
+    case cbor::CBORTokenTag::BINARY: {
       span<uint8_t> payload = tokenizer->GetBinary();
       tokenizer->Next();
       return BinaryValue::create(Binary::fromSpan(payload.data(), payload.size()));
     }
-    case CBORTokenTag::MAP_START:
+    case cbor::CBORTokenTag::MAP_START:
       return parseMap(stack_depth + 1, tokenizer);
-    case CBORTokenTag::ARRAY_START:
+    case cbor::CBORTokenTag::ARRAY_START:
       return parseArray(stack_depth + 1, tokenizer);
     default:
       // Error::CBOR_UNSUPPORTED_VALUE
@@ -162,22 +162,22 @@
 // ParseArray may only be called after an indefinite length array has been
 // detected.
 std::unique_ptr<DictionaryValue> parseMap(
-    int32_t stack_depth, CBORTokenizer* tokenizer) {
+    int32_t stack_depth, cbor::CBORTokenizer* tokenizer) {
   auto dict = DictionaryValue::create();
   tokenizer->Next();
-  while (tokenizer->TokenTag() != CBORTokenTag::STOP) {
-    if (tokenizer->TokenTag() == CBORTokenTag::DONE) {
+  while (tokenizer->TokenTag() != cbor::CBORTokenTag::STOP) {
+    if (tokenizer->TokenTag() == cbor::CBORTokenTag::DONE) {
       // Error::CBOR_UNEXPECTED_EOF_IN_MAP
       return nullptr;
     }
-    if (tokenizer->TokenTag() == CBORTokenTag::ERROR_VALUE) return nullptr;
+    if (tokenizer->TokenTag() == cbor::CBORTokenTag::ERROR_VALUE) return nullptr;
     // Parse key.
     String key;
-    if (tokenizer->TokenTag() == CBORTokenTag::STRING8) {
+    if (tokenizer->TokenTag() == cbor::CBORTokenTag::STRING8) {
       span<uint8_t> key_span = tokenizer->GetString8();
       key = StringUtil::fromUTF8(key_span.data(), key_span.size());
       tokenizer->Next();
-    } else if (tokenizer->TokenTag() == CBORTokenTag::STRING16) {
+    } else if (tokenizer->TokenTag() == cbor::CBORTokenTag::STRING16) {
       return nullptr;  // STRING16 not supported yet.
     } else {
       // Error::CBOR_INVALID_MAP_KEY
@@ -202,22 +202,21 @@
   if (bytes.empty()) return nullptr;
 
   // Error::CBOR_INVALID_START_BYTE
-  // TODO(johannes): EncodeInitialByteForEnvelope() method.
-  if (bytes[0] != 0xd8) return nullptr;
+  if (bytes[0] != cbor::InitialByteForEnvelope()) return nullptr;
 
-  CBORTokenizer tokenizer(bytes);
-  if (tokenizer.TokenTag() == CBORTokenTag::ERROR_VALUE) return nullptr;
+  cbor::CBORTokenizer tokenizer(bytes);
+  if (tokenizer.TokenTag() == cbor::CBORTokenTag::ERROR_VALUE) return nullptr;
 
   // We checked for the envelope start byte above, so the tokenizer
   // must agree here, since it's not an error.
-  DCHECK(tokenizer.TokenTag() == CBORTokenTag::ENVELOPE);
+  DCHECK(tokenizer.TokenTag() == cbor::CBORTokenTag::ENVELOPE);
   tokenizer.EnterEnvelope();
   // Error::MAP_START_EXPECTED
-  if (tokenizer.TokenTag() != CBORTokenTag::MAP_START) return nullptr;
+  if (tokenizer.TokenTag() != cbor::CBORTokenTag::MAP_START) return nullptr;
   std::unique_ptr<Value> result = parseMap(/*stack_depth=*/1, &tokenizer);
   if (!result) return nullptr;
-  if (tokenizer.TokenTag() == CBORTokenTag::DONE) return result;
-  if (tokenizer.TokenTag() == CBORTokenTag::ERROR_VALUE) return nullptr;
+  if (tokenizer.TokenTag() == cbor::CBORTokenTag::DONE) return result;
+  if (tokenizer.TokenTag() == cbor::CBORTokenTag::ERROR_VALUE) return nullptr;
   // Error::CBOR_TRAILING_JUNK
   return nullptr;
 }
@@ -255,7 +254,7 @@
 
 void Value::writeBinary(std::vector<uint8_t>* bytes) const {
     DCHECK(m_type == TypeNull);
-    bytes->push_back(EncodeNull());
+    bytes->push_back(cbor::EncodeNull());
 }
 
 std::unique_ptr<Value> Value::clone() const
@@ -332,13 +331,13 @@
 void FundamentalValue::writeBinary(std::vector<uint8_t>* bytes) const {
     switch (type()) {
     case TypeDouble:
-        EncodeDouble(m_doubleValue, bytes);
+        cbor::EncodeDouble(m_doubleValue, bytes);
         return;
     case TypeInteger:
-        EncodeInt32(m_integerValue, bytes);
+        cbor::EncodeInt32(m_integerValue, bytes);
         return;
     case TypeBoolean:
-        bytes->push_back(m_boolValue ? EncodeTrue() : EncodeFalse());
+        bytes->push_back(m_boolValue ? cbor::EncodeTrue() : cbor::EncodeFalse());
         return;
     default:
         DCHECK(false);
@@ -381,19 +380,19 @@
 //   transcodes to UTF8 if needed.
 void EncodeString(const String& s, std::vector<uint8_t>* out) {
   if (StringUtil::CharacterCount(s) == 0) {
-    EncodeString8(span<uint8_t>(nullptr, 0), out);  // Empty string.
+    cbor::EncodeString8(span<uint8_t>(nullptr, 0), out);  // Empty string.
   } else if (StringUtil::CharactersLatin1(s)) {
-    EncodeFromLatin1(span<uint8_t>(StringUtil::CharactersLatin1(s),
-                                   StringUtil::CharacterCount(s)),
-                     out);
+    cbor::EncodeFromLatin1(span<uint8_t>(StringUtil::CharactersLatin1(s),
+		                         StringUtil::CharacterCount(s)),
+                           out);
   } else if (StringUtil::CharactersUTF16(s)) {
-    EncodeFromUTF16(span<uint16_t>(StringUtil::CharactersUTF16(s),
-                                   StringUtil::CharacterCount(s)),
-                    out);
+    cbor::EncodeFromUTF16(span<uint16_t>(StringUtil::CharactersUTF16(s),
+                                         StringUtil::CharacterCount(s)),
+                          out);
   } else if (StringUtil::CharactersUTF8(s)) {
-    EncodeString8(span<uint8_t>(StringUtil::CharactersUTF8(s),
-                                StringUtil::CharacterCount(s)),
-                  out);
+    cbor::EncodeString8(span<uint8_t>(StringUtil::CharactersUTF8(s),
+                                      StringUtil::CharacterCount(s)),
+                        out);
   }
 }
 }  // namespace
@@ -420,7 +419,8 @@
 }
 
 void BinaryValue::writeBinary(std::vector<uint8_t>* bytes) const {
-    EncodeBinary(span<uint8_t>(m_binaryValue.data(), m_binaryValue.size()), bytes);
+    cbor::EncodeBinary(span<uint8_t>(m_binaryValue.data(),
+                                     m_binaryValue.size()), bytes);
 }
 
 std::unique_ptr<Value> BinaryValue::clone() const
@@ -583,9 +583,9 @@
 }
 
 void DictionaryValue::writeBinary(std::vector<uint8_t>* bytes) const {
-    EnvelopeEncoder encoder;
+    cbor::EnvelopeEncoder encoder;
     encoder.EncodeStart(bytes);
-    bytes->push_back(EncodeIndefiniteLengthMapStart());
+    bytes->push_back(cbor::EncodeIndefiniteLengthMapStart());
     for (size_t i = 0; i < m_order.size(); ++i) {
         const String& key = m_order[i];
         Dictionary::const_iterator value = m_data.find(key);
@@ -593,7 +593,7 @@
         EncodeString(key, bytes);
         value->second->writeBinary(bytes);
     }
-    bytes->push_back(EncodeStop());
+    bytes->push_back(cbor::EncodeStop());
     encoder.EncodeStop(bytes);
 }
 
@@ -632,13 +632,13 @@
 }
 
 void ListValue::writeBinary(std::vector<uint8_t>* bytes) const {
-    EnvelopeEncoder encoder;
+    cbor::EnvelopeEncoder encoder;
     encoder.EncodeStart(bytes);
-    bytes->push_back(EncodeIndefiniteLengthArrayStart());
+    bytes->push_back(cbor::EncodeIndefiniteLengthArrayStart());
     for (size_t i = 0; i < m_data.size(); ++i) {
         m_data[i]->writeBinary(bytes);
     }
-    bytes->push_back(EncodeStop());
+    bytes->push_back(cbor::EncodeStop());
     encoder.EncodeStop(bytes);
 }
 
diff --git a/third_party/inspector_protocol/lib/base_string_adapter_cc.template b/third_party/inspector_protocol/lib/base_string_adapter_cc.template
index 24855d4..94bcd88 100644
--- a/third_party/inspector_protocol/lib/base_string_adapter_cc.template
+++ b/third_party/inspector_protocol/lib/base_string_adapter_cc.template
@@ -256,34 +256,34 @@
   if (in.size() < 1 + 1 + 4 + 1 + 1)
     return false;
   const uint8_t* envelope = reinterpret_cast<const uint8_t*>(in.data());
-  if (cbor::kInitialByteForEnvelope != envelope[0])
+  if (cbor::InitialByteForEnvelope() != envelope[0])
     return false;
-  if (cbor::kInitialByteFor32BitLengthByteString != envelope[1])
+  if (cbor::InitialByteFor32BitLengthByteString() != envelope[1])
     return false;
-  if (cbor::kInitialByteIndefiniteLengthMap != envelope[6])
+  if (cbor::EncodeIndefiniteLengthMapStart() != envelope[6])
     return false;
 
   uint32_t envelope_size = ReadEnvelopeSize(envelope + 2);
   if (envelope_size + 2 + 4 != in.size())
     return false;
-  if (cbor::kStopByte != static_cast<uint8_t>(*in.rbegin()))
+  if (cbor::EncodeStop() != static_cast<uint8_t>(*in.rbegin()))
     return false;
 
   std::vector<uint8_t> encoded_entry;
   encoded_entry.reserve(1 + 4 + key.size() + 1 + 4 + value.size());
   span<uint8_t> key_span(
       reinterpret_cast<const uint8_t*>(key.data()), key.size());
-  EncodeString8(key_span, &encoded_entry);
+  cbor::EncodeString8(key_span, &encoded_entry);
   span<uint8_t> value_span(
       reinterpret_cast<const uint8_t*>(value.data()), value.size());
-  EncodeString8(value_span, &encoded_entry);
+  cbor::EncodeString8(value_span, &encoded_entry);
 
   out->clear();
   out->reserve(in.size() + encoded_entry.size());
   out->append(in.begin(), in.end() - 1);
   out->append(reinterpret_cast<const char*>(encoded_entry.data()),
       encoded_entry.size());
-  out->append(1, static_cast<char>(cbor::kStopByte));
+  out->append(1, static_cast<char>(cbor::EncodeStop()));
   std::size_t new_size = envelope_size + out->size() - in.size();
   if (new_size > static_cast<std::size_t>(
       std::numeric_limits<uint32_t>::max())) {
diff --git a/third_party/inspector_protocol/lib/encoding_cpp.template b/third_party/inspector_protocol/lib/encoding_cpp.template
new file mode 100644
index 0000000..84251d9
--- /dev/null
+++ b/third_party/inspector_protocol/lib/encoding_cpp.template
@@ -0,0 +1,1807 @@
+{# This template is generated by gen_cbor_templates.py. #}
+// Generated by lib/encoding_cpp.template.
+
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+#include <cassert>
+#include <cstring>
+#include <limits>
+#include <stack>
+
+{% for namespace in config.protocol.namespace %}
+namespace {{namespace}} {
+{% endfor %}
+
+// ===== encoding/encoding.cc =====
+
+namespace cbor {
+namespace {
+// Indicates the number of bits the "initial byte" needs to be shifted to the
+// right after applying |kMajorTypeMask| to produce the major type in the
+// lowermost bits.
+static constexpr uint8_t kMajorTypeBitShift = 5u;
+// Mask selecting the low-order 5 bits of the "initial byte", which is where
+// the additional information is encoded.
+static constexpr uint8_t kAdditionalInformationMask = 0x1f;
+// Mask selecting the high-order 3 bits of the "initial byte", which indicates
+// the major type of the encoded value.
+static constexpr uint8_t kMajorTypeMask = 0xe0;
+// Indicates the integer is in the following byte.
+static constexpr uint8_t kAdditionalInformation1Byte = 24u;
+// Indicates the integer is in the next 2 bytes.
+static constexpr uint8_t kAdditionalInformation2Bytes = 25u;
+// Indicates the integer is in the next 4 bytes.
+static constexpr uint8_t kAdditionalInformation4Bytes = 26u;
+// Indicates the integer is in the next 8 bytes.
+static constexpr uint8_t kAdditionalInformation8Bytes = 27u;
+
+// Encodes the initial byte, consisting of the |type| in the first 3 bits
+// followed by 5 bits of |additional_info|.
+constexpr uint8_t EncodeInitialByte(MajorType type, uint8_t additional_info) {
+  return (static_cast<uint8_t>(type) << kMajorTypeBitShift) |
+         (additional_info & kAdditionalInformationMask);
+}
+
+// TAG 24 indicates that what follows is a byte string which is
+// encoded in CBOR format. We use this as a wrapper for
+// maps and arrays, allowing us to skip them, because the
+// byte string carries its size (byte length).
+// https://tools.ietf.org/html/rfc7049#section-2.4.4.1
+static constexpr uint8_t kInitialByteForEnvelope =
+    EncodeInitialByte(MajorType::TAG, 24);
+// The initial byte for a byte string with at most 2^32 bytes
+// of payload. This is used for envelope encoding, even if
+// the byte string is shorter.
+static constexpr uint8_t kInitialByteFor32BitLengthByteString =
+    EncodeInitialByte(MajorType::BYTE_STRING, 26);
+
+// See RFC 7049 Section 2.2.1, indefinite length arrays / maps have additional
+// info = 31.
+static constexpr uint8_t kInitialByteIndefiniteLengthArray =
+    EncodeInitialByte(MajorType::ARRAY, 31);
+static constexpr uint8_t kInitialByteIndefiniteLengthMap =
+    EncodeInitialByte(MajorType::MAP, 31);
+// See RFC 7049 Section 2.3, Table 1; this is used for finishing indefinite
+// length maps / arrays.
+static constexpr uint8_t kStopByte =
+    EncodeInitialByte(MajorType::SIMPLE_VALUE, 31);
+
+// See RFC 7049 Section 2.3, Table 2.
+static constexpr uint8_t kEncodedTrue =
+    EncodeInitialByte(MajorType::SIMPLE_VALUE, 21);
+static constexpr uint8_t kEncodedFalse =
+    EncodeInitialByte(MajorType::SIMPLE_VALUE, 20);
+static constexpr uint8_t kEncodedNull =
+    EncodeInitialByte(MajorType::SIMPLE_VALUE, 22);
+static constexpr uint8_t kInitialByteForDouble =
+    EncodeInitialByte(MajorType::SIMPLE_VALUE, 27);
+
+// See RFC 7049 Table 3 and Section 2.4.4.2. This is used as a prefix for
+// arbitrary binary data encoded as BYTE_STRING.
+static constexpr uint8_t kExpectedConversionToBase64Tag =
+    EncodeInitialByte(MajorType::TAG, 22);
+
+// Writes the bytes for |v| to |out|, starting with the most significant byte.
+// See also: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
+template <typename T>
+void WriteBytesMostSignificantByteFirst(T v, std::vector<uint8_t>* out) {
+  for (int shift_bytes = sizeof(T) - 1; shift_bytes >= 0; --shift_bytes)
+    out->push_back(0xff & (v >> (shift_bytes * 8)));
+}
+
+// Extracts sizeof(T) bytes from |in| to extract a value of type T
+// (e.g. uint64_t, uint32_t, ...), most significant byte first.
+// See also: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
+template <typename T>
+T ReadBytesMostSignificantByteFirst(span<uint8_t> in) {
+  assert(static_cast<std::size_t>(in.size()) >= sizeof(T));
+  T result = 0;
+  for (std::size_t shift_bytes = 0; shift_bytes < sizeof(T); ++shift_bytes)
+    result |= T(in[sizeof(T) - 1 - shift_bytes]) << (shift_bytes * 8);
+  return result;
+}
+}  // namespace
+
+namespace internals {
+// Reads the start of a token with definitive size from |bytes|.
+// |type| is the major type as specified in RFC 7049 Section 2.1.
+// |value| is the payload (e.g. for MajorType::UNSIGNED) or is the size
+// (e.g. for BYTE_STRING).
+// If successful, returns the number of bytes read. Otherwise returns -1.
+int8_t ReadTokenStart(span<uint8_t> bytes, MajorType* type, uint64_t* value) {
+  if (bytes.empty())
+    return -1;
+  uint8_t initial_byte = bytes[0];
+  *type = MajorType((initial_byte & kMajorTypeMask) >> kMajorTypeBitShift);
+
+  uint8_t additional_information = initial_byte & kAdditionalInformationMask;
+  if (additional_information < 24) {
+    // Values 0-23 are encoded directly into the additional info of the
+    // initial byte.
+    *value = additional_information;
+    return 1;
+  }
+  if (additional_information == kAdditionalInformation1Byte) {
+    // Values 24-255 are encoded with one initial byte, followed by the value.
+    if (bytes.size() < 2)
+      return -1;
+    *value = ReadBytesMostSignificantByteFirst<uint8_t>(bytes.subspan(1));
+    return 2;
+  }
+  if (additional_information == kAdditionalInformation2Bytes) {
+    // Values 256-65535: 1 initial byte + 2 bytes payload.
+    if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint16_t))
+      return -1;
+    *value = ReadBytesMostSignificantByteFirst<uint16_t>(bytes.subspan(1));
+    return 3;
+  }
+  if (additional_information == kAdditionalInformation4Bytes) {
+    // 32 bit uint: 1 initial byte + 4 bytes payload.
+    if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint32_t))
+      return -1;
+    *value = ReadBytesMostSignificantByteFirst<uint32_t>(bytes.subspan(1));
+    return 5;
+  }
+  if (additional_information == kAdditionalInformation8Bytes) {
+    // 64 bit uint: 1 initial byte + 8 bytes payload.
+    if (static_cast<std::size_t>(bytes.size()) < 1 + sizeof(uint64_t))
+      return -1;
+    *value = ReadBytesMostSignificantByteFirst<uint64_t>(bytes.subspan(1));
+    return 9;
+  }
+  return -1;
+}
+
+// Writes the start of a token with |type|. The |value| may indicate the size,
+// or it may be the payload if the value is an unsigned integer.
+void WriteTokenStart(MajorType type,
+                     uint64_t value,
+                     std::vector<uint8_t>* encoded) {
+  if (value < 24) {
+    // Values 0-23 are encoded directly into the additional info of the
+    // initial byte.
+    encoded->push_back(EncodeInitialByte(type, /*additional_info=*/value));
+    return;
+  }
+  if (value <= std::numeric_limits<uint8_t>::max()) {
+    // Values 24-255 are encoded with one initial byte, followed by the value.
+    encoded->push_back(EncodeInitialByte(type, kAdditionalInformation1Byte));
+    encoded->push_back(value);
+    return;
+  }
+  if (value <= std::numeric_limits<uint16_t>::max()) {
+    // Values 256-65535: 1 initial byte + 2 bytes payload.
+    encoded->push_back(EncodeInitialByte(type, kAdditionalInformation2Bytes));
+    WriteBytesMostSignificantByteFirst<uint16_t>(value, encoded);
+    return;
+  }
+  if (value <= std::numeric_limits<uint32_t>::max()) {
+    // 32 bit uint: 1 initial byte + 4 bytes payload.
+    encoded->push_back(EncodeInitialByte(type, kAdditionalInformation4Bytes));
+    WriteBytesMostSignificantByteFirst<uint32_t>(static_cast<uint32_t>(value),
+                                                 encoded);
+    return;
+  }
+  // 64 bit uint: 1 initial byte + 8 bytes payload.
+  encoded->push_back(EncodeInitialByte(type, kAdditionalInformation8Bytes));
+  WriteBytesMostSignificantByteFirst<uint64_t>(value, encoded);
+}
+}  // namespace internals
+
+// =============================================================================
+// Detecting CBOR content
+// =============================================================================
+
+uint8_t InitialByteForEnvelope() {
+  return kInitialByteForEnvelope;
+}
+uint8_t InitialByteFor32BitLengthByteString() {
+  return kInitialByteFor32BitLengthByteString;
+}
+bool IsCBORMessage(span<uint8_t> msg) {
+  return msg.size() >= 6 && msg[0] == InitialByteForEnvelope() &&
+         msg[1] == InitialByteFor32BitLengthByteString();
+}
+
+// =============================================================================
+// Encoding invidiual CBOR items
+// =============================================================================
+
+uint8_t EncodeTrue() {
+  return kEncodedTrue;
+}
+uint8_t EncodeFalse() {
+  return kEncodedFalse;
+}
+uint8_t EncodeNull() {
+  return kEncodedNull;
+}
+
+uint8_t EncodeIndefiniteLengthArrayStart() {
+  return kInitialByteIndefiniteLengthArray;
+}
+
+uint8_t EncodeIndefiniteLengthMapStart() {
+  return kInitialByteIndefiniteLengthMap;
+}
+
+uint8_t EncodeStop() {
+  return kStopByte;
+}
+
+void EncodeInt32(int32_t value, std::vector<uint8_t>* out) {
+  if (value >= 0) {
+    internals::WriteTokenStart(MajorType::UNSIGNED, value, out);
+  } else {
+    uint64_t representation = static_cast<uint64_t>(-(value + 1));
+    internals::WriteTokenStart(MajorType::NEGATIVE, representation, out);
+  }
+}
+
+void EncodeString16(span<uint16_t> in, std::vector<uint8_t>* out) {
+  uint64_t byte_length = static_cast<uint64_t>(in.size_bytes());
+  internals::WriteTokenStart(MajorType::BYTE_STRING, byte_length, out);
+  // When emitting UTF16 characters, we always write the least significant byte
+  // first; this is because it's the native representation for X86.
+  // TODO(johannes): Implement a more efficient thing here later, e.g.
+  // casting *iff* the machine has this byte order.
+  // The wire format for UTF16 chars will probably remain the same
+  // (least significant byte first) since this way we can have
+  // golden files, unittests, etc. that port easily and universally.
+  // See also:
+  // https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
+  for (const uint16_t two_bytes : in) {
+    out->push_back(two_bytes);
+    out->push_back(two_bytes >> 8);
+  }
+}
+
+void EncodeString8(span<uint8_t> in, std::vector<uint8_t>* out) {
+  internals::WriteTokenStart(MajorType::STRING,
+                             static_cast<uint64_t>(in.size_bytes()), out);
+  out->insert(out->end(), in.begin(), in.end());
+}
+
+void EncodeFromLatin1(span<uint8_t> latin1, std::vector<uint8_t>* out) {
+  for (std::ptrdiff_t ii = 0; ii < latin1.size(); ++ii) {
+    if (latin1[ii] <= 127)
+      continue;
+    // If there's at least one non-ASCII char, convert to UTF8.
+    std::vector<uint8_t> utf8(latin1.begin(), latin1.begin() + ii);
+    for (; ii < latin1.size(); ++ii) {
+      if (latin1[ii] <= 127) {
+        utf8.push_back(latin1[ii]);
+      } else {
+        // 0xC0 means it's a UTF8 sequence with 2 bytes.
+        utf8.push_back((latin1[ii] >> 6) | 0xc0);
+        utf8.push_back((latin1[ii] | 0x80) & 0xbf);
+      }
+    }
+    EncodeString8(SpanFromVector(utf8), out);
+    return;
+  }
+  EncodeString8(latin1, out);
+}
+
+void EncodeFromUTF16(span<uint16_t> utf16, std::vector<uint8_t>* out) {
+  // If there's at least one non-ASCII char, encode as STRING16 (UTF16).
+  for (uint16_t ch : utf16) {
+    if (ch <= 127)
+      continue;
+    EncodeString16(utf16, out);
+    return;
+  }
+  // It's all US-ASCII, strip out every second byte and encode as UTF8.
+  internals::WriteTokenStart(MajorType::STRING,
+                             static_cast<uint64_t>(utf16.size()), out);
+  out->insert(out->end(), utf16.begin(), utf16.end());
+}
+
+void EncodeBinary(span<uint8_t> in, std::vector<uint8_t>* out) {
+  out->push_back(kExpectedConversionToBase64Tag);
+  uint64_t byte_length = static_cast<uint64_t>(in.size_bytes());
+  internals::WriteTokenStart(MajorType::BYTE_STRING, byte_length, out);
+  out->insert(out->end(), in.begin(), in.end());
+}
+
+// A double is encoded with a specific initial byte
+// (kInitialByteForDouble) plus the 64 bits of payload for its value.
+constexpr std::ptrdiff_t kEncodedDoubleSize = 1 + sizeof(uint64_t);
+
+// An envelope is encoded with a specific initial byte
+// (kInitialByteForEnvelope), plus the start byte for a BYTE_STRING with a 32
+// bit wide length, plus a 32 bit length for that string.
+constexpr std::ptrdiff_t kEncodedEnvelopeHeaderSize = 1 + 1 + sizeof(uint32_t);
+
+void EncodeDouble(double value, std::vector<uint8_t>* out) {
+  // The additional_info=27 indicates 64 bits for the double follow.
+  // See RFC 7049 Section 2.3, Table 1.
+  out->push_back(kInitialByteForDouble);
+  union {
+    double from_double;
+    uint64_t to_uint64;
+  } reinterpret;
+  reinterpret.from_double = value;
+  WriteBytesMostSignificantByteFirst<uint64_t>(reinterpret.to_uint64, out);
+}
+
+// =============================================================================
+// cbor::EnvelopeEncoder - for wrapping submessages
+// =============================================================================
+
+void EnvelopeEncoder::EncodeStart(std::vector<uint8_t>* out) {
+  assert(byte_size_pos_ == 0);
+  out->push_back(kInitialByteForEnvelope);
+  out->push_back(kInitialByteFor32BitLengthByteString);
+  byte_size_pos_ = out->size();
+  out->resize(out->size() + sizeof(uint32_t));
+}
+
+bool EnvelopeEncoder::EncodeStop(std::vector<uint8_t>* out) {
+  assert(byte_size_pos_ != 0);
+  // The byte size is the size of the payload, that is, all the
+  // bytes that were written past the byte size position itself.
+  uint64_t byte_size = out->size() - (byte_size_pos_ + sizeof(uint32_t));
+  // We store exactly 4 bytes, so at most INT32MAX, with most significant
+  // byte first.
+  if (byte_size > std::numeric_limits<uint32_t>::max())
+    return false;
+  for (int shift_bytes = sizeof(uint32_t) - 1; shift_bytes >= 0;
+       --shift_bytes) {
+    (*out)[byte_size_pos_++] = 0xff & (byte_size >> (shift_bytes * 8));
+  }
+  return true;
+}
+
+// =============================================================================
+// cbor::NewCBOREncoder - for encoding from a streaming parser
+// =============================================================================
+
+namespace {
+class CBOREncoder : public StreamingParserHandler {
+ public:
+  CBOREncoder(std::vector<uint8_t>* out, Status* status)
+      : out_(out), status_(status) {
+    *status_ = Status();
+  }
+
+  void HandleMapBegin() override {
+    envelopes_.emplace_back();
+    envelopes_.back().EncodeStart(out_);
+    out_->push_back(kInitialByteIndefiniteLengthMap);
+  }
+
+  void HandleMapEnd() override {
+    out_->push_back(kStopByte);
+    assert(!envelopes_.empty());
+    envelopes_.back().EncodeStop(out_);
+    envelopes_.pop_back();
+  }
+
+  void HandleArrayBegin() override {
+    envelopes_.emplace_back();
+    envelopes_.back().EncodeStart(out_);
+    out_->push_back(kInitialByteIndefiniteLengthArray);
+  }
+
+  void HandleArrayEnd() override {
+    out_->push_back(kStopByte);
+    assert(!envelopes_.empty());
+    envelopes_.back().EncodeStop(out_);
+    envelopes_.pop_back();
+  }
+
+  void HandleString8(span<uint8_t> chars) override {
+    EncodeString8(chars, out_);
+  }
+
+  void HandleString16(span<uint16_t> chars) override {
+    EncodeFromUTF16(chars, out_);
+  }
+
+  void HandleBinary(span<uint8_t> bytes) override { EncodeBinary(bytes, out_); }
+
+  void HandleDouble(double value) override { EncodeDouble(value, out_); }
+
+  void HandleInt32(int32_t value) override { EncodeInt32(value, out_); }
+
+  void HandleBool(bool value) override {
+    // See RFC 7049 Section 2.3, Table 2.
+    out_->push_back(value ? kEncodedTrue : kEncodedFalse);
+  }
+
+  void HandleNull() override {
+    // See RFC 7049 Section 2.3, Table 2.
+    out_->push_back(kEncodedNull);
+  }
+
+  void HandleError(Status error) override {
+    assert(!error.ok());
+    *status_ = error;
+    out_->clear();
+  }
+
+ private:
+  std::vector<uint8_t>* out_;
+  std::vector<EnvelopeEncoder> envelopes_;
+  Status* status_;
+};
+}  // namespace
+
+std::unique_ptr<StreamingParserHandler> NewCBOREncoder(
+    std::vector<uint8_t>* out,
+    Status* status) {
+  return std::unique_ptr<StreamingParserHandler>(new CBOREncoder(out, status));
+}
+
+// =============================================================================
+// cbor::CBORTokenizer - for parsing individual CBOR items
+// =============================================================================
+
+CBORTokenizer::CBORTokenizer(span<uint8_t> bytes) : bytes_(bytes) {
+  ReadNextToken(/*enter_envelope=*/false);
+}
+CBORTokenizer::~CBORTokenizer() {}
+
+CBORTokenTag CBORTokenizer::TokenTag() const {
+  return token_tag_;
+}
+
+void CBORTokenizer::Next() {
+  if (token_tag_ == CBORTokenTag::ERROR_VALUE ||
+      token_tag_ == CBORTokenTag::DONE)
+    return;
+  ReadNextToken(/*enter_envelope=*/false);
+}
+
+void CBORTokenizer::EnterEnvelope() {
+  assert(token_tag_ == CBORTokenTag::ENVELOPE);
+  ReadNextToken(/*enter_envelope=*/true);
+}
+
+Status CBORTokenizer::Status() const {
+  return status_;
+}
+
+int32_t CBORTokenizer::GetInt32() const {
+  assert(token_tag_ == CBORTokenTag::INT32);
+  // The range checks happen in ::ReadNextToken().
+  return static_cast<uint32_t>(
+      token_start_type_ == MajorType::UNSIGNED
+          ? token_start_internal_value_
+          : -static_cast<int64_t>(token_start_internal_value_) - 1);
+}
+
+double CBORTokenizer::GetDouble() const {
+  assert(token_tag_ == CBORTokenTag::DOUBLE);
+  union {
+    uint64_t from_uint64;
+    double to_double;
+  } reinterpret;
+  reinterpret.from_uint64 = ReadBytesMostSignificantByteFirst<uint64_t>(
+      bytes_.subspan(status_.pos + 1));
+  return reinterpret.to_double;
+}
+
+span<uint8_t> CBORTokenizer::GetString8() const {
+  assert(token_tag_ == CBORTokenTag::STRING8);
+  auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
+  return bytes_.subspan(status_.pos + (token_byte_length_ - length), length);
+}
+
+span<uint8_t> CBORTokenizer::GetString16WireRep() const {
+  assert(token_tag_ == CBORTokenTag::STRING16);
+  auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
+  return bytes_.subspan(status_.pos + (token_byte_length_ - length), length);
+}
+
+span<uint8_t> CBORTokenizer::GetBinary() const {
+  assert(token_tag_ == CBORTokenTag::BINARY);
+  auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
+  return bytes_.subspan(status_.pos + (token_byte_length_ - length), length);
+}
+
+span<uint8_t> CBORTokenizer::GetEnvelopeContents() const {
+  assert(token_tag_ == CBORTokenTag::ENVELOPE);
+  auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
+  return bytes_.subspan(status_.pos + kEncodedEnvelopeHeaderSize, length);
+}
+
+void CBORTokenizer::ReadNextToken(bool enter_envelope) {
+  if (enter_envelope) {
+    status_.pos += kEncodedEnvelopeHeaderSize;
+  } else {
+    status_.pos =
+        status_.pos == Status::npos() ? 0 : status_.pos + token_byte_length_;
+  }
+  status_.error = Error::OK;
+  if (status_.pos >= bytes_.size()) {
+    token_tag_ = CBORTokenTag::DONE;
+    return;
+  }
+  switch (bytes_[status_.pos]) {
+    case kStopByte:
+      SetToken(CBORTokenTag::STOP, 1);
+      return;
+    case kInitialByteIndefiniteLengthMap:
+      SetToken(CBORTokenTag::MAP_START, 1);
+      return;
+    case kInitialByteIndefiniteLengthArray:
+      SetToken(CBORTokenTag::ARRAY_START, 1);
+      return;
+    case kEncodedTrue:
+      SetToken(CBORTokenTag::TRUE_VALUE, 1);
+      return;
+    case kEncodedFalse:
+      SetToken(CBORTokenTag::FALSE_VALUE, 1);
+      return;
+    case kEncodedNull:
+      SetToken(CBORTokenTag::NULL_VALUE, 1);
+      return;
+    case kExpectedConversionToBase64Tag: {  // BINARY
+      int8_t bytes_read = internals::ReadTokenStart(
+          bytes_.subspan(status_.pos + 1), &token_start_type_,
+          &token_start_internal_value_);
+      int64_t token_byte_length = 1 + bytes_read + token_start_internal_value_;
+      if (-1 == bytes_read || token_start_type_ != MajorType::BYTE_STRING ||
+          status_.pos + token_byte_length > bytes_.size()) {
+        SetError(Error::CBOR_INVALID_BINARY);
+        return;
+      }
+      SetToken(CBORTokenTag::BINARY,
+               static_cast<std::ptrdiff_t>(token_byte_length));
+      return;
+    }
+    case kInitialByteForDouble: {  // DOUBLE
+      if (status_.pos + kEncodedDoubleSize > bytes_.size()) {
+        SetError(Error::CBOR_INVALID_DOUBLE);
+        return;
+      }
+      SetToken(CBORTokenTag::DOUBLE, kEncodedDoubleSize);
+      return;
+    }
+    case kInitialByteForEnvelope: {  // ENVELOPE
+      if (status_.pos + kEncodedEnvelopeHeaderSize > bytes_.size()) {
+        SetError(Error::CBOR_INVALID_ENVELOPE);
+        return;
+      }
+      // The envelope must be a byte string with 32 bit length.
+      if (bytes_[status_.pos + 1] != kInitialByteFor32BitLengthByteString) {
+        SetError(Error::CBOR_INVALID_ENVELOPE);
+        return;
+      }
+      // Read the length of the byte string.
+      token_start_internal_value_ = ReadBytesMostSignificantByteFirst<uint32_t>(
+          bytes_.subspan(status_.pos + 2));
+      // Make sure the payload is contained within the message.
+      if (token_start_internal_value_ + kEncodedEnvelopeHeaderSize +
+              status_.pos >
+          static_cast<std::size_t>(bytes_.size())) {
+        SetError(Error::CBOR_INVALID_ENVELOPE);
+        return;
+      }
+      auto length = static_cast<std::ptrdiff_t>(token_start_internal_value_);
+      SetToken(CBORTokenTag::ENVELOPE, kEncodedEnvelopeHeaderSize + length);
+      return;
+    }
+    default: {
+      span<uint8_t> remainder =
+          bytes_.subspan(status_.pos, bytes_.size() - status_.pos);
+      assert(!remainder.empty());
+      int8_t token_start_length = internals::ReadTokenStart(
+          remainder, &token_start_type_, &token_start_internal_value_);
+      bool success = token_start_length != -1;
+      switch (token_start_type_) {
+        case MajorType::UNSIGNED:  // INT32.
+          if (!success || std::numeric_limits<int32_t>::max() <
+                              token_start_internal_value_) {
+            SetError(Error::CBOR_INVALID_INT32);
+            return;
+          }
+          SetToken(CBORTokenTag::INT32, token_start_length);
+          return;
+        case MajorType::NEGATIVE:  // INT32.
+          if (!success ||
+              std::numeric_limits<int32_t>::min() >
+                  -static_cast<int64_t>(token_start_internal_value_) - 1) {
+            SetError(Error::CBOR_INVALID_INT32);
+            return;
+          }
+          SetToken(CBORTokenTag::INT32, token_start_length);
+          return;
+        case MajorType::STRING: {  // STRING8.
+          if (!success || remainder.size() < static_cast<int64_t>(
+                                                 token_start_internal_value_)) {
+            SetError(Error::CBOR_INVALID_STRING8);
+            return;
+          }
+          auto length =
+              static_cast<std::ptrdiff_t>(token_start_internal_value_);
+          SetToken(CBORTokenTag::STRING8, token_start_length + length);
+          return;
+        }
+        case MajorType::BYTE_STRING: {  // STRING16.
+          if (!success ||
+              remainder.size() <
+                  static_cast<int64_t>(token_start_internal_value_) ||
+              // Must be divisible by 2 since UTF16 is 2 bytes per character.
+              token_start_internal_value_ & 1) {
+            SetError(Error::CBOR_INVALID_STRING16);
+            return;
+          }
+          auto length =
+              static_cast<std::ptrdiff_t>(token_start_internal_value_);
+          SetToken(CBORTokenTag::STRING16, token_start_length + length);
+          return;
+        }
+        case MajorType::ARRAY:
+        case MajorType::MAP:
+        case MajorType::TAG:
+        case MajorType::SIMPLE_VALUE:
+          SetError(Error::CBOR_UNSUPPORTED_VALUE);
+          return;
+      }
+    }
+  }
+}
+
+void CBORTokenizer::SetToken(CBORTokenTag token_tag,
+                             std::ptrdiff_t token_byte_length) {
+  token_tag_ = token_tag;
+  token_byte_length_ = token_byte_length;
+}
+
+void CBORTokenizer::SetError(Error error) {
+  token_tag_ = CBORTokenTag::ERROR_VALUE;
+  status_.error = error;
+}
+
+// =============================================================================
+// cbor::ParseCBOR - for receiving streaming parser events for CBOR messages
+// =============================================================================
+
+namespace {
+// When parsing CBOR, we limit recursion depth for objects and arrays
+// to this constant.
+static constexpr int kStackLimit = 1000;
+
+// Below are three parsing routines for CBOR, which cover enough
+// to roundtrip JSON messages.
+bool ParseMap(int32_t stack_depth,
+              CBORTokenizer* tokenizer,
+              StreamingParserHandler* out);
+bool ParseArray(int32_t stack_depth,
+                CBORTokenizer* tokenizer,
+                StreamingParserHandler* out);
+bool ParseValue(int32_t stack_depth,
+                CBORTokenizer* tokenizer,
+                StreamingParserHandler* out);
+
+void ParseUTF16String(CBORTokenizer* tokenizer, StreamingParserHandler* out) {
+  std::vector<uint16_t> value;
+  span<uint8_t> rep = tokenizer->GetString16WireRep();
+  for (std::ptrdiff_t ii = 0; ii < rep.size(); ii += 2)
+    value.push_back((rep[ii + 1] << 8) | rep[ii]);
+  out->HandleString16(span<uint16_t>(value.data(), value.size()));
+  tokenizer->Next();
+}
+
+bool ParseUTF8String(CBORTokenizer* tokenizer, StreamingParserHandler* out) {
+  assert(tokenizer->TokenTag() == CBORTokenTag::STRING8);
+  out->HandleString8(tokenizer->GetString8());
+  tokenizer->Next();
+  return true;
+}
+
+bool ParseValue(int32_t stack_depth,
+                CBORTokenizer* tokenizer,
+                StreamingParserHandler* out) {
+  if (stack_depth > kStackLimit) {
+    out->HandleError(
+        Status{Error::CBOR_STACK_LIMIT_EXCEEDED, tokenizer->Status().pos});
+    return false;
+  }
+  // Skip past the envelope to get to what's inside.
+  if (tokenizer->TokenTag() == CBORTokenTag::ENVELOPE)
+    tokenizer->EnterEnvelope();
+  switch (tokenizer->TokenTag()) {
+    case CBORTokenTag::ERROR_VALUE:
+      out->HandleError(tokenizer->Status());
+      return false;
+    case CBORTokenTag::DONE:
+      out->HandleError(Status{Error::CBOR_UNEXPECTED_EOF_EXPECTED_VALUE,
+                              tokenizer->Status().pos});
+      return false;
+    case CBORTokenTag::TRUE_VALUE:
+      out->HandleBool(true);
+      tokenizer->Next();
+      return true;
+    case CBORTokenTag::FALSE_VALUE:
+      out->HandleBool(false);
+      tokenizer->Next();
+      return true;
+    case CBORTokenTag::NULL_VALUE:
+      out->HandleNull();
+      tokenizer->Next();
+      return true;
+    case CBORTokenTag::INT32:
+      out->HandleInt32(tokenizer->GetInt32());
+      tokenizer->Next();
+      return true;
+    case CBORTokenTag::DOUBLE:
+      out->HandleDouble(tokenizer->GetDouble());
+      tokenizer->Next();
+      return true;
+    case CBORTokenTag::STRING8:
+      return ParseUTF8String(tokenizer, out);
+    case CBORTokenTag::STRING16:
+      ParseUTF16String(tokenizer, out);
+      return true;
+    case CBORTokenTag::BINARY: {
+      out->HandleBinary(tokenizer->GetBinary());
+      tokenizer->Next();
+      return true;
+    }
+    case CBORTokenTag::MAP_START:
+      return ParseMap(stack_depth + 1, tokenizer, out);
+    case CBORTokenTag::ARRAY_START:
+      return ParseArray(stack_depth + 1, tokenizer, out);
+    default:
+      out->HandleError(
+          Status{Error::CBOR_UNSUPPORTED_VALUE, tokenizer->Status().pos});
+      return false;
+  }
+}
+
+// |bytes| must start with the indefinite length array byte, so basically,
+// ParseArray may only be called after an indefinite length array has been
+// detected.
+bool ParseArray(int32_t stack_depth,
+                CBORTokenizer* tokenizer,
+                StreamingParserHandler* out) {
+  assert(tokenizer->TokenTag() == CBORTokenTag::ARRAY_START);
+  tokenizer->Next();
+  out->HandleArrayBegin();
+  while (tokenizer->TokenTag() != CBORTokenTag::STOP) {
+    if (tokenizer->TokenTag() == CBORTokenTag::DONE) {
+      out->HandleError(
+          Status{Error::CBOR_UNEXPECTED_EOF_IN_ARRAY, tokenizer->Status().pos});
+      return false;
+    }
+    if (tokenizer->TokenTag() == CBORTokenTag::ERROR_VALUE) {
+      out->HandleError(tokenizer->Status());
+      return false;
+    }
+    // Parse value.
+    if (!ParseValue(stack_depth, tokenizer, out))
+      return false;
+  }
+  out->HandleArrayEnd();
+  tokenizer->Next();
+  return true;
+}
+
+// |bytes| must start with the indefinite length array byte, so basically,
+// ParseArray may only be called after an indefinite length array has been
+// detected.
+bool ParseMap(int32_t stack_depth,
+              CBORTokenizer* tokenizer,
+              StreamingParserHandler* out) {
+  assert(tokenizer->TokenTag() == CBORTokenTag::MAP_START);
+  out->HandleMapBegin();
+  tokenizer->Next();
+  while (tokenizer->TokenTag() != CBORTokenTag::STOP) {
+    if (tokenizer->TokenTag() == CBORTokenTag::DONE) {
+      out->HandleError(
+          Status{Error::CBOR_UNEXPECTED_EOF_IN_MAP, tokenizer->Status().pos});
+      return false;
+    }
+    if (tokenizer->TokenTag() == CBORTokenTag::ERROR_VALUE) {
+      out->HandleError(tokenizer->Status());
+      return false;
+    }
+    // Parse key.
+    if (tokenizer->TokenTag() == CBORTokenTag::STRING8) {
+      if (!ParseUTF8String(tokenizer, out))
+        return false;
+    } else if (tokenizer->TokenTag() == CBORTokenTag::STRING16) {
+      ParseUTF16String(tokenizer, out);
+    } else {
+      out->HandleError(
+          Status{Error::CBOR_INVALID_MAP_KEY, tokenizer->Status().pos});
+      return false;
+    }
+    // Parse value.
+    if (!ParseValue(stack_depth, tokenizer, out))
+      return false;
+  }
+  out->HandleMapEnd();
+  tokenizer->Next();
+  return true;
+}
+}  // namespace
+
+void ParseCBOR(span<uint8_t> bytes, StreamingParserHandler* out) {
+  if (bytes.empty()) {
+    out->HandleError(Status{Error::CBOR_NO_INPUT, 0});
+    return;
+  }
+  if (bytes[0] != kInitialByteForEnvelope) {
+    out->HandleError(Status{Error::CBOR_INVALID_START_BYTE, 0});
+    return;
+  }
+  CBORTokenizer tokenizer(bytes);
+  if (tokenizer.TokenTag() == CBORTokenTag::ERROR_VALUE) {
+    out->HandleError(tokenizer.Status());
+    return;
+  }
+  // We checked for the envelope start byte above, so the tokenizer
+  // must agree here, since it's not an error.
+  assert(tokenizer.TokenTag() == CBORTokenTag::ENVELOPE);
+  tokenizer.EnterEnvelope();
+  if (tokenizer.TokenTag() != CBORTokenTag::MAP_START) {
+    out->HandleError(
+        Status{Error::CBOR_MAP_START_EXPECTED, tokenizer.Status().pos});
+    return;
+  }
+  if (!ParseMap(/*stack_depth=*/1, &tokenizer, out))
+    return;
+  if (tokenizer.TokenTag() == CBORTokenTag::DONE)
+    return;
+  if (tokenizer.TokenTag() == CBORTokenTag::ERROR_VALUE) {
+    out->HandleError(tokenizer.Status());
+    return;
+  }
+  out->HandleError(Status{Error::CBOR_TRAILING_JUNK, tokenizer.Status().pos});
+}
+}  // namespace cbor
+
+namespace json {
+
+// =============================================================================
+// json::NewJSONEncoder - for encoding streaming parser events as JSON
+// =============================================================================
+
+namespace {
+// Prints |value| to |out| with 4 hex digits, most significant chunk first.
+void PrintHex(uint16_t value, std::string* out) {
+  for (int ii = 3; ii >= 0; --ii) {
+    int four_bits = 0xf & (value >> (4 * ii));
+    out->append(1, four_bits + ((four_bits <= 9) ? '0' : ('a' - 10)));
+  }
+}
+
+// In the writer below, we maintain a stack of State instances.
+// It is just enough to emit the appropriate delimiters and brackets
+// in JSON.
+enum class Container {
+  // Used for the top-level, initial state.
+  NONE,
+  // Inside a JSON object.
+  MAP,
+  // Inside a JSON array.
+  ARRAY
+};
+class State {
+ public:
+  explicit State(Container container) : container_(container) {}
+  void StartElement(std::string* out) {
+    assert(container_ != Container::NONE || size_ == 0);
+    if (size_ != 0) {
+      char delim = (!(size_ & 1) || container_ == Container::ARRAY) ? ',' : ':';
+      out->append(1, delim);
+    }
+    ++size_;
+  }
+  Container container() const { return container_; }
+
+ private:
+  Container container_ = Container::NONE;
+  int size_ = 0;
+};
+
+constexpr char kBase64Table[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "abcdefghijklmnopqrstuvwxyz0123456789+/";
+
+void Base64Encode(const span<uint8_t>& in, std::string* out) {
+  // The following three cases are based on the tables in the example
+  // section in https://en.wikipedia.org/wiki/Base64. We process three
+  // input bytes at a time, emitting 4 output bytes at a time.
+  std::ptrdiff_t ii = 0;
+
+  // While possible, process three input bytes.
+  for (; ii + 3 <= in.size(); ii += 3) {
+    uint32_t twentyfour_bits = (in[ii] << 16) | (in[ii + 1] << 8) | in[ii + 2];
+    out->push_back(kBase64Table[(twentyfour_bits >> 18)]);
+    out->push_back(kBase64Table[(twentyfour_bits >> 12) & 0x3f]);
+    out->push_back(kBase64Table[(twentyfour_bits >> 6) & 0x3f]);
+    out->push_back(kBase64Table[twentyfour_bits & 0x3f]);
+  }
+  if (ii + 2 <= in.size()) {  // Process two input bytes.
+    uint32_t twentyfour_bits = (in[ii] << 16) | (in[ii + 1] << 8);
+    out->push_back(kBase64Table[(twentyfour_bits >> 18)]);
+    out->push_back(kBase64Table[(twentyfour_bits >> 12) & 0x3f]);
+    out->push_back(kBase64Table[(twentyfour_bits >> 6) & 0x3f]);
+    out->push_back('=');  // Emit padding.
+    return;
+  }
+  if (ii + 1 <= in.size()) {  // Process a single input byte.
+    uint32_t twentyfour_bits = (in[ii] << 16);
+    out->push_back(kBase64Table[(twentyfour_bits >> 18)]);
+    out->push_back(kBase64Table[(twentyfour_bits >> 12) & 0x3f]);
+    out->push_back('=');  // Emit padding.
+    out->push_back('=');  // Emit padding.
+  }
+}
+
+// Implements a handler for JSON parser events to emit a JSON string.
+class JSONEncoder : public StreamingParserHandler {
+ public:
+  JSONEncoder(const Platform* platform, std::string* out, Status* status)
+      : platform_(platform), out_(out), status_(status) {
+    *status_ = Status();
+    state_.emplace(Container::NONE);
+  }
+
+  void HandleMapBegin() override {
+    if (!status_->ok())
+      return;
+    assert(!state_.empty());
+    state_.top().StartElement(out_);
+    state_.emplace(Container::MAP);
+    out_->append("{");
+  }
+
+  void HandleMapEnd() override {
+    if (!status_->ok())
+      return;
+    assert(state_.size() >= 2 && state_.top().container() == Container::MAP);
+    state_.pop();
+    out_->append("}");
+  }
+
+  void HandleArrayBegin() override {
+    if (!status_->ok())
+      return;
+    state_.top().StartElement(out_);
+    state_.emplace(Container::ARRAY);
+    out_->append("[");
+  }
+
+  void HandleArrayEnd() override {
+    if (!status_->ok())
+      return;
+    assert(state_.size() >= 2 && state_.top().container() == Container::ARRAY);
+    state_.pop();
+    out_->append("]");
+  }
+
+  void HandleString16(span<uint16_t> chars) override {
+    if (!status_->ok())
+      return;
+    state_.top().StartElement(out_);
+    out_->append("\"");
+    for (const uint16_t ch : chars) {
+      if (ch == '"') {
+        out_->append("\\\"");
+      } else if (ch == '\\') {
+        out_->append("\\\\");
+      } else if (ch == '\b') {
+        out_->append("\\b");
+      } else if (ch == '\f') {
+        out_->append("\\f");
+      } else if (ch == '\n') {
+        out_->append("\\n");
+      } else if (ch == '\r') {
+        out_->append("\\r");
+      } else if (ch == '\t') {
+        out_->append("\\t");
+      } else if (ch >= 32 && ch <= 126) {
+        out_->append(1, ch);
+      } else {
+        out_->append("\\u");
+        PrintHex(ch, out_);
+      }
+    }
+    out_->append("\"");
+  }
+
+  void HandleString8(span<uint8_t> chars) override {
+    if (!status_->ok())
+      return;
+    state_.top().StartElement(out_);
+    out_->append("\"");
+    for (std::ptrdiff_t ii = 0; ii < chars.size(); ++ii) {
+      uint8_t c = chars[ii];
+      if (c == '"') {
+        out_->append("\\\"");
+      } else if (c == '\\') {
+        out_->append("\\\\");
+      } else if (c == '\b') {
+        out_->append("\\b");
+      } else if (c == '\f') {
+        out_->append("\\f");
+      } else if (c == '\n') {
+        out_->append("\\n");
+      } else if (c == '\r') {
+        out_->append("\\r");
+      } else if (c == '\t') {
+        out_->append("\\t");
+      } else if (c >= 32 && c <= 126) {
+        out_->append(1, c);
+      } else if (c < 32) {
+        out_->append("\\u");
+        PrintHex(static_cast<uint16_t>(c), out_);
+      } else {
+        // Inspect the leading byte to figure out how long the utf8
+        // byte sequence is; while doing this initialize |codepoint|
+        // with the first few bits.
+        // See table in: https://en.wikipedia.org/wiki/UTF-8
+        // byte one is 110x xxxx -> 2 byte utf8 sequence
+        // byte one is 1110 xxxx -> 3 byte utf8 sequence
+        // byte one is 1111 0xxx -> 4 byte utf8 sequence
+        uint32_t codepoint;
+        int num_bytes_left;
+        if ((c & 0xe0) == 0xc0) {  // 2 byte utf8 sequence
+          num_bytes_left = 1;
+          codepoint = c & 0x1f;
+        } else if ((c & 0xf0) == 0xe0) {  // 3 byte utf8 sequence
+          num_bytes_left = 2;
+          codepoint = c & 0x0f;
+        } else if ((c & 0xf8) == 0xf0) {  // 4 byte utf8 sequence
+          codepoint = c & 0x07;
+          num_bytes_left = 3;
+        } else {
+          continue;  // invalid leading byte
+        }
+
+        // If we have enough bytes in our input, decode the remaining ones
+        // belonging to this Unicode character into |codepoint|.
+        if (ii + num_bytes_left > chars.size())
+          continue;
+        while (num_bytes_left > 0) {
+          c = chars[++ii];
+          --num_bytes_left;
+          // Check the next byte is a continuation byte, that is 10xx xxxx.
+          if ((c & 0xc0) != 0x80)
+            continue;
+          codepoint = (codepoint << 6) | (c & 0x3f);
+        }
+
+        // Disallow overlong encodings for ascii characters, as these
+        // would include " and other characters significant to JSON
+        // string termination / control.
+        if (codepoint < 0x7f)
+          continue;
+        // Invalid in UTF8, and can't be represented in UTF16 anyway.
+        if (codepoint > 0x10ffff)
+          continue;
+
+        // So, now we transcode to UTF16,
+        // using the math described at https://en.wikipedia.org/wiki/UTF-16,
+        // for either one or two 16 bit characters.
+        if (codepoint < 0xffff) {
+          out_->append("\\u");
+          PrintHex(static_cast<uint16_t>(codepoint), out_);
+          continue;
+        }
+        codepoint -= 0x10000;
+        // high surrogate
+        out_->append("\\u");
+        PrintHex(static_cast<uint16_t>((codepoint >> 10) + 0xd800), out_);
+        // low surrogate
+        out_->append("\\u");
+        PrintHex(static_cast<uint16_t>((codepoint & 0x3ff) + 0xdc00), out_);
+      }
+    }
+    out_->append("\"");
+  }
+
+  void HandleBinary(span<uint8_t> bytes) override {
+    if (!status_->ok())
+      return;
+    state_.top().StartElement(out_);
+    out_->append("\"");
+    Base64Encode(bytes, out_);
+    out_->append("\"");
+  }
+
+  void HandleDouble(double value) override {
+    if (!status_->ok())
+      return;
+    state_.top().StartElement(out_);
+    std::unique_ptr<char[]> str_value = platform_->DToStr(value);
+
+    // DToStr may fail to emit a 0 before the decimal dot. E.g. this is
+    // the case in base::NumberToString in Chromium (which is based on
+    // dmg_fp). So, much like
+    // https://cs.chromium.org/chromium/src/base/json/json_writer.cc
+    // we probe for this and emit the leading 0 anyway if necessary.
+    const char* chars = str_value.get();
+    if (chars[0] == '.') {
+      out_->append("0");
+    } else if (chars[0] == '-' && chars[1] == '.') {
+      out_->append("-0");
+      ++chars;
+    }
+    out_->append(chars);
+  }
+
+  void HandleInt32(int32_t value) override {
+    if (!status_->ok())
+      return;
+    state_.top().StartElement(out_);
+    out_->append(std::to_string(value));
+  }
+
+  void HandleBool(bool value) override {
+    if (!status_->ok())
+      return;
+    state_.top().StartElement(out_);
+    out_->append(value ? "true" : "false");
+  }
+
+  void HandleNull() override {
+    if (!status_->ok())
+      return;
+    state_.top().StartElement(out_);
+    out_->append("null");
+  }
+
+  void HandleError(Status error) override {
+    assert(!error.ok());
+    *status_ = error;
+    out_->clear();
+  }
+
+ private:
+  const Platform* platform_;
+  std::string* out_;
+  Status* status_;
+  std::stack<State> state_;
+};
+}  // namespace
+
+std::unique_ptr<StreamingParserHandler> NewJSONEncoder(const Platform* platform,
+                                                       std::string* out,
+                                                       Status* status) {
+  return std::unique_ptr<StreamingParserHandler>(
+      new JSONEncoder(platform, out, status));
+}
+
+// =============================================================================
+// json::ParseJSON - for receiving streaming parser events for JSON.
+// =============================================================================
+
+namespace {
+const int kStackLimit = 1000;
+
+enum Token {
+  ObjectBegin,
+  ObjectEnd,
+  ArrayBegin,
+  ArrayEnd,
+  StringLiteral,
+  Number,
+  BoolTrue,
+  BoolFalse,
+  NullToken,
+  ListSeparator,
+  ObjectPairSeparator,
+  InvalidToken,
+  NoInput
+};
+
+const char* const kNullString = "null";
+const char* const kTrueString = "true";
+const char* const kFalseString = "false";
+
+template <typename Char>
+class JsonParser {
+ public:
+  JsonParser(const Platform* platform, StreamingParserHandler* handler)
+      : platform_(platform), handler_(handler) {}
+
+  void Parse(const Char* start, std::size_t length) {
+    start_pos_ = start;
+    const Char* end = start + length;
+    const Char* tokenEnd;
+    ParseValue(start, end, &tokenEnd, 0);
+    if (tokenEnd != end) {
+      HandleError(Error::JSON_PARSER_UNPROCESSED_INPUT_REMAINS, tokenEnd);
+    }
+  }
+
+ private:
+  bool CharsToDouble(const uint16_t* chars,
+                     std::size_t length,
+                     double* result) {
+    std::string buffer;
+    buffer.reserve(length + 1);
+    for (std::size_t ii = 0; ii < length; ++ii) {
+      bool is_ascii = !(chars[ii] & ~0x7F);
+      if (!is_ascii)
+        return false;
+      buffer.push_back(static_cast<char>(chars[ii]));
+    }
+    return platform_->StrToD(buffer.c_str(), result);
+  }
+
+  bool CharsToDouble(const uint8_t* chars, std::size_t length, double* result) {
+    std::string buffer(reinterpret_cast<const char*>(chars), length);
+    return platform_->StrToD(buffer.c_str(), result);
+  }
+
+  static bool ParseConstToken(const Char* start,
+                              const Char* end,
+                              const Char** token_end,
+                              const char* token) {
+    // |token| is \0 terminated, it's one of the constants at top of the file.
+    while (start < end && *token != '\0' && *start++ == *token++) {
+    }
+    if (*token != '\0')
+      return false;
+    *token_end = start;
+    return true;
+  }
+
+  static bool ReadInt(const Char* start,
+                      const Char* end,
+                      const Char** token_end,
+                      bool allow_leading_zeros) {
+    if (start == end)
+      return false;
+    bool has_leading_zero = '0' == *start;
+    int length = 0;
+    while (start < end && '0' <= *start && *start <= '9') {
+      ++start;
+      ++length;
+    }
+    if (!length)
+      return false;
+    if (!allow_leading_zeros && length > 1 && has_leading_zero)
+      return false;
+    *token_end = start;
+    return true;
+  }
+
+  static bool ParseNumberToken(const Char* start,
+                               const Char* end,
+                               const Char** token_end) {
+    // We just grab the number here. We validate the size in DecodeNumber.
+    // According to RFC4627, a valid number is: [minus] int [frac] [exp]
+    if (start == end)
+      return false;
+    Char c = *start;
+    if ('-' == c)
+      ++start;
+
+    if (!ReadInt(start, end, &start, /*allow_leading_zeros=*/false))
+      return false;
+    if (start == end) {
+      *token_end = start;
+      return true;
+    }
+
+    // Optional fraction part
+    c = *start;
+    if ('.' == c) {
+      ++start;
+      if (!ReadInt(start, end, &start, /*allow_leading_zeros=*/true))
+        return false;
+      if (start == end) {
+        *token_end = start;
+        return true;
+      }
+      c = *start;
+    }
+
+    // Optional exponent part
+    if ('e' == c || 'E' == c) {
+      ++start;
+      if (start == end)
+        return false;
+      c = *start;
+      if ('-' == c || '+' == c) {
+        ++start;
+        if (start == end)
+          return false;
+      }
+      if (!ReadInt(start, end, &start, /*allow_leading_zeros=*/true))
+        return false;
+    }
+
+    *token_end = start;
+    return true;
+  }
+
+  static bool ReadHexDigits(const Char* start,
+                            const Char* end,
+                            const Char** token_end,
+                            int digits) {
+    if (end - start < digits)
+      return false;
+    for (int i = 0; i < digits; ++i) {
+      Char c = *start++;
+      if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') ||
+            ('A' <= c && c <= 'F')))
+        return false;
+    }
+    *token_end = start;
+    return true;
+  }
+
+  static bool ParseStringToken(const Char* start,
+                               const Char* end,
+                               const Char** token_end) {
+    while (start < end) {
+      Char c = *start++;
+      if ('\\' == c) {
+        if (start == end)
+          return false;
+        c = *start++;
+        // Make sure the escaped char is valid.
+        switch (c) {
+          case 'x':
+            if (!ReadHexDigits(start, end, &start, 2))
+              return false;
+            break;
+          case 'u':
+            if (!ReadHexDigits(start, end, &start, 4))
+              return false;
+            break;
+          case '\\':
+          case '/':
+          case 'b':
+          case 'f':
+          case 'n':
+          case 'r':
+          case 't':
+          case 'v':
+          case '"':
+            break;
+          default:
+            return false;
+        }
+      } else if ('"' == c) {
+        *token_end = start;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  static bool SkipComment(const Char* start,
+                          const Char* end,
+                          const Char** comment_end) {
+    if (start == end)
+      return false;
+
+    if (*start != '/' || start + 1 >= end)
+      return false;
+    ++start;
+
+    if (*start == '/') {
+      // Single line comment, read to newline.
+      for (++start; start < end; ++start) {
+        if (*start == '\n' || *start == '\r') {
+          *comment_end = start + 1;
+          return true;
+        }
+      }
+      *comment_end = end;
+      // Comment reaches end-of-input, which is fine.
+      return true;
+    }
+
+    if (*start == '*') {
+      Char previous = '\0';
+      // Block comment, read until end marker.
+      for (++start; start < end; previous = *start++) {
+        if (previous == '*' && *start == '/') {
+          *comment_end = start + 1;
+          return true;
+        }
+      }
+      // Block comment must close before end-of-input.
+      return false;
+    }
+
+    return false;
+  }
+
+  static bool IsSpaceOrNewLine(Char c) {
+    // \v = vertial tab; \f = form feed page break.
+    return c == ' ' || c == '\n' || c == '\v' || c == '\f' || c == '\r' ||
+           c == '\t';
+  }
+
+  static void SkipWhitespaceAndComments(const Char* start,
+                                        const Char* end,
+                                        const Char** whitespace_end) {
+    while (start < end) {
+      if (IsSpaceOrNewLine(*start)) {
+        ++start;
+      } else if (*start == '/') {
+        const Char* comment_end;
+        if (!SkipComment(start, end, &comment_end))
+          break;
+        start = comment_end;
+      } else {
+        break;
+      }
+    }
+    *whitespace_end = start;
+  }
+
+  static Token ParseToken(const Char* start,
+                          const Char* end,
+                          const Char** tokenStart,
+                          const Char** token_end) {
+    SkipWhitespaceAndComments(start, end, tokenStart);
+    start = *tokenStart;
+
+    if (start == end)
+      return NoInput;
+
+    switch (*start) {
+      case 'n':
+        if (ParseConstToken(start, end, token_end, kNullString))
+          return NullToken;
+        break;
+      case 't':
+        if (ParseConstToken(start, end, token_end, kTrueString))
+          return BoolTrue;
+        break;
+      case 'f':
+        if (ParseConstToken(start, end, token_end, kFalseString))
+          return BoolFalse;
+        break;
+      case '[':
+        *token_end = start + 1;
+        return ArrayBegin;
+      case ']':
+        *token_end = start + 1;
+        return ArrayEnd;
+      case ',':
+        *token_end = start + 1;
+        return ListSeparator;
+      case '{':
+        *token_end = start + 1;
+        return ObjectBegin;
+      case '}':
+        *token_end = start + 1;
+        return ObjectEnd;
+      case ':':
+        *token_end = start + 1;
+        return ObjectPairSeparator;
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+      case '-':
+        if (ParseNumberToken(start, end, token_end))
+          return Number;
+        break;
+      case '"':
+        if (ParseStringToken(start + 1, end, token_end))
+          return StringLiteral;
+        break;
+    }
+    return InvalidToken;
+  }
+
+  static int HexToInt(Char c) {
+    if ('0' <= c && c <= '9')
+      return c - '0';
+    if ('A' <= c && c <= 'F')
+      return c - 'A' + 10;
+    if ('a' <= c && c <= 'f')
+      return c - 'a' + 10;
+    assert(false);  // Unreachable.
+    return 0;
+  }
+
+  static bool DecodeString(const Char* start,
+                           const Char* end,
+                           std::vector<uint16_t>* output) {
+    if (start == end)
+      return true;
+    if (start > end)
+      return false;
+    output->reserve(end - start);
+    while (start < end) {
+      uint16_t c = *start++;
+      // If the |Char| we're dealing with is really a byte, then
+      // we have utf8 here, and we need to check for multibyte characters
+      // and transcode them to utf16 (either one or two utf16 chars).
+      if (sizeof(Char) == sizeof(uint8_t) && c >= 0x7f) {
+        // Inspect the leading byte to figure out how long the utf8
+        // byte sequence is; while doing this initialize |codepoint|
+        // with the first few bits.
+        // See table in: https://en.wikipedia.org/wiki/UTF-8
+        // byte one is 110x xxxx -> 2 byte utf8 sequence
+        // byte one is 1110 xxxx -> 3 byte utf8 sequence
+        // byte one is 1111 0xxx -> 4 byte utf8 sequence
+        uint32_t codepoint;
+        int num_bytes_left;
+        if ((c & 0xe0) == 0xc0) {  // 2 byte utf8 sequence
+          num_bytes_left = 1;
+          codepoint = c & 0x1f;
+        } else if ((c & 0xf0) == 0xe0) {  // 3 byte utf8 sequence
+          num_bytes_left = 2;
+          codepoint = c & 0x0f;
+        } else if ((c & 0xf8) == 0xf0) {  // 4 byte utf8 sequence
+          codepoint = c & 0x07;
+          num_bytes_left = 3;
+        } else {
+          return false;  // invalid leading byte
+        }
+
+        // If we have enough bytes in our inpput, decode the remaining ones
+        // belonging to this Unicode character into |codepoint|.
+        if (start + num_bytes_left > end)
+          return false;
+        while (num_bytes_left > 0) {
+          c = *start++;
+          --num_bytes_left;
+          // Check the next byte is a continuation byte, that is 10xx xxxx.
+          if ((c & 0xc0) != 0x80)
+            return false;
+          codepoint = (codepoint << 6) | (c & 0x3f);
+        }
+
+        // Disallow overlong encodings for ascii characters, as these
+        // would include " and other characters significant to JSON
+        // string termination / control.
+        if (codepoint < 0x7f)
+          return false;
+        // Invalid in UTF8, and can't be represented in UTF16 anyway.
+        if (codepoint > 0x10ffff)
+          return false;
+
+        // So, now we transcode to UTF16,
+        // using the math described at https://en.wikipedia.org/wiki/UTF-16,
+        // for either one or two 16 bit characters.
+        if (codepoint < 0xffff) {
+          output->push_back(codepoint);
+          continue;
+        }
+        codepoint -= 0x10000;
+        output->push_back((codepoint >> 10) + 0xd800);    // high surrogate
+        output->push_back((codepoint & 0x3ff) + 0xdc00);  // low surrogate
+        continue;
+      }
+      if ('\\' != c) {
+        output->push_back(c);
+        continue;
+      }
+      if (start == end)
+        return false;
+      c = *start++;
+
+      if (c == 'x') {
+        // \x is not supported.
+        return false;
+      }
+
+      switch (c) {
+        case '"':
+        case '/':
+        case '\\':
+          break;
+        case 'b':
+          c = '\b';
+          break;
+        case 'f':
+          c = '\f';
+          break;
+        case 'n':
+          c = '\n';
+          break;
+        case 'r':
+          c = '\r';
+          break;
+        case 't':
+          c = '\t';
+          break;
+        case 'v':
+          c = '\v';
+          break;
+        case 'u':
+          c = (HexToInt(*start) << 12) + (HexToInt(*(start + 1)) << 8) +
+              (HexToInt(*(start + 2)) << 4) + HexToInt(*(start + 3));
+          start += 4;
+          break;
+        default:
+          return false;
+      }
+      output->push_back(c);
+    }
+    return true;
+  }
+
+  void ParseValue(const Char* start,
+                  const Char* end,
+                  const Char** value_token_end,
+                  int depth) {
+    if (depth > kStackLimit) {
+      HandleError(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, start);
+      return;
+    }
+    const Char* token_start;
+    const Char* token_end;
+    Token token = ParseToken(start, end, &token_start, &token_end);
+    switch (token) {
+      case NoInput:
+        HandleError(Error::JSON_PARSER_NO_INPUT, token_start);
+        return;
+      case InvalidToken:
+        HandleError(Error::JSON_PARSER_INVALID_TOKEN, token_start);
+        return;
+      case NullToken:
+        handler_->HandleNull();
+        break;
+      case BoolTrue:
+        handler_->HandleBool(true);
+        break;
+      case BoolFalse:
+        handler_->HandleBool(false);
+        break;
+      case Number: {
+        double value;
+        if (!CharsToDouble(token_start, token_end - token_start, &value)) {
+          HandleError(Error::JSON_PARSER_INVALID_NUMBER, token_start);
+          return;
+        }
+        if (value >= std::numeric_limits<int32_t>::min() &&
+            value <= std::numeric_limits<int32_t>::max() &&
+            static_cast<int32_t>(value) == value)
+          handler_->HandleInt32(static_cast<int32_t>(value));
+        else
+          handler_->HandleDouble(value);
+        break;
+      }
+      case StringLiteral: {
+        std::vector<uint16_t> value;
+        bool ok = DecodeString(token_start + 1, token_end - 1, &value);
+        if (!ok) {
+          HandleError(Error::JSON_PARSER_INVALID_STRING, token_start);
+          return;
+        }
+        handler_->HandleString16(span<uint16_t>(value.data(), value.size()));
+        break;
+      }
+      case ArrayBegin: {
+        handler_->HandleArrayBegin();
+        start = token_end;
+        token = ParseToken(start, end, &token_start, &token_end);
+        while (token != ArrayEnd) {
+          ParseValue(start, end, &token_end, depth + 1);
+          if (error_)
+            return;
+
+          // After a list value, we expect a comma or the end of the list.
+          start = token_end;
+          token = ParseToken(start, end, &token_start, &token_end);
+          if (token == ListSeparator) {
+            start = token_end;
+            token = ParseToken(start, end, &token_start, &token_end);
+            if (token == ArrayEnd) {
+              HandleError(Error::JSON_PARSER_UNEXPECTED_ARRAY_END, token_start);
+              return;
+            }
+          } else if (token != ArrayEnd) {
+            // Unexpected value after list value. Bail out.
+            HandleError(Error::JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED,
+                        token_start);
+            return;
+          }
+        }
+        handler_->HandleArrayEnd();
+        break;
+      }
+      case ObjectBegin: {
+        handler_->HandleMapBegin();
+        start = token_end;
+        token = ParseToken(start, end, &token_start, &token_end);
+        while (token != ObjectEnd) {
+          if (token != StringLiteral) {
+            HandleError(Error::JSON_PARSER_STRING_LITERAL_EXPECTED,
+                        token_start);
+            return;
+          }
+          std::vector<uint16_t> key;
+          if (!DecodeString(token_start + 1, token_end - 1, &key)) {
+            HandleError(Error::JSON_PARSER_INVALID_STRING, token_start);
+            return;
+          }
+          handler_->HandleString16(span<uint16_t>(key.data(), key.size()));
+          start = token_end;
+
+          token = ParseToken(start, end, &token_start, &token_end);
+          if (token != ObjectPairSeparator) {
+            HandleError(Error::JSON_PARSER_COLON_EXPECTED, token_start);
+            return;
+          }
+          start = token_end;
+
+          ParseValue(start, end, &token_end, depth + 1);
+          if (error_)
+            return;
+          start = token_end;
+
+          // After a key/value pair, we expect a comma or the end of the
+          // object.
+          token = ParseToken(start, end, &token_start, &token_end);
+          if (token == ListSeparator) {
+            start = token_end;
+            token = ParseToken(start, end, &token_start, &token_end);
+            if (token == ObjectEnd) {
+              HandleError(Error::JSON_PARSER_UNEXPECTED_MAP_END, token_start);
+              return;
+            }
+          } else if (token != ObjectEnd) {
+            // Unexpected value after last object value. Bail out.
+            HandleError(Error::JSON_PARSER_COMMA_OR_MAP_END_EXPECTED,
+                        token_start);
+            return;
+          }
+        }
+        handler_->HandleMapEnd();
+        break;
+      }
+
+      default:
+        // We got a token that's not a value.
+        HandleError(Error::JSON_PARSER_VALUE_EXPECTED, token_start);
+        return;
+    }
+
+    SkipWhitespaceAndComments(token_end, end, value_token_end);
+  }
+
+  void HandleError(Error error, const Char* pos) {
+    assert(error != Error::OK);
+    if (!error_) {
+      handler_->HandleError(Status{error, pos - start_pos_});
+      error_ = true;
+    }
+  }
+
+  const Char* start_pos_ = nullptr;
+  bool error_ = false;
+  const Platform* platform_;
+  StreamingParserHandler* handler_;
+};
+}  // namespace
+
+void ParseJSON(const Platform* platform,
+               span<uint8_t> chars,
+               StreamingParserHandler* handler) {
+  JsonParser<uint8_t> parser(platform, handler);
+  parser.Parse(chars.data(), chars.size());
+}
+
+void ParseJSON(const Platform* platform,
+               span<uint16_t> chars,
+               StreamingParserHandler* handler) {
+  JsonParser<uint16_t> parser(platform, handler);
+  parser.Parse(chars.data(), chars.size());
+}
+}  // namespace json
+
+{% for namespace in config.protocol.namespace %}
+} // namespace {{namespace}}
+{% endfor %}
+
diff --git a/third_party/inspector_protocol/lib/CBOR_h.template b/third_party/inspector_protocol/lib/encoding_h.template
similarity index 65%
copy from third_party/inspector_protocol/lib/CBOR_h.template
copy to third_party/inspector_protocol/lib/encoding_h.template
index 9d28adb..aba28c8 100644
--- a/third_party/inspector_protocol/lib/CBOR_h.template
+++ b/third_party/inspector_protocol/lib/encoding_h.template
@@ -1,75 +1,29 @@
 {# This template is generated by gen_cbor_templates.py. #}
-// Generated by lib/CBOR_h.template.
+// Generated by lib/encoding_h.template.
 
 // Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef {{"_".join(config.protocol.namespace)}}_CBOR_h
-#define {{"_".join(config.protocol.namespace)}}_CBOR_h
+#ifndef {{"_".join(config.protocol.namespace)}}_encoding_h
+#define {{"_".join(config.protocol.namespace)}}_encoding_h
 
 #include <cstddef>
 #include <cstdint>
 #include <memory>
+#include <string>
 #include <vector>
 
 {% for namespace in config.protocol.namespace %}
 namespace {{namespace}} {
 {% endfor %}
 
-// ===== encoding/status.h =====
+// ===== encoding/encoding.h =====
 
-// Error codes.
-enum class Error {
-  OK = 0,
-  // JSON parsing errors - json_parser.{h,cc}.
-  JSON_PARSER_UNPROCESSED_INPUT_REMAINS = 0x01,
-  JSON_PARSER_STACK_LIMIT_EXCEEDED = 0x02,
-  JSON_PARSER_NO_INPUT = 0x03,
-  JSON_PARSER_INVALID_TOKEN = 0x04,
-  JSON_PARSER_INVALID_NUMBER = 0x05,
-  JSON_PARSER_INVALID_STRING = 0x06,
-  JSON_PARSER_UNEXPECTED_ARRAY_END = 0x07,
-  JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED = 0x08,
-  JSON_PARSER_STRING_LITERAL_EXPECTED = 0x09,
-  JSON_PARSER_COLON_EXPECTED = 0x0a,
-  JSON_PARSER_UNEXPECTED_OBJECT_END = 0x0b,
-  JSON_PARSER_COMMA_OR_OBJECT_END_EXPECTED = 0x0c,
-  JSON_PARSER_VALUE_EXPECTED = 0x0d,
 
-  CBOR_INVALID_INT32 = 0x0e,
-  CBOR_INVALID_DOUBLE = 0x0f,
-  CBOR_INVALID_ENVELOPE = 0x10,
-  CBOR_INVALID_STRING8 = 0x11,
-  CBOR_INVALID_STRING16 = 0x12,
-  CBOR_INVALID_BINARY = 0x13,
-  CBOR_UNSUPPORTED_VALUE = 0x14,
-  CBOR_NO_INPUT = 0x15,
-  CBOR_INVALID_START_BYTE = 0x16,
-  CBOR_UNEXPECTED_EOF_EXPECTED_VALUE = 0x17,
-  CBOR_UNEXPECTED_EOF_IN_ARRAY = 0x18,
-  CBOR_UNEXPECTED_EOF_IN_MAP = 0x19,
-  CBOR_INVALID_MAP_KEY = 0x1a,
-  CBOR_STACK_LIMIT_EXCEEDED = 0x1b,
-  CBOR_STRING8_MUST_BE_7BIT = 0x1c,
-  CBOR_TRAILING_JUNK = 0x1d,
-  CBOR_MAP_START_EXPECTED = 0x1e,
-};
-
-// A status value with position that can be copied. The default status
-// is OK. Usually, error status values should come with a valid position.
-struct Status {
-  static constexpr std::ptrdiff_t npos() { return -1; }
-
-  bool ok() const { return error == Error::OK; }
-
-  Error error = Error::OK;
-  std::ptrdiff_t pos = npos();
-  Status(Error error, std::ptrdiff_t pos) : error(error), pos(pos) {}
-  Status() = default;
-};
-
-// ===== encoding/span.h =====
+// =============================================================================
+// span - sequence of bytes
+// =============================================================================
 
 // This template is similar to std::span, which will be included in C++20.  Like
 // std::span it uses ptrdiff_t, which is signed (and thus a bit annoying
@@ -107,19 +61,78 @@
   index_type size_;
 };
 
-// ===== encoding/json_parser_handler.h =====
+template <typename T>
+span<T> SpanFromVector(const std::vector<T>& v) {
+  return span<T>(v.data(), v.size());
+}
 
-// Handler interface for JSON parser events. See also json_parser.h.
-class JSONParserHandler {
+inline span<uint8_t> SpanFromStdString(const std::string& v) {
+  return span<uint8_t>(reinterpret_cast<const uint8_t*>(v.data()), v.size());
+}
+
+// Error codes.
+enum class Error {
+  OK = 0,
+  // JSON parsing errors - json_parser.{h,cc}.
+  JSON_PARSER_UNPROCESSED_INPUT_REMAINS = 0x01,
+  JSON_PARSER_STACK_LIMIT_EXCEEDED = 0x02,
+  JSON_PARSER_NO_INPUT = 0x03,
+  JSON_PARSER_INVALID_TOKEN = 0x04,
+  JSON_PARSER_INVALID_NUMBER = 0x05,
+  JSON_PARSER_INVALID_STRING = 0x06,
+  JSON_PARSER_UNEXPECTED_ARRAY_END = 0x07,
+  JSON_PARSER_COMMA_OR_ARRAY_END_EXPECTED = 0x08,
+  JSON_PARSER_STRING_LITERAL_EXPECTED = 0x09,
+  JSON_PARSER_COLON_EXPECTED = 0x0a,
+  JSON_PARSER_UNEXPECTED_MAP_END = 0x0b,
+  JSON_PARSER_COMMA_OR_MAP_END_EXPECTED = 0x0c,
+  JSON_PARSER_VALUE_EXPECTED = 0x0d,
+
+  CBOR_INVALID_INT32 = 0x0e,
+  CBOR_INVALID_DOUBLE = 0x0f,
+  CBOR_INVALID_ENVELOPE = 0x10,
+  CBOR_INVALID_STRING8 = 0x11,
+  CBOR_INVALID_STRING16 = 0x12,
+  CBOR_INVALID_BINARY = 0x13,
+  CBOR_UNSUPPORTED_VALUE = 0x14,
+  CBOR_NO_INPUT = 0x15,
+  CBOR_INVALID_START_BYTE = 0x16,
+  CBOR_UNEXPECTED_EOF_EXPECTED_VALUE = 0x17,
+  CBOR_UNEXPECTED_EOF_IN_ARRAY = 0x18,
+  CBOR_UNEXPECTED_EOF_IN_MAP = 0x19,
+  CBOR_INVALID_MAP_KEY = 0x1a,
+  CBOR_STACK_LIMIT_EXCEEDED = 0x1b,
+  CBOR_STRING8_MUST_BE_7BIT = 0x1c,
+  CBOR_TRAILING_JUNK = 0x1d,
+  CBOR_MAP_START_EXPECTED = 0x1e,
+};
+
+// A status value with position that can be copied. The default status
+// is OK. Usually, error status values should come with a valid position.
+struct Status {
+  static constexpr std::ptrdiff_t npos() { return -1; }
+
+  bool ok() const { return error == Error::OK; }
+
+  Error error = Error::OK;
+  std::ptrdiff_t pos = npos();
+  Status(Error error, std::ptrdiff_t pos) : error(error), pos(pos) {}
+  Status() = default;
+};
+
+// Handler interface for parser events emitted by a streaming parser.
+// See cbor::NewCBOREncoder, cbor::ParseCBOR, json::NewJSONEncoder,
+// json::ParseJSON.
+class StreamingParserHandler {
  public:
-  virtual ~JSONParserHandler() = default;
-  virtual void HandleObjectBegin() = 0;
-  virtual void HandleObjectEnd() = 0;
+  virtual ~StreamingParserHandler() = default;
+  virtual void HandleMapBegin() = 0;
+  virtual void HandleMapEnd() = 0;
   virtual void HandleArrayBegin() = 0;
   virtual void HandleArrayEnd() = 0;
   virtual void HandleString8(span<uint8_t> chars) = 0;
   virtual void HandleString16(span<uint16_t> chars) = 0;
-  virtual void HandleBinary(std::vector<uint8_t> bytes) = 0;
+  virtual void HandleBinary(span<uint8_t> bytes) = 0;
   virtual void HandleDouble(double value) = 0;
   virtual void HandleInt32(int32_t value) = 0;
   virtual void HandleBool(bool value) = 0;
@@ -132,97 +145,7 @@
   virtual void HandleError(Status error) = 0;
 };
 
-// ===== encoding/cbor_internals.h =====
-
 namespace cbor {
-enum class MajorType;
-}
-
-namespace cbor_internals {
-
-// Reads the start of a token with definitive size from |bytes|.
-// |type| is the major type as specified in RFC 7049 Section 2.1.
-// |value| is the payload (e.g. for MajorType::UNSIGNED) or is the size
-// (e.g. for BYTE_STRING).
-// If successful, returns the number of bytes read. Otherwise returns -1.
-int8_t ReadTokenStart(span<uint8_t> bytes, cbor::MajorType* type,
-                      uint64_t* value);
-
-// Writes the start of a token with |type|. The |value| may indicate the size,
-// or it may be the payload if the value is an unsigned integer.
-void WriteTokenStart(cbor::MajorType type, uint64_t value,
-                     std::vector<uint8_t>* encoded);
-}  // namespace cbor_internals
-
-// ===== encoding/cbor.h =====
-
-
-namespace cbor {
-
-// The major types from RFC 7049 Section 2.1.
-enum class MajorType {
-  UNSIGNED = 0,
-  NEGATIVE = 1,
-  BYTE_STRING = 2,
-  STRING = 3,
-  ARRAY = 4,
-  MAP = 5,
-  TAG = 6,
-  SIMPLE_VALUE = 7
-};
-
-// Indicates the number of bits the "initial byte" needs to be shifted to the
-// right after applying |kMajorTypeMask| to produce the major type in the
-// lowermost bits.
-static constexpr uint8_t kMajorTypeBitShift = 5u;
-// Mask selecting the low-order 5 bits of the "initial byte", which is where
-// the additional information is encoded.
-static constexpr uint8_t kAdditionalInformationMask = 0x1f;
-// Mask selecting the high-order 3 bits of the "initial byte", which indicates
-// the major type of the encoded value.
-static constexpr uint8_t kMajorTypeMask = 0xe0;
-// Indicates the integer is in the following byte.
-static constexpr uint8_t kAdditionalInformation1Byte = 24u;
-// Indicates the integer is in the next 2 bytes.
-static constexpr uint8_t kAdditionalInformation2Bytes = 25u;
-// Indicates the integer is in the next 4 bytes.
-static constexpr uint8_t kAdditionalInformation4Bytes = 26u;
-// Indicates the integer is in the next 8 bytes.
-static constexpr uint8_t kAdditionalInformation8Bytes = 27u;
-
-// Encodes the initial byte, consisting of the |type| in the first 3 bits
-// followed by 5 bits of |additional_info|.
-constexpr uint8_t EncodeInitialByte(MajorType type, uint8_t additional_info) {
-  return (static_cast<uint8_t>(type) << kMajorTypeBitShift) |
-         (additional_info & kAdditionalInformationMask);
-}
-
-// TAG 24 indicates that what follows is a byte string which is
-// encoded in CBOR format. We use this as a wrapper for
-// maps and arrays, allowing us to skip them, because the
-// byte string carries its size (byte length).
-// https://tools.ietf.org/html/rfc7049#section-2.4.4.1
-static constexpr uint8_t kInitialByteForEnvelope =
-    EncodeInitialByte(MajorType::TAG, 24);
-// The initial byte for a byte string with at most 2^32 bytes
-// of payload. This is used for envelope encoding, even if
-// the byte string is shorter.
-static constexpr uint8_t kInitialByteFor32BitLengthByteString =
-    EncodeInitialByte(MajorType::BYTE_STRING, 26);
-
-// See RFC 7049 Section 2.2.1, indefinite length arrays / maps have additional
-// info = 31.
-static constexpr uint8_t kInitialByteIndefiniteLengthArray =
-    EncodeInitialByte(MajorType::ARRAY, 31);
-static constexpr uint8_t kInitialByteIndefiniteLengthMap =
-    EncodeInitialByte(MajorType::MAP, 31);
-// See RFC 7049 Section 2.3, Table 1; this is used for finishing indefinite
-// length maps / arrays.
-static constexpr uint8_t kStopByte =
-    EncodeInitialByte(MajorType::SIMPLE_VALUE, 31);
-
-}  // namespace cbor
-
 // The binary encoding for the inspector protocol follows the CBOR specification
 // (RFC 7049). Additional constraints:
 // - Only indefinite length maps and arrays are supported.
@@ -239,12 +162,38 @@
 //   as CBOR BYTE_STRING (major type 2). For such strings, the number of
 //   bytes encoded must be even.
 // - UTF8 strings (major type 3) are supported.
-// - 7 bit US-ASCII strings must always be encoded as UTF8 strings, not
+// - 7 bit US-ASCII strings must always be encoded as UTF8 strings, never
 //   as UTF16 strings.
 // - Arbitrary byte arrays, in the inspector protocol called 'binary',
 //   are encoded as BYTE_STRING (major type 2), prefixed with a byte
 //   indicating base64 when rendered as JSON.
 
+// =============================================================================
+// Detecting CBOR content
+// =============================================================================
+
+// The first byte for an envelope, which we use for wrapping dictionaries
+// and arrays; and the byte that indicates a byte string with 32 bit length.
+// These two bytes start an envelope, and thereby also any CBOR message
+// produced or consumed by this protocol. See also |EnvelopeEncoder| below.
+uint8_t InitialByteForEnvelope();
+uint8_t InitialByteFor32BitLengthByteString();
+
+// Checks whether |msg| is a cbor message.
+bool IsCBORMessage(span<uint8_t> msg);
+
+// =============================================================================
+// Encoding individual CBOR items
+// =============================================================================
+
+// Some constants for CBOR tokens that only take a single byte on the wire.
+uint8_t EncodeTrue();
+uint8_t EncodeFalse();
+uint8_t EncodeNull();
+uint8_t EncodeIndefiniteLengthArrayStart();
+uint8_t EncodeIndefiniteLengthMapStart();
+uint8_t EncodeStop();
+
 // Encodes |value| as |UNSIGNED| (major type 0) iff >= 0, or |NEGATIVE|
 // (major type 1) iff < 0.
 void EncodeInt32(int32_t value, std::vector<uint8_t>* out);
@@ -275,13 +224,9 @@
 // with additional info = 27, followed by 8 bytes in big endian.
 void EncodeDouble(double value, std::vector<uint8_t>* out);
 
-// Some constants for CBOR tokens that only take a single byte on the wire.
-uint8_t EncodeTrue();
-uint8_t EncodeFalse();
-uint8_t EncodeNull();
-uint8_t EncodeIndefiniteLengthArrayStart();
-uint8_t EncodeIndefiniteLengthMapStart();
-uint8_t EncodeStop();
+// =============================================================================
+// cbor::EnvelopeEncoder - for wrapping submessages
+// =============================================================================
 
 // An envelope indicates the byte length of a wrapped item.
 // We use this for maps and array, which allows the decoder
@@ -304,20 +249,23 @@
   std::size_t byte_size_pos_ = 0;
 };
 
-// This can be used to convert from JSON to CBOR, by passing the
-// return value to the routines in json_parser.h.  The handler will encode into
-// |out|, and iff an error occurs it will set |status| to an error and clear
-// |out|. Otherwise, |status.ok()| will be |true|.
-std::unique_ptr<JSONParserHandler> NewJSONToCBOREncoder(
-    std::vector<uint8_t>* out, Status* status);
+// =============================================================================
+// cbor::NewCBOREncoder - for encoding from a streaming parser
+// =============================================================================
 
-// Parses a CBOR encoded message from |bytes|, sending JSON events to
-// |json_out|. If an error occurs, sends |out->HandleError|, and parsing stops.
-// The client is responsible for discarding the already received information in
-// that case.
-void ParseCBOR(span<uint8_t> bytes, JSONParserHandler* json_out);
+// This can be used to convert to CBOR, by passing the return value to a parser
+// that drives it. The handler will encode into |out|, and iff an error occurs
+// it will set |status| to an error and clear |out|. Otherwise, |status.ok()|
+// will be |true|.
+std::unique_ptr<StreamingParserHandler> NewCBOREncoder(
+    std::vector<uint8_t>* out,
+    Status* status);
 
-// Tags for the tokens within a CBOR message that CBORStream understands.
+// =============================================================================
+// cbor::CBORTokenizer - for parsing individual CBOR items
+// =============================================================================
+
+// Tags for the tokens within a CBOR message that CBORTokenizer understands.
 // Note that this is not the same terminology as the CBOR spec (RFC 7049),
 // but rather, our adaptation. For instance, we lump unsigned and signed
 // major type into INT32 here (and disallow values outside the int32_t range).
@@ -357,6 +305,18 @@
   DONE,
 };
 
+// The major types from RFC 7049 Section 2.1.
+enum class MajorType {
+  UNSIGNED = 0,
+  NEGATIVE = 1,
+  BYTE_STRING = 2,
+  STRING = 3,
+  ARRAY = 4,
+  MAP = 5,
+  TAG = 6,
+  SIMPLE_VALUE = 7
+};
+
 // CBORTokenizer segments a CBOR message, presenting the tokens therein as
 // numbers, strings, etc. This is not a complete CBOR parser, but makes it much
 // easier to implement one (e.g. ParseCBOR, above). It can also be used to parse
@@ -403,6 +363,9 @@
   // To be called only if ::TokenTag() == CBORTokenTag::BINARY.
   span<uint8_t> GetBinary() const;
 
+  // To be called only if ::TokenTag() == CBORTokenTag::ENVELOPE.
+  span<uint8_t> GetEnvelopeContents() const;
+
  private:
   void ReadNextToken(bool enter_envelope);
   void SetToken(CBORTokenTag token, std::ptrdiff_t token_byte_length);
@@ -412,14 +375,72 @@
   CBORTokenTag token_tag_;
   struct Status status_;
   std::ptrdiff_t token_byte_length_;
-  cbor::MajorType token_start_type_;
+  MajorType token_start_type_;
   uint64_t token_start_internal_value_;
 };
 
-void DumpCBOR(span<uint8_t> cbor);
+// =============================================================================
+// cbor::ParseCBOR - for receiving streaming parser events for CBOR messages
+// =============================================================================
 
+// Parses a CBOR encoded message from |bytes|, sending events to
+// |out|. If an error occurs, sends |out->HandleError|, and parsing stops.
+// The client is responsible for discarding the already received information in
+// that case.
+void ParseCBOR(span<uint8_t> bytes, StreamingParserHandler* out);
+
+namespace internals {  // Exposed only for writing tests.
+int8_t ReadTokenStart(span<uint8_t> bytes,
+                      cbor::MajorType* type,
+                      uint64_t* value);
+
+void WriteTokenStart(cbor::MajorType type,
+                     uint64_t value,
+                     std::vector<uint8_t>* encoded);
+}  // namespace internals
+}  // namespace cbor
+
+namespace json {
+// Client code must provide an instance. Implementation should delegate
+// to whatever is appropriate.
+class Platform {
+ public:
+  virtual ~Platform() = default;
+  // Parses |str| into |result|. Returns false iff there are
+  // leftover characters or parsing errors.
+  virtual bool StrToD(const char* str, double* result) const = 0;
+
+  // Prints |value| in a format suitable for JSON.
+  virtual std::unique_ptr<char[]> DToStr(double value) const = 0;
+};
+
+// =============================================================================
+// json::NewJSONEncoder - for encoding streaming parser events as JSON
+// =============================================================================
+
+// Returns a handler object which will write ascii characters to |out|.
+// |status->ok()| will be false iff the handler routine HandleError() is called.
+// In that case, we'll stop emitting output.
+// Except for calling the HandleError routine at any time, the client
+// code must call the Handle* methods in an order in which they'd occur
+// in valid JSON; otherwise we may crash (the code uses assert).
+std::unique_ptr<StreamingParserHandler> NewJSONEncoder(const Platform* platform,
+                                                       std::string* out,
+                                                       Status* status);
+
+// =============================================================================
+// json::ParseJSON - for receiving streaming parser events for JSON
+// =============================================================================
+
+void ParseJSON(const Platform* platform,
+               span<uint8_t> chars,
+               StreamingParserHandler* handler);
+void ParseJSON(const Platform* platform,
+               span<uint16_t> chars,
+               StreamingParserHandler* handler);
+}  // namespace json
 
 {% for namespace in config.protocol.namespace %}
 } // namespace {{namespace}}
 {% endfor %}
-#endif // !defined({{"_".join(config.protocol.namespace)}}_CBOR_h)
+#endif // !defined({{"_".join(config.protocol.namespace)}}_encoding_h)
diff --git a/third_party/inspector_protocol/roll.py b/third_party/inspector_protocol/roll.py
index 59699e6..deb1b28 100755
--- a/third_party/inspector_protocol/roll.py
+++ b/third_party/inspector_protocol/roll.py
@@ -13,7 +13,6 @@
 
 
 FILES_TO_SYNC = [
-    'BUILD.gn',
     'README.md',
     'check_protocol_compatibility.py',
     'code_generator.py',
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium
index 331f07e5..f6bf534 100644
--- a/third_party/libvpx/README.chromium
+++ b/third_party/libvpx/README.chromium
@@ -5,9 +5,9 @@
 License File: source/libvpx/LICENSE
 Security Critical: yes
 
-Date: Thursday March 07 2019
+Date: Thursday March 14 2019
 Branch: master
-Commit: 8256c8b297c8b7c7ee4de24edff82ed67d6ef207
+Commit: 1533bd84f12e5b24b5c2e41d1729942c7aa218ad
 
 Description:
 Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/libvpx_srcs.gni b/third_party/libvpx/libvpx_srcs.gni
index 13614df..376acb9 100644
--- a/third_party/libvpx/libvpx_srcs.gni
+++ b/third_party/libvpx/libvpx_srcs.gni
@@ -444,8 +444,7 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/variance_sse2.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/vpx_subpixel_4t_intrin_sse2.c",
 ]
-libvpx_srcs_x86_sse3 = [
-]
+libvpx_srcs_x86_sse3 = []
 libvpx_srcs_x86_ssse3 = [
   "//third_party/libvpx/source/libvpx/vp8/encoder/x86/vp8_quantize_ssse3.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/x86/vp9_dct_ssse3.c",
@@ -481,8 +480,7 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/variance_avx2.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/vpx_subpixel_8t_intrin_avx2.c",
 ]
-libvpx_srcs_x86_avx512 = [
-]
+libvpx_srcs_x86_avx512 = []
 libvpx_srcs_x86_64 = [
   "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c",
   "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h",
@@ -897,9 +895,8 @@
   "//third_party/libvpx/source/libvpx/vpx_ports/emms_mmx.asm",
   "//third_party/libvpx/source/libvpx/vpx_ports/float_control_word.asm",
 ]
-libvpx_srcs_x86_64_mmx = [
-  "//third_party/libvpx/source/libvpx/vp8/common/x86/idct_blk_mmx.c",
-]
+libvpx_srcs_x86_64_mmx =
+    [ "//third_party/libvpx/source/libvpx/vp8/common/x86/idct_blk_mmx.c" ]
 libvpx_srcs_x86_64_sse2 = [
   "//third_party/libvpx/source/libvpx/vp8/common/x86/bilinear_filter_sse2.c",
   "//third_party/libvpx/source/libvpx/vp8/common/x86/idct_blk_sse2.c",
@@ -930,8 +927,7 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/variance_sse2.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/vpx_subpixel_4t_intrin_sse2.c",
 ]
-libvpx_srcs_x86_64_sse3 = [
-]
+libvpx_srcs_x86_64_sse3 = []
 libvpx_srcs_x86_64_ssse3 = [
   "//third_party/libvpx/source/libvpx/vp8/encoder/x86/vp8_quantize_ssse3.c",
   "//third_party/libvpx/source/libvpx/vp9/encoder/x86/vp9_dct_ssse3.c",
@@ -967,8 +963,7 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/variance_avx2.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/vpx_subpixel_8t_intrin_avx2.c",
 ]
-libvpx_srcs_x86_64_avx512 = [
-]
+libvpx_srcs_x86_64_avx512 = []
 libvpx_srcs_arm = [
   "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c",
   "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h",
@@ -1311,8 +1306,7 @@
   "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.c",
   "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.h",
 ]
-libvpx_srcs_arm_assembly = [
-]
+libvpx_srcs_arm_assembly = []
 libvpx_srcs_arm_neon = [
   "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c",
   "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h",
@@ -2570,8 +2564,7 @@
   "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.c",
   "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.h",
 ]
-libvpx_srcs_arm64_assembly = [
-]
+libvpx_srcs_arm64_assembly = []
 libvpx_srcs_arm_neon_highbd = [
   "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c",
   "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h",
@@ -3436,8 +3429,7 @@
   "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.c",
   "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.h",
 ]
-libvpx_srcs_arm64_highbd_assembly = [
-]
+libvpx_srcs_arm64_highbd_assembly = []
 libvpx_srcs_mips = [
   "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c",
   "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h",
@@ -3779,8 +3771,7 @@
   "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.c",
   "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.h",
 ]
-libvpx_srcs_mips_assembly = [
-]
+libvpx_srcs_mips_assembly = []
 libvpx_srcs_nacl = [
   "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c",
   "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h",
@@ -4121,8 +4112,7 @@
   "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.c",
   "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.h",
 ]
-libvpx_srcs_nacl_assembly = [
-]
+libvpx_srcs_nacl_assembly = []
 libvpx_srcs_generic = [
   "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.c",
   "//third_party/libvpx/source/libvpx/vp8/common/alloccommon.h",
@@ -4463,5 +4453,4 @@
   "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.c",
   "//third_party/libvpx/source/libvpx/vpx_util/vpx_write_yuv_frame.h",
 ]
-libvpx_srcs_generic_assembly = [
-]
+libvpx_srcs_generic_assembly = []
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h
index bde94740..72e4d8ce 100644
--- a/third_party/libvpx/source/config/vpx_version.h
+++ b/third_party/libvpx/source/config/vpx_version.h
@@ -2,7 +2,7 @@
 #define VERSION_MAJOR  1
 #define VERSION_MINOR  8
 #define VERSION_PATCH  0
-#define VERSION_EXTRA  "207-g8256c8b29"
+#define VERSION_EXTRA  "239-g1533bd84f"
 #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.8.0-207-g8256c8b29"
-#define VERSION_STRING      " v1.8.0-207-g8256c8b29"
+#define VERSION_STRING_NOSP "v1.8.0-239-g1533bd84f"
+#define VERSION_STRING      " v1.8.0-239-g1533bd84f"
diff --git a/third_party/protobuf/proto_library.gni b/third_party/protobuf/proto_library.gni
index 7d470ca6..bf22f7b 100644
--- a/third_party/protobuf/proto_library.gni
+++ b/third_party/protobuf/proto_library.gni
@@ -56,6 +56,10 @@
 #   generator_plugin_options (optional)
 #       Extra flags passed to the plugin. See cc_generator_options.
 #
+#   deps (optional)
+#       DEPRECATED: use proto_deps or link_deps instead (crbug.com/938011).
+#       Additional dependencies.
+#
 #   link_deps (optional)
 #       Additional dependencies linked to library.
 #
@@ -323,6 +327,9 @@
     if (defined(invoker.proto_deps)) {
       deps += invoker.proto_deps
     }
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
   }
 
   # Option to disable building a library in component build.
@@ -414,6 +421,9 @@
 
     # This will link any libraries in the deps (the use of invoker.deps in the
     # action won't link it).
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
     if (defined(invoker.link_deps)) {
       deps += invoker.link_deps
     }
diff --git a/tools/cfi/blacklist.txt b/tools/cfi/blacklist.txt
index 8ebf793..273b8788 100644
--- a/tools/cfi/blacklist.txt
+++ b/tools/cfi/blacklist.txt
@@ -122,6 +122,7 @@
 
 # ANGLE
 src:*third_party/angle/src/libANGLE/*
+src:*third_party/angle/src/libEGL/*
 src:*third_party/angle/src/third_party/libXNVCtrl/NVCtrl.c
 # third_party/angle/src/gpu_info_util/SystemInfo_libpci.cpp
 fun:*GetPCIDevicesWithLibPCI*
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index a9e1a04..a3a2f28d 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -7,6 +7,8 @@
 
 It is also used by package.py to build the prebuilt clang binaries."""
 
+from __future__ import print_function
+
 import argparse
 import distutils.spawn
 import glob
@@ -20,7 +22,13 @@
 import tarfile
 import tempfile
 import time
-import urllib2
+
+try:
+  import urllib2 as urllib
+except ImportError: # For Py3 compatibility
+  import urllib.request as urllib
+  import urllib.error as urllib
+
 import zipfile
 
 
@@ -95,7 +103,7 @@
     try:
       sys.stdout.write('Downloading %s ' % url)
       sys.stdout.flush()
-      response = urllib2.urlopen(url)
+      response = urllib.urlopen(url)
       total_size = int(response.info().getheader('Content-Length').strip())
       bytes_done = 0
       dots_printed = 0
@@ -110,17 +118,17 @@
         sys.stdout.flush()
         dots_printed = num_dots
       if bytes_done != total_size:
-        raise urllib2.URLError("only got %d of %d bytes" %
-                               (bytes_done, total_size))
-      print ' Done.'
+        raise urllib.URLError("only got %d of %d bytes" %
+                              (bytes_done, total_size))
+      print(' Done.')
       return
-    except urllib2.URLError as e:
+    except urllib.URLError as e:
       sys.stdout.write('\n')
-      print e
-      if num_retries == 0 or isinstance(e, urllib2.HTTPError) and e.code == 404:
+      print(e)
+      if num_retries == 0 or isinstance(e, urllib.HTTPError) and e.code == 404:
         raise e
       num_retries -= 1
-      print 'Retrying in %d s ...' % retry_wait_s
+      print('Retrying in %d s ...' % retry_wait_s)
       time.sleep(retry_wait_s)
       retry_wait_s *= 2
 
@@ -218,10 +226,10 @@
   # do the single-string transformation there.
   if sys.platform != 'win32':
     command = ' '.join([pipes.quote(c) for c in command])
-  print 'Running', command
+  print('Running', command)
   if subprocess.call(command, env=env, shell=True) == 0:
     return True
-  print 'Failed.'
+  print('Failed.')
   if fail_hard:
     sys.exit(1)
   return False
@@ -229,7 +237,7 @@
 
 def CopyFile(src, dst):
   """Copy a file from src to dst."""
-  print "Copying %s to %s" % (src, dst)
+  print("Copying %s to %s" % (src, dst))
   shutil.copy(src, dst)
 
 
@@ -243,17 +251,17 @@
 
 def Checkout(name, url, dir):
   """Checkout the SVN module at url into dir. Use name for the log message."""
-  print "Checking out %s r%s into '%s'" % (name, CLANG_REVISION, dir)
+  print("Checking out %s r%s into '%s'" % (name, CLANG_REVISION, dir))
 
   command = ['svn', 'checkout', '--force', url + '@' + CLANG_REVISION, dir]
   if RunCommand(command, fail_hard=False):
     return
 
   if os.path.isdir(dir):
-    print "Removing %s." % (dir)
+    print("Removing %s." % dir)
     RmTree(dir)
 
-  print "Retrying."
+  print("Retrying.")
   RunCommand(command)
 
 
@@ -350,7 +358,7 @@
   GNUWIN_VERSION = '9'
   GNUWIN_STAMP = os.path.join(gnuwin_dir, 'stamp')
   if ReadStampFile(GNUWIN_STAMP) == GNUWIN_VERSION:
-    print 'GNU Win tools already up to date.'
+    print('GNU Win tools already up to date.')
   else:
     zip_name = 'gnuwin-%s.zip' % GNUWIN_VERSION
     DownloadAndUnpack(CDS_URL + '/tools/' + zip_name, LLVM_BUILD_TOOLS_DIR)
@@ -439,8 +447,8 @@
   version_out = subprocess.check_output([clang, '--version'])
   version_out = re.match(r'clang version ([0-9.]+)', version_out).group(1)
   if version_out != VERSION:
-    print ('unexpected clang version %s (not %s), update VERSION in update.py'
-           % (version_out, VERSION))
+    print('unexpected clang version %s (not %s), update VERSION in update.py'
+          % (version_out, VERSION))
     sys.exit(1)
 
 
@@ -461,10 +469,10 @@
     if runtimes_only:
       path_prefix = 'lib/clang/' + VERSION + '/lib/'
     DownloadAndUnpack(cds_full_url, LLVM_BUILD_DIR, path_prefix)
-  except urllib2.URLError:
-    print 'Failed to download prebuilt clang %s' % cds_file
-    print 'Use --force-local-build if you want to build locally.'
-    print 'Exiting.'
+  except urllib.URLError:
+    print('Failed to download prebuilt clang %s' % cds_file)
+    print('Use --force-local-build if you want to build locally.')
+    print('Exiting.')
     sys.exit(1)
 
 
@@ -500,24 +508,24 @@
     return 0
 
   if args.with_android and not os.path.exists(ANDROID_NDK_DIR):
-    print 'Android NDK not found at ' + ANDROID_NDK_DIR
-    print 'The Android NDK is needed to build a Clang whose -fsanitize=address'
-    print 'works on Android. See '
-    print 'https://www.chromium.org/developers/how-tos/android-build-instructions'
-    print 'for how to install the NDK, or pass --without-android.'
+    print('Android NDK not found at ' + ANDROID_NDK_DIR)
+    print('The Android NDK is needed to build a Clang whose -fsanitize=address')
+    print('works on Android. See ')
+    print('https://www.chromium.org/developers/how-tos/android-build-instructions')
+    print('for how to install the NDK, or pass --without-android.')
     return 1
 
   if args.with_fuchsia and not os.path.exists(FUCHSIA_SDK_DIR):
-    print 'Fuchsia SDK not found at ' + FUCHSIA_SDK_DIR
-    print 'The Fuchsia SDK is needed to build libclang_rt for Fuchsia.'
-    print 'Install the Fuchsia SDK by adding fuchsia to the '
-    print 'target_os section in your .gclient and running hooks, '
-    print 'or pass --without-fuchsia.'
-    print 'https://chromium.googlesource.com/chromium/src/+/master/docs/fuchsia_build_instructions.md'
-    print 'for general Fuchsia build instructions.'
+    print('Fuchsia SDK not found at ' + FUCHSIA_SDK_DIR)
+    print('The Fuchsia SDK is needed to build libclang_rt for Fuchsia.')
+    print('Install the Fuchsia SDK by adding fuchsia to the ')
+    print('target_os section in your .gclient and running hooks, ')
+    print('or pass --without-fuchsia.')
+    print('https://chromium.googlesource.com/chromium/src/+/master/docs/fuchsia_build_instructions.md')
+    print('for general Fuchsia build instructions.')
     return 1
 
-  print 'Locally building Clang %s...' % PACKAGE_VERSION
+  print('Locally building Clang %s...' % PACKAGE_VERSION)
 
   AddCMakeToPath(args)
   AddGnuWinToPath()
@@ -557,7 +565,7 @@
     base_cmake_args.append('-DLLVM_ENABLE_LIBXML2=FORCE_ON')
 
   if args.bootstrap:
-    print 'Building bootstrap compiler'
+    print('Building bootstrap compiler')
     EnsureDirExists(LLVM_BOOTSTRAP_DIR)
     os.chdir(LLVM_BOOTSTRAP_DIR)
     bootstrap_args = base_cmake_args + [
@@ -588,7 +596,7 @@
       cc = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang')
       cxx = os.path.join(LLVM_BOOTSTRAP_INSTALL_DIR, 'bin', 'clang++')
 
-    print 'Building final compiler'
+    print('Building final compiler')
 
   # LLVM uses C++11 starting in llvm 3.5. On Linux, this means libstdc++4.7+ is
   # needed, on OS X it requires libc++. clang only automatically links to libc++
@@ -632,7 +640,7 @@
   # Build lld and code coverage tools. This is done separately from the rest of
   # the build because these tools require threading support.
   tools_with_threading = [ 'lld', 'llvm-cov', 'llvm-profdata' ]
-  print 'Building the following tools with threading support: %s' % (
+  print('Building the following tools with threading support: %s' %
         str(tools_with_threading))
 
   if os.path.exists(THREADS_ENABLED_BUILD_DIR):
@@ -926,7 +934,7 @@
     RunCommand(['ninja', 'check-all'], msvc_arch='x64')
 
   WriteStampFile(PACKAGE_VERSION)
-  print 'Clang update was successful.'
+  print('Clang update was successful.')
   return 0
 
 
@@ -983,10 +991,10 @@
   args = parser.parse_args()
 
   if args.lto_lld and not args.bootstrap:
-    print '--lto-lld requires --bootstrap'
+    print('--lto-lld requires --bootstrap')
     return 1
   if args.lto_lld and not sys.platform.startswith('linux'):
-    print '--lto-lld is only effective on Linux. Ignoring the option.'
+    print('--lto-lld is only effective on Linux. Ignoring the option.')
     args.lto_lld = False
 
   # Get svn if we're going to use it to check the revision or do a local build.
@@ -995,9 +1003,9 @@
     AddSvnToPathOnWin()
 
   if args.verify_version and args.verify_version != VERSION:
-    print 'VERSION is %s but --verify-version argument was %s, exiting.' % (
-        VERSION, args.verify_version)
-    print 'clang_version in build/toolchain/toolchain.gni is likely outdated.'
+    print('VERSION is %s but --verify-version argument was %s, exiting.' % (
+        VERSION, args.verify_version))
+    print('clang_version in build/toolchain/toolchain.gni is likely outdated.')
     return 1
 
   # DEVELOPER_DIR needs to be set when Xcode isn't in a standard location
@@ -1009,9 +1017,9 @@
   global CLANG_REVISION, PACKAGE_VERSION
   if args.print_revision:
     if use_head_revision or args.llvm_force_head_revision:
-      print GetSvnRevision(LLVM_DIR)
+      print(GetSvnRevision(LLVM_DIR))
     else:
-      print PACKAGE_VERSION
+      print(PACKAGE_VERSION)
     return 0
 
   if args.print_clang_version:
diff --git a/tools/grit/grit/format/html_inline.py b/tools/grit/grit/format/html_inline.py
index b5393a7..226c323 100755
--- a/tools/grit/grit/format/html_inline.py
+++ b/tools/grit/grit/format/html_inline.py
@@ -55,7 +55,7 @@
     re.MULTILINE)
 # This re matches '<img srcset="..."'
 _SRCSET_RE = lazy_re.compile(
-    r'<img\b(?:[^>]*?\s)srcset="(?!\[\[|{{)(?P<srcset>[^"\']*)"',
+    r'<img\b(?:[^>]*?\s)srcset="(?!\[\[|{{|\$i18n{)(?P<srcset>[^"\']*)"',
     re.MULTILINE)
 # This re is for splitting srcset value string into "image candidate strings".
 # Notes:
diff --git a/tools/grit/grit/format/html_inline_unittest.py b/tools/grit/grit/format/html_inline_unittest.py
index eca6ada..96f1e26 100755
--- a/tools/grit/grit/format/html_inline_unittest.py
+++ b/tools/grit/grit/format/html_inline_unittest.py
@@ -648,6 +648,38 @@
                          util.FixLineEnd(result.inlined_data, '\n'))
     tmp_dir.CleanUp()
 
+  def testImgSrcsetIgnoresI18n(self):
+    '''Tests that $i18n{...} strings are ignored when inlining.
+    '''
+
+    src_html = '''
+      <html>
+      <head></head>
+      <body>
+        <img srcset="$i18n{foo}">
+      </body>
+      </html>
+      '''
+
+    files = {
+      'index.html': src_html,
+    }
+
+    expected_inlined = src_html
+
+    source_resources = set()
+    tmp_dir = util.TempDir(files)
+    for filename in files:
+      source_resources.add(tmp_dir.GetPath(util.normpath(filename)))
+
+    result = html_inline.DoInline(tmp_dir.GetPath('index.html'), None)
+    resources = result.inlined_files
+    resources.add(tmp_dir.GetPath('index.html'))
+    self.failUnlessEqual(resources, source_resources)
+    self.failUnlessEqual(expected_inlined,
+                         util.FixLineEnd(result.inlined_data, '\n'))
+    tmp_dir.CleanUp()
+
   def testConditionalInclude(self):
     '''Tests that output and dependency generation includes only files not'''\
         ''' blocked by  <if> macros.'''
diff --git a/tools/licenses.py b/tools/licenses.py
index 4d609162d..f893756 100755
--- a/tools/licenses.py
+++ b/tools/licenses.py
@@ -192,6 +192,12 @@
         "License": "BSD",
         "License File": "NOT_SHIPPED",
     },
+    os.path.join('third_party', 'crashpad', 'crashpad', 'third_party', 'xnu'): {
+        "Name": "xnu",
+        "URL": "https://opensource.apple.com/source/xnu/",
+        "License": "Apple Public Source License 2.0",
+        "License File": "APPLE_LICENSE",
+    },
     os.path.join('third_party', 'crashpad', 'crashpad', 'third_party',
                  'zlib'): {
         "Name": "zlib",
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index b246c7d..2378ac5 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -208,6 +208,7 @@
       'chromeos-amd64-generic-rel-vm-tests': 'cros_chrome_sdk_headless_ozone_dcheck_always_on',
       'chromeos-kevin-rel-hw-tests': 'cros_chrome_sdk_headless_ozone',
       'chromeos-vm-code-coverage': 'cros_chrome_sdk_headless_ozone_coverage',
+      'linux-chromeos-code-coverage': 'chromeos_with_codecs_release_bot_coverage',
 
       'Linux Builder Goma Canary': 'release_bot',
       'Linux Builder Goma Latest Client': 'release_bot',
@@ -349,6 +350,7 @@
       'Android FYI Release (Nexus 6P)': 'gpu_tests_android_release_trybot_arm64',
       'Android FYI Release (Nexus 9)': 'gpu_tests_android_release_trybot_arm64',
       'Android FYI Release (NVIDIA Shield TV)': 'gpu_tests_android_release_trybot_arm64',
+      'Android FYI Release (Pixel 2)': 'gpu_tests_android_release_trybot',
       'Android FYI 32 Vk Release (Nexus 5X)': 'gpu_tests_android_vulkan_release_trybot',
       'Android FYI 32 Vk Release (Pixel 2)': 'gpu_tests_android_vulkan_release_trybot',
       'Android FYI 32 Vk Release (Pixel XL)': 'gpu_tests_android_vulkan_release_trybot',
@@ -622,6 +624,7 @@
       'gpu-manual-try-android-m-nexus-6p-64': 'gpu_tests_android_release_trybot_arm64',
       'gpu-manual-try-android-m-nexus-9-64': 'gpu_tests_android_release_trybot_arm64',
       'gpu-manual-try-android-n-nvidia-shield-tv-64': 'gpu_tests_android_release_trybot_arm64',
+      'gpu-manual-try-android-p-pixel-2-32': 'gpu_tests_android_release_trybot',
       'gpu-manual-try-android-p-pixel-2-32-vk': 'gpu_tests_android_vulkan_release_trybot',
       'gpu-manual-try-android-p-pixel-2-32-deqp-vk': 'deqp_android_vulkan_release_trybot',
       'gpu-manual-try-android-p-pixel-2-64-vk': 'gpu_tests_android_vulkan_release_trybot_arm64',
@@ -1170,6 +1173,10 @@
       'chromeos_with_codecs', 'release_bot', 'use_vaapi',
     ],
 
+    'chromeos_with_codecs_release_bot_coverage': [
+      'chromeos_with_codecs', 'release_bot', 'use_vaapi', 'use_clang_coverage',
+    ],
+
     'chromeos_with_codecs_release_trybot': [
       'chromeos_with_codecs', 'release_trybot', 'use_vaapi', 'no_symbols',
     ],
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 568c3371..b14c7931 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -31700,6 +31700,7 @@
   <int value="-1720653947" label="WebRtcHybridAgc:disabled"/>
   <int value="-1719833926" label="disable-answers-in-suggest"/>
   <int value="-1716654100" label="tab-capture-downscale-quality"/>
+  <int value="-1716140224" label="EnableEmbeddedAssistantUI:disabled"/>
   <int value="-1715180530"
       label="OmniboxUIExperimentShowSuffixOnAllSearchSuggestions:disabled"/>
   <int value="-1714128884" label="disable-launcher-search-provider-api"/>
@@ -33320,6 +33321,7 @@
   <int value="941036016" label="ContentSuggestionsSettings:disabled"/>
   <int value="941883332" label="ProactiveTabFreezeAndDiscard:disabled"/>
   <int value="943319566" label="enable-intent-picker"/>
+  <int value="944484780" label="EnableEmbeddedAssistantUI:enabled"/>
   <int value="946185008" label="EnableAppDataSearch:disabled"/>
   <int value="946688335" label="OmniboxSpareRenderer:disabled"/>
   <int value="952558794" label="enable-remote-assistance"/>
@@ -50452,12 +50454,23 @@
 </enum>
 
 <enum name="SpareWebContentsStatus">
+  <obsolete>
+    Superseded by SpareWebContentsStatus2 as of 03/2019.
+  </obsolete>
   <int value="0" label="Created"/>
   <int value="1" label="Used"/>
   <int value="2" label="Render process gone"/>
   <int value="3" label="Destroyed"/>
 </enum>
 
+<enum name="SpareWebContentsStatus2">
+  <int value="0" label="Created"/>
+  <int value="1" label="Used"/>
+  <int value="2" label="Render process gone"/>
+  <int value="3" label="Destroyed"/>
+  <int value="4" label="Stolen"/>
+</enum>
+
 <enum name="SpdyFrameFlowControlState">
   <int value="0" label="Send not stalled"/>
   <int value="1" label="Send stalled by stream"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 8e12354..30d39622 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -13561,6 +13561,18 @@
   </summary>
 </histogram>
 
+<histogram base="true" name="Browser.Tabs.TotalSwitchDuration" units="ms"
+    expires_after="2019-08-31">
+<!-- Name completed by histogram_suffixes name="TabSwitchingTime" -->
+
+  <owner>ejoe@google.com</owner>
+  <owner>jonross@chromium.com</owner>
+  <summary>
+    The time between the input event timestamp and the frame presentation time
+    on a tab switch.
+  </summary>
+</histogram>
+
 <histogram name="BrowserActions.NumTabCreatedInBackground" units="tabNum">
   <owner>peconn@chromium.org</owner>
   <summary>
@@ -128871,6 +128883,28 @@
   </summary>
 </histogram>
 
+<histogram name="WebAudio.AudioContextOptions.sampleRate" units="Hz"
+    expires_after="2019-09-08">
+  <owner>rtoy@chromium.org</owner>
+  <owner>hongchan@chromium.org</owner>
+  <summary>
+    The sample rate requested by developer to be used as the sample rate when
+    constructing an AudioContext with an AudioContextOptions dictionary. This is
+    recorded for each AudioContext created, probably just one or two per page.
+  </summary>
+</histogram>
+
+<histogram name="WebAudio.AudioContextOptions.sampleRateRatio"
+    expires_after="2019-09-08">
+  <owner>rtoy@chromium.org</owner>
+  <owner>hongchan@chromium.org</owner>
+  <summary>
+    The ratio of the user-selected sample rate to the hardware sample rate of an
+    AudioContext. The ratio is represented as a percentage. This is recorded for
+    each AudioContext created, probably just one or two per page.
+  </summary>
+</histogram>
+
 <histogram name="WebAudio.AudioDestination.CallbackBufferSize">
   <owner>rtoy@chromium.org</owner>
   <owner>hongchan@chromium.org</owner>
@@ -148090,6 +148124,18 @@
   <affected-histogram name="Tabs.UsedInInterval.Count"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="TabSwitchingTime" separator=".">
+  <suffix name="NoSavedFrames"
+      label="The time from the input timestamp on a tab switch, until the
+             frame is presented on the screen when there is no saved frame in
+             the cache."/>
+  <suffix name="WithSavedFrames"
+      label="The time from the input timestamp on a tab switch, until the
+             frame is presented on the screen when there are saved frames in
+             the cache."/>
+  <affected-histogram name="Browser.Tabs.TotalSwitchDuration"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="TabSwitchInputLatency" separator=".">
   <suffix name="Keyboard"
       label="The time it takes from receiving a keyboard input event that
diff --git a/tools/perf/cli_tools/update_wpr/update_wpr.py b/tools/perf/cli_tools/update_wpr/update_wpr.py
index d7f0879..ee8faaf 100644
--- a/tools/perf/cli_tools/update_wpr/update_wpr.py
+++ b/tools/perf/cli_tools/update_wpr/update_wpr.py
@@ -112,44 +112,6 @@
         cli_helpers.Info('    %-26s%s' % ('[%s]:' % line[0], line[2]))
 
 
-def _PrintRunInfo(out_file, results_details=True):
-  try:
-    if results_details:
-      _PrintResultsHTMLInfo(out_file)
-  except Exception as e:
-    cli_helpers.Error('Could not print results.html tests: %s' % e)
-
-  def shell(cmd):
-    return subprocess.check_output(cmd, shell=True).rstrip()
-
-  def statsFor(name, filters='wc -l'):
-    cmd = 'grep "DevTools console .%s." "%s"' % (name, out_file)
-    cmd += ' | ' + filters
-    output = shell(cmd) or '0'
-    if len(output) > 7:
-      cli_helpers.Info('    %-26s%s' % ('[%s]:' % name, cmd))
-      cli_helpers.Info('      ' + output.replace('\n', '\n      '))
-    else:
-      cli_helpers.Info('    %-16s%-8s  %s' % ('[%s]:' % name, output, cmd))
-
-  cli_helpers.Info('Stdout/Stderr Log: %s' % out_file)
-  cli_helpers.Info('Chrome Log: %s.chrome.log' % out_file)
-  cli_helpers.Info(
-      '    Total output:   %s' %
-      subprocess.check_output(['wc', '-l', out_file]).rstrip())
-  cli_helpers.Info(
-      '    Total Console:  %s' %
-      shell('grep "DevTools console" "%s" | wc -l' % out_file))
-  statsFor('security')
-  statsFor('network', 'cut -d " " -f 20- | sort | uniq -c | sort -nr')
-
-  chrome_log = '%s.chrome.log' % out_file
-  if os.path.isfile(chrome_log):
-    cmd = 'grep "Uncaught .*Error" "%s"' % chrome_log
-    count = shell(cmd + '| wc -l')
-    cli_helpers.Info('    %-16s%-8s  %s' % ('[javascript]:', count, cmd))
-
-
 def _UploadArchiveToGoogleStorage(archive):
   """Uploads specified WPR archive to the GS."""
   cli_helpers.Run([
@@ -244,7 +206,7 @@
     if self._IsDesktop():
       args.append('system_health.memory_desktop')
     else:
-      args.extend('system_health.memory_mobile')
+      args.extend(['system_health.memory_mobile', '--device={device_id}'])
 
 
     args.extend([
@@ -257,9 +219,48 @@
       args.append('--use-live-sites')
     out_file = self._CheckLog(args, log_name=log_name)
     self._ExtractResultsFile(out_file)
-    _ExtractLogFile(out_file)
+    if self._IsDesktop():  # Mobile test runner does not product the log file.
+      _ExtractLogFile(out_file)
     return out_file
 
+  def _PrintRunInfo(self, out_file, results_details=True):
+    try:
+      if results_details:
+        _PrintResultsHTMLInfo(out_file)
+    except Exception as e:
+      cli_helpers.Error('Could not print results.html tests: %s' % e)
+
+    def shell(cmd):
+      return subprocess.check_output(cmd, shell=True).rstrip()
+
+    def statsFor(name, filters='wc -l'):
+      cmd = 'grep "DevTools console .%s." "%s"' % (name, out_file)
+      cmd += ' | ' + filters
+      output = shell(cmd) or '0'
+      if len(output) > 7:
+        cli_helpers.Info('    %-26s%s' % ('[%s]:' % name, cmd))
+        cli_helpers.Info('      ' + output.replace('\n', '\n      '))
+      else:
+        cli_helpers.Info('    %-16s%-8s  %s' % ('[%s]:' % name, output, cmd))
+
+    cli_helpers.Info('Stdout/Stderr Log: %s' % out_file)
+    if self._IsDesktop():  # Mobile test runner does not product the log file.
+      cli_helpers.Info('Chrome Log: %s.chrome.log' % out_file)
+    cli_helpers.Info(
+        '    Total output:   %s' %
+        subprocess.check_output(['wc', '-l', out_file]).rstrip())
+    cli_helpers.Info(
+        '    Total Console:  %s' %
+        shell('grep "DevTools console" "%s" | wc -l' % out_file))
+    statsFor('security')
+    statsFor('network', 'cut -d " " -f 20- | sort | uniq -c | sort -nr')
+
+    chrome_log = '%s.chrome.log' % out_file
+    if os.path.isfile(chrome_log):
+      cmd = 'grep "Uncaught .*Error" "%s"' % chrome_log
+      count = shell(cmd + '| wc -l')
+      cli_helpers.Info('    %-16s%-8s  %s' % ('[javascript]:', count, cmd))
+
   def _GetBranchIssueUrl(self):
     output_file = os.path.join(self.output_dir, 'git_cl_issue.json')
     subprocess.check_output(['git', 'cl', 'issue', '--json', output_file])
@@ -337,7 +338,7 @@
     cli_helpers.Step('LIVE RUN: %s' % self.story)
     out_file = self._RunSystemHealthMemoryBenchmark(
         log_name='live', live=True)
-    _PrintRunInfo(out_file)
+    self._PrintRunInfo(out_file)
     return out_file
 
   def Cleanup(self):
@@ -357,13 +358,13 @@
     else:
       args.extend(['--device={device_id}', 'mobile_system_health_story_set'])
     out_file = self._CheckLog(args, log_name='record')
-    _PrintRunInfo(out_file, results_details=False)
+    self._PrintRunInfo(out_file, results_details=False)
 
   def ReplayWpr(self):
     cli_helpers.Step('REPLAY WPR: %s' % self.story)
     out_file = self._RunSystemHealthMemoryBenchmark(
         log_name='replay', live=False)
-    _PrintRunInfo(out_file)
+    self._PrintRunInfo(out_file)
     return out_file
 
   def UploadWpr(self):
@@ -384,7 +385,8 @@
           'with tools/perf/update_wpr script' % self.story)
     if self.bug_id:
       commit_message += '\n\nBug: %s' % self.bug_id
-    cli_helpers.Run(['git', 'commit', '-a', '-m', commit_message])
+    if subprocess.call(['git', 'diff', '--quiet']):
+      cli_helpers.Run(['git', 'commit', '-a', '-m', commit_message])
     commit_msg_file = os.path.join(self.output_dir, 'commit_message.tmp')
     with open(commit_msg_file, 'w') as fd:
       fd.write(commit_message)
diff --git a/tools/perf/cli_tools/update_wpr/update_wpr_unittest.py b/tools/perf/cli_tools/update_wpr/update_wpr_unittest.py
index 26d6bb0..a875a38f 100644
--- a/tools/perf/cli_tools/update_wpr/update_wpr_unittest.py
+++ b/tools/perf/cli_tools/update_wpr/update_wpr_unittest.py
@@ -165,7 +165,7 @@
 
   @mock.patch(WPR_UPDATER + 'WprUpdater._RunSystemHealthMemoryBenchmark',
               return_value='<out-file>')
-  @mock.patch(WPR_UPDATER + '_PrintRunInfo')
+  @mock.patch(WPR_UPDATER + 'WprUpdater._PrintRunInfo')
   def testLiveRun(self, print_run_info, run_benchmark):
     self.wpr_updater.LiveRun()
     run_benchmark.assert_called_once_with(log_name='live', live=True)
@@ -223,7 +223,7 @@
   @mock.patch(WPR_UPDATER + '_PrintResultsHTMLInfo', side_effect=[Exception()])
   def testPrintRunInfo(self, print_results):
     self._check_output.return_value = '0\n'
-    update_wpr._PrintRunInfo('<outfile>', True)
+    self.wpr_updater._PrintRunInfo('<outfile>', True)
     print_results.assert_called_once_with('<outfile>')
     self.assertListEqual(self._info.mock_calls, [
       mock.call('Stdout/Stderr Log: <outfile>'),
@@ -255,7 +255,7 @@
       mock.call('.../data/dir/<archive>.sha1'),
     ])
 
-  @mock.patch(WPR_UPDATER + '_PrintRunInfo')
+  @mock.patch(WPR_UPDATER + 'WprUpdater._PrintRunInfo')
   @mock.patch(WPR_UPDATER + 'WprUpdater._DeleteExistingWpr')
   def testRecordWprDesktop(self, delete_existing_wpr, print_run_info):
     del delete_existing_wpr, print_run_info  # Unused.
@@ -265,7 +265,7 @@
       '--browser=system', 'desktop_system_health_story_set'
     ], env={'LC_ALL': 'en_US.UTF-8'}, log_path='/tmp/dir/record_<tstamp>')
 
-  @mock.patch(WPR_UPDATER + '_PrintRunInfo')
+  @mock.patch(WPR_UPDATER + 'WprUpdater._PrintRunInfo')
   @mock.patch(WPR_UPDATER + 'WprUpdater._DeleteExistingWpr')
   def testRecordWprMobile(self, delete_existing_wpr, print_run_info):
     del delete_existing_wpr, print_run_info  # Unused.
@@ -277,7 +277,7 @@
       'mobile_system_health_story_set'
     ], env={'LC_ALL': 'en_US.UTF-8'}, log_path='/tmp/dir/record_<tstamp>')
 
-  @mock.patch(WPR_UPDATER + '_PrintRunInfo')
+  @mock.patch(WPR_UPDATER + 'WprUpdater._PrintRunInfo')
   @mock.patch(WPR_UPDATER + 'WprUpdater._RunSystemHealthMemoryBenchmark',
               return_value='<out-file>')
   def testReplayWpr(self, run_benchmark, print_run_info):
@@ -296,7 +296,9 @@
       mock.call(['git', 'add', '<archive>.sha1'])
     ])
 
-  def testUploadCL(self):
+  @mock.patch('subprocess.call', return_value=1)
+  def testUploadCL(self, subprocess_call):
+    del subprocess_call  # Unused.
     self._run.return_value = 42
     self.assertEqual(self.wpr_updater.UploadCL(), 42)
     self.assertListEqual(self._run.mock_calls, [
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index 1cc04c4..25e771bd 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -100,7 +100,6 @@
         }
       ],
       'platform': 'android-chrome',
-      'browser': 'bin/monochrome_64_32_bundle',
       'dimension': {
         'pool': 'chrome.tests.perf-fyi',
         'os': 'Android',
@@ -911,8 +910,6 @@
   # For trybot testing we always use the reference build
   if tester_config.get('testing', False):
     browser_name = 'reference'
-  elif 'browser' in tester_config:
-    browser_name = 'exact'
   elif tester_config['platform'] == 'android':
     browser_name = 'android-chromium'
   elif tester_config['platform'].startswith('android-'):
@@ -929,13 +926,7 @@
     '--upload-results'
   ]
 
-  if 'browser' in tester_config:
-    test_args.append('--browser-executable=../../out/Release/%s' %
-                     tester_config['browser'])
-    if tester_config['platform'].startswith('android'):
-      test_args.append('--device=android')
-
-  if tester_config['platform'].startswith('android-webview'):
+  if browser_name.startswith('android-webview'):
     test_args.append(
         '--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk')
 
diff --git a/tools/perf/core/perf_data_generator_unittest.py b/tools/perf/core/perf_data_generator_unittest.py
index 7697b49..3f326e7 100644
--- a/tools/perf/core/perf_data_generator_unittest.py
+++ b/tools/perf/core/perf_data_generator_unittest.py
@@ -97,61 +97,6 @@
       }
     self.assertEquals(returned_test, expected_generated_test)
 
-  def testGeneratePerformanceTestSuiteExact(self):
-    swarming_dimensions = [
-        {'os': 'SkyNet', 'pool': 'T-RIP'}
-    ]
-    test_config = {
-        'platform': 'android-webview',
-        'browser': 'bin/monochrome_64_32_bundle',
-        'dimension': swarming_dimensions,
-    }
-    test = {
-        'isolate': 'performance_test_suite',
-        'extra_args': [
-            '--run-ref-build',
-            '--test-shard-map-filename=shard_map.json',
-          ],
-        'num_shards': 26
-    }
-    returned_test = perf_data_generator.generate_performance_test(
-        test_config, test)
-
-    expected_generated_test = {
-        'override_compile_targets': ['performance_test_suite'],
-        'isolate_name': 'performance_test_suite',
-        'args': ['-v', '--browser=exact', '--upload-results',
-                 '--browser-executable=../../out/Release'
-                 '/bin/monochrome_64_32_bundle',
-                 '--device=android',
-                 '--webview-embedder-apk=../../out/Release'
-                 '/apks/SystemWebViewShell.apk',
-                 '--run-ref-build',
-                 '--test-shard-map-filename=shard_map.json'],
-        'trigger_script': {
-          'args': [
-            '--multiple-dimension-script-verbose',
-            'True'
-          ],
-          'requires_simultaneous_shard_dispatch': True,
-          'script': '//testing/trigger_scripts/perf_device_trigger.py'
-        },
-        'merge': {
-          'script': '//tools/perf/process_perf_results.py'
-        },
-        'swarming': {
-          'ignore_task_failure': False,
-          'can_use_on_swarming_builders': True,
-          'expiration': 7200,
-          'io_timeout': 1800,
-          'hard_timeout': 36000,
-          'dimension_sets': [[{'os': 'SkyNet', 'pool': 'T-RIP'}]],
-          'shards': 26
-        },
-        'name': 'performance_test_suite'
-      }
-    self.assertEquals(returned_test, expected_generated_test)
-
   def testGeneratePerformanceTestSuiteWebview(self):
     swarming_dimensions = [
         {'os': 'SkyNet', 'pool': 'T-RIP'}
diff --git a/tools/perf/core/perf_json_config_validator.py b/tools/perf/core/perf_json_config_validator.py
index 7ace5f3..df7cd111 100644
--- a/tools/perf/core/perf_json_config_validator.py
+++ b/tools/perf/core/perf_json_config_validator.py
@@ -81,18 +81,17 @@
   browser_options = _ParseBrowserFlags(test_config['args'])
   if 'WebView' in builder_name or 'webview' in builder_name:
     if browser_options.browser not in (
-        'android-webview', 'android-webview-google', 'exact'):
+        'android-webview', 'android-webview-google'):
       raise ValueError(
-          "%s must use 'android-webview', 'android-webview-google' or 'exact' "
-          "browser" % builder_name)
+          "%s must use 'android-webview' or 'android-webview-google' browser" %
+          builder_name)
     if not browser_options.webview_embedder_apk:
       raise ValueError('%s must set --webview-embedder-apk flag' % builder_name)
   elif 'Android' in builder_name or 'android' in builder_name:
-    if browser_options.browser not in (
-        'android-chromium', 'android-chrome', 'exact'):
+    if browser_options.browser not in ('android-chromium', 'android-chrome'):
       raise ValueError(
-          "%s must use 'android-chromium', 'android-chrome' or 'exact' "
-          "browser" % builder_name)
+          "%s must use 'android-chromium' or 'android-chrome' browser" %
+          builder_name)
   elif builder_name in ('win-10-perf', 'Win 7 Nvidia GPU Perf'):
     if browser_options.browser != 'release_x64':
       raise ValueError("%s must use 'release_x64' browser type" %
diff --git a/ui/android/display_android_manager.cc b/ui/android/display_android_manager.cc
index fc3407b..8509bd7b 100644
--- a/ui/android/display_android_manager.cc
+++ b/ui/android/display_android_manager.cc
@@ -21,18 +21,20 @@
 using display::Display;
 using display::DisplayList;
 
-void SetScreenAndroid() {
+void SetScreenAndroid(bool use_display_wide_color_gamut) {
   // Do not override existing Screen.
   DCHECK_EQ(display::Screen::GetScreen(), nullptr);
 
-  DisplayAndroidManager* manager = new DisplayAndroidManager();
+  DisplayAndroidManager* manager =
+      new DisplayAndroidManager(use_display_wide_color_gamut);
   display::Screen::SetScreenInstance(manager);
 
   JNIEnv* env = AttachCurrentThread();
   Java_DisplayAndroidManager_onNativeSideCreated(env, (jlong)manager);
 }
 
-DisplayAndroidManager::DisplayAndroidManager() {}
+DisplayAndroidManager::DisplayAndroidManager(bool use_display_wide_color_gamut)
+    : use_display_wide_color_gamut_(use_display_wide_color_gamut) {}
 
 DisplayAndroidManager::~DisplayAndroidManager() {}
 
@@ -79,9 +81,11 @@
   if (!Display::HasForceDeviceScaleFactor())
     display->set_device_scale_factor(dipScale);
   if (!Display::HasForceDisplayColorProfile()) {
-    // TODO(ccameron): Use CreateDisplayP3D65 if isWideColorGamut is true, once
-    // the feature is ready to use.
-    display->set_color_space(gfx::ColorSpace::CreateSRGB());
+    if (isWideColorGamut) {
+      display->set_color_space(gfx::ColorSpace::CreateDisplayP3D65());
+    } else {
+      display->set_color_space(gfx::ColorSpace::CreateSRGB());
+    }
   }
 
   display->set_size_in_pixels(size_in_pixels);
@@ -110,7 +114,8 @@
 
   display::Display display(sdkDisplayId, bounds_in_dip);
   DoUpdateDisplay(&display, bounds_in_pixels.size(), dipScale, rotationDegrees,
-                  bitsPerPixel, bitsPerComponent, isWideColorGamut);
+                  bitsPerPixel, bitsPerComponent,
+                  isWideColorGamut && use_display_wide_color_gamut_);
   ProcessDisplayChanged(display, sdkDisplayId == primary_display_id_);
 }
 
diff --git a/ui/android/display_android_manager.h b/ui/android/display_android_manager.h
index f1fc6a49..e278624c 100644
--- a/ui/android/display_android_manager.h
+++ b/ui/android/display_android_manager.h
@@ -51,8 +51,8 @@
 
  private:
   friend class WindowAndroid;
-  friend void SetScreenAndroid();
-  DisplayAndroidManager();
+  friend void SetScreenAndroid(bool use_display_wide_color_gamut);
+  explicit DisplayAndroidManager(bool use_display_wide_color_gamut);
 
   static void DoUpdateDisplay(display::Display* display,
                               gfx::Size size_in_pixels,
@@ -62,6 +62,7 @@
                               int bitsPerComponent,
                               bool isWideColorGamut);
 
+  const bool use_display_wide_color_gamut_;
   int primary_display_id_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(DisplayAndroidManager);
diff --git a/ui/android/java/res/values/color_palette.xml b/ui/android/java/res/values/color_palette.xml
index 01e1ead..c1639897 100644
--- a/ui/android/java/res/values/color_palette.xml
+++ b/ui/android/java/res/values/color_palette.xml
@@ -44,6 +44,8 @@
     <color name="default_icon_color_white_pressed" tools:ignore="UnusedResources">
         @color/white_alpha_50
     </color>
+    <!-- Common text colors -->
+    <color name="default_text_color_dark">@color/modern_grey_900</color>
 
     <color name="default_red_light" tools:ignore="UnusedResources">@color/google_red_300</color>
     <color name="default_red_dark" tools:ignore="UnusedResources">@color/google_red_700</color>
diff --git a/ui/android/java/res/values/colors.xml b/ui/android/java/res/values/colors.xml
index afaecd83..fc5fd39 100644
--- a/ui/android/java/res/values/colors.xml
+++ b/ui/android/java/res/values/colors.xml
@@ -7,7 +7,7 @@
 <resources xmlns:tools="http://schemas.android.com/tools">
     <!-- TODO(huayinz): remove tools:ignore once these colors are used in ui/android -->
     <!-- Common text colors -->
-    <color name="default_text_color">@color/modern_grey_900</color>
+    <color name="default_text_color">@color/default_text_color_dark</color>
     <color name="default_text_color_secondary">@color/modern_grey_700</color>
     <!-- Text color for non-clickable blue text. -->
     <color name="default_text_color_blue" tools:ignore="UnusedResources">@color/modern_blue_600</color>
diff --git a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
index 7889bdd..f0b667d 100644
--- a/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/base/WindowAndroid.java
@@ -55,14 +55,6 @@
 public class WindowAndroid implements AndroidPermissionDelegate, DisplayAndroidObserver {
     private static final String TAG = "WindowAndroid";
 
-    // Allow client to control whether wide gamut is enabled.
-    private static boolean sEnableWideColorGamut;
-
-    public static void enableWideColorGamut() {
-        assert !sEnableWideColorGamut;
-        sEnableWideColorGamut = true;
-    }
-
     private KeyboardVisibilityDelegate mKeyboardVisibilityDelegate =
             KeyboardVisibilityDelegate.getInstance();
 
@@ -707,7 +699,6 @@
     // gamut (on supported hardware and os). However it is important for embedders like WebView
     // which do not make the wide gamut decision to check this at run time.
     private boolean getWindowIsWideColorGamut() {
-        if (!sEnableWideColorGamut) return false;
         if (!BuildInfo.isAtLeastQ()) return false;
         Window window = getWindow();
         if (window == null) return false;
diff --git a/ui/android/screen_android.h b/ui/android/screen_android.h
index 1482223..4e61a2c 100644
--- a/ui/android/screen_android.h
+++ b/ui/android/screen_android.h
@@ -10,7 +10,7 @@
 
 namespace ui {
 
-UI_ANDROID_EXPORT void SetScreenAndroid();
+UI_ANDROID_EXPORT void SetScreenAndroid(bool use_display_wide_color_gamut);
 
 }  // namespace display
 
diff --git a/ui/android/window_android.cc b/ui/android/window_android.cc
index fff35c2..c5bd4f5 100644
--- a/ui/android/window_android.cc
+++ b/ui/android/window_android.cc
@@ -396,9 +396,6 @@
       &display, display.GetSizeInPixel(), display.device_scale_factor(),
       display.RotationAsDegree(), display.color_depth(),
       display.depth_per_component(), window_is_wide_color_gamut_);
-  if (window_is_wide_color_gamut_) {
-    display.set_color_space(gfx::ColorSpace::CreateDisplayP3D65());
-  }
   return display;
 }
 
diff --git a/ui/aura/mus/property_converter.cc b/ui/aura/mus/property_converter.cc
index dd9cd90..cee64d4 100644
--- a/ui/aura/mus/property_converter.cc
+++ b/ui/aura/mus/property_converter.cc
@@ -76,6 +76,8 @@
                             ws::mojom::WindowManager::kAppIconLarge_Property);
   RegisterImageSkiaProperty(client::kAppIconSmallKey,
                             ws::mojom::WindowManager::kAppIconSmall_Property);
+  RegisterImageSkiaProperty(client::kAvatarIconKey,
+                            ws::mojom::WindowManager::kAvatarIcon_Property);
   RegisterPrimitiveProperty(client::kAlwaysOnTopKey,
                             ws::mojom::WindowManager::kAlwaysOnTop_Property,
                             CreateAcceptAnyValueCallback());
diff --git a/ui/aura/mus/window_port_mus.cc b/ui/aura/mus/window_port_mus.cc
index 75baf1fd..8b4c1ba 100644
--- a/ui/aura/mus/window_port_mus.cc
+++ b/ui/aura/mus/window_port_mus.cc
@@ -137,7 +137,7 @@
 }
 
 void WindowPortMus::SetCursor(const ui::Cursor& cursor) {
-  if (cursor_.IsSameAs(cursor))
+  if (cursor == cursor_)
     return;
 
   window_tree_client_->SetCursor(this, cursor_, cursor);
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc
index 714ef6e..69ac7c3 100644
--- a/ui/aura/mus/window_tree_client.cc
+++ b/ui/aura/mus/window_tree_client.cc
@@ -236,8 +236,10 @@
 void WindowTreeClient::SetCursor(WindowMus* window,
                                  const ui::Cursor& old_cursor,
                                  const ui::Cursor& new_cursor) {
-  DCHECK(tree_);
+  if (old_cursor == new_cursor)
+    return;
 
+  DCHECK(tree_);
   const uint32_t change_id = ScheduleInFlightChange(
       std::make_unique<InFlightCursorChange>(window, old_cursor));
   tree_->SetCursor(change_id, window->server_id(), new_cursor);
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 43bfcf4..085ef60 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -908,6 +908,7 @@
       "cocoa/touch_bar_util_unittest.mm",
       "cocoa/tracking_area_unittest.mm",
       "cocoa/weak_ptr_nsobject_unittest.mm",
+      "cursor/cursor_unittest.cc",
       "cursor/cursor_util_unittest.cc",
       "models/list_model_unittest.cc",
       "models/list_selection_model_unittest.cc",
diff --git a/ui/base/cursor/cursor.cc b/ui/base/cursor/cursor.cc
index 1ed7f1b9..6dc54dc 100644
--- a/ui/base/cursor/cursor.cc
+++ b/ui/base/cursor/cursor.cc
@@ -5,23 +5,20 @@
 #include "ui/base/cursor/cursor.h"
 
 #include "base/logging.h"
+#include "ui/gfx/skia_util.h"
 
 namespace ui {
 
-Cursor::Cursor()
-    : native_type_(CursorType::kNull),
-      platform_cursor_(0),
-      device_scale_factor_(0.0f) {}
+Cursor::Cursor() = default;
 
-Cursor::Cursor(CursorType type)
-    : native_type_(type), platform_cursor_(0), device_scale_factor_(0.0f) {}
+Cursor::Cursor(CursorType type) : native_type_(type) {}
 
 Cursor::Cursor(const Cursor& cursor)
     : native_type_(cursor.native_type_),
       platform_cursor_(cursor.platform_cursor_),
       device_scale_factor_(cursor.device_scale_factor_),
-      custom_bitmap_(cursor.custom_bitmap_),
-      custom_hotspot_(cursor.custom_hotspot_) {
+      custom_hotspot_(cursor.custom_hotspot_),
+      custom_bitmap_(cursor.custom_bitmap_) {
   if (native_type_ == CursorType::kCustom)
     RefCustomCursor();
 }
@@ -68,15 +65,18 @@
 #endif
 }
 
-bool Cursor::IsSameAs(const Cursor& rhs) const {
-  return native_type_ == rhs.native_type_ &&
-         custom_hotspot_ == rhs.custom_hotspot_ &&
-         device_scale_factor_ == rhs.device_scale_factor_ &&
-         custom_bitmap_.getGenerationID() ==
-             rhs.custom_bitmap_.getGenerationID();
+bool Cursor::operator==(const Cursor& cursor) const {
+  return native_type_ == cursor.native_type_ &&
+         platform_cursor_ == cursor.platform_cursor_ &&
+         device_scale_factor_ == cursor.device_scale_factor_ &&
+         custom_hotspot_ == cursor.custom_hotspot_ &&
+         (native_type_ != CursorType::kCustom ||
+          custom_bitmap_.getGenerationID() ==
+              cursor.custom_bitmap_.getGenerationID() ||
+          gfx::BitmapsAreEqual(custom_bitmap_, cursor.custom_bitmap_));
 }
 
-void Cursor::Assign(const Cursor& cursor) {
+void Cursor::operator=(const Cursor& cursor) {
   if (*this == cursor)
     return;
   if (native_type_ == CursorType::kCustom)
@@ -86,8 +86,8 @@
   if (native_type_ == CursorType::kCustom)
     RefCustomCursor();
   device_scale_factor_ = cursor.device_scale_factor_;
-  custom_bitmap_ = cursor.custom_bitmap_;
   custom_hotspot_ = cursor.custom_hotspot_;
+  custom_bitmap_ = cursor.custom_bitmap_;
 }
 
 }  // namespace ui
diff --git a/ui/base/cursor/cursor.h b/ui/base/cursor/cursor.h
index 06b5510a9..d95ad138d 100644
--- a/ui/base/cursor/cursor.h
+++ b/ui/base/cursor/cursor.h
@@ -47,12 +47,8 @@
 
   CursorType native_type() const { return native_type_; }
   PlatformCursor platform() const { return platform_cursor_; }
-  float device_scale_factor() const {
-    return device_scale_factor_;
-  }
-  void set_device_scale_factor(float device_scale_factor) {
-    device_scale_factor_ = device_scale_factor;
-  }
+  float device_scale_factor() const { return device_scale_factor_; }
+  void set_device_scale_factor(float scale) { device_scale_factor_ = scale; }
 
   SkBitmap GetBitmap() const;
   void set_custom_bitmap(const SkBitmap& bitmap) { custom_bitmap_ = bitmap; }
@@ -62,65 +58,35 @@
     custom_hotspot_ = hotspot;
   }
 
+  // Note: custom cursor comparison may perform expensive pixel equality checks!
+  bool operator==(const Cursor& cursor) const;
+  bool operator!=(const Cursor& cursor) const { return !(*this == cursor); }
+
   bool operator==(CursorType type) const { return native_type_ == type; }
-  bool operator==(const Cursor& cursor) const {
-    return native_type_ == cursor.native_type_ &&
-           platform_cursor_ == cursor.platform_cursor_ &&
-           device_scale_factor_ == cursor.device_scale_factor_ &&
-           custom_bitmap_.info() == cursor.custom_bitmap_.info() &&
-           custom_bitmap_.rowBytes() == cursor.custom_bitmap_.rowBytes() &&
-           custom_bitmap_.getPixels() == cursor.custom_bitmap_.getPixels() &&
-           custom_hotspot_ == cursor.custom_hotspot_;
-  }
   bool operator!=(CursorType type) const { return native_type_ != type; }
-  bool operator!=(const Cursor& cursor) const {
-    return native_type_ != cursor.native_type_ ||
-           platform_cursor_ != cursor.platform_cursor_ ||
-           device_scale_factor_ != cursor.device_scale_factor_ ||
-           custom_bitmap_.info() != cursor.custom_bitmap_.info() ||
-           custom_bitmap_.rowBytes() != cursor.custom_bitmap_.rowBytes() ||
-           custom_bitmap_.getPixels() != cursor.custom_bitmap_.getPixels() ||
-           custom_hotspot_ != cursor.custom_hotspot_;
-  }
 
-  void operator=(const Cursor& cursor) {
-    Assign(cursor);
-  }
-
-  // Checks if the data in |rhs| was created from the same input data.
-  //
-  // This is subtly different from operator==, as we need this to be a
-  // lightweight operation instead of performing pixel equality checks on
-  // arbitrary sized SkBitmaps. So we check the internal SkBitmap generation
-  // IDs, which are per-process, monotonically increasing ids which get changed
-  // whenever there's a modification to the pixel data. This means that this
-  // method can have false negatives: two SkBitmap instances made with the same
-  // input data (but which weren't copied from each other) can have equal pixel
-  // data, but different generation ids.
-  bool IsSameAs(const Cursor& rhs) const;
+  void operator=(const Cursor& cursor);
 
  private:
-  void Assign(const Cursor& cursor);
-
 #if defined(USE_AURA)
   SkBitmap GetDefaultBitmap() const;
   gfx::Point GetDefaultHotspot() const;
 #endif
 
-  // See definitions above.
-  CursorType native_type_;
+  // The basic cursor type.
+  CursorType native_type_ = CursorType::kNull;
 
-  PlatformCursor platform_cursor_;
+  // The native platform cursor.
+  PlatformCursor platform_cursor_ = 0;
 
   // The device scale factor for the cursor.
-  float device_scale_factor_;
+  float device_scale_factor_ = 0.0f;
 
-  // The bitmap for the cursor. This is only used when it is custom cursor type.
-  SkBitmap custom_bitmap_;
-
-  // The hotspot for the cursor. This is only used when it is custom cursor
-  // type.
+  // The hotspot for the cursor. This is only used for the custom cursor type.
   gfx::Point custom_hotspot_;
+
+  // The bitmap for the cursor. This is only used for the custom cursor type.
+  SkBitmap custom_bitmap_;
 };
 
 }  // namespace ui
diff --git a/ui/base/cursor/cursor_unittest.cc b/ui/base/cursor/cursor_unittest.cc
new file mode 100644
index 0000000..71685501
--- /dev/null
+++ b/ui/base/cursor/cursor_unittest.cc
@@ -0,0 +1,78 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/base/cursor/cursor.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/skia_util.h"
+
+namespace ui {
+namespace {
+
+TEST(CursorTest, Null) {
+  Cursor cursor;
+  EXPECT_EQ(CursorType::kNull, cursor.native_type());
+}
+
+TEST(CursorTest, BasicType) {
+  Cursor cursor(CursorType::kPointer);
+  EXPECT_EQ(CursorType::kPointer, cursor.native_type());
+
+  Cursor copy(cursor);
+  EXPECT_EQ(cursor, copy);
+}
+
+TEST(CursorTest, CustomType) {
+  Cursor cursor(CursorType::kCustom);
+  EXPECT_EQ(CursorType::kCustom, cursor.native_type());
+
+  const float kScale = 2.0f;
+  cursor.set_device_scale_factor(kScale);
+  EXPECT_EQ(kScale, cursor.device_scale_factor());
+
+  const gfx::Point kHotspot = gfx::Point(5, 2);
+  cursor.set_custom_hotspot(kHotspot);
+  EXPECT_EQ(kHotspot, cursor.GetHotspot());
+
+  SkBitmap bitmap;
+  bitmap.allocN32Pixels(10, 10);
+  bitmap.eraseColor(SK_ColorRED);
+  cursor.set_custom_bitmap(bitmap);
+
+  EXPECT_EQ(bitmap.getGenerationID(), cursor.GetBitmap().getGenerationID());
+  EXPECT_TRUE(gfx::BitmapsAreEqual(bitmap, cursor.GetBitmap()));
+
+  Cursor copy(cursor);
+  EXPECT_EQ(cursor.GetBitmap().getGenerationID(),
+            copy.GetBitmap().getGenerationID());
+  EXPECT_TRUE(gfx::BitmapsAreEqual(cursor.GetBitmap(), copy.GetBitmap()));
+  EXPECT_EQ(cursor, copy);
+}
+
+TEST(CursorTest, CustomTypeComparesBitmapPixels) {
+  Cursor cursor1(CursorType::kCustom);
+  Cursor cursor2(CursorType::kCustom);
+
+  SkBitmap bitmap1;
+  bitmap1.allocN32Pixels(10, 10);
+  bitmap1.eraseColor(SK_ColorRED);
+  cursor1.set_custom_bitmap(bitmap1);
+
+  SkBitmap bitmap2;
+  bitmap2.allocN32Pixels(10, 10);
+  bitmap2.eraseColor(SK_ColorRED);
+  cursor2.set_custom_bitmap(bitmap2);
+
+  EXPECT_NE(cursor1.GetBitmap().getGenerationID(),
+            cursor2.GetBitmap().getGenerationID());
+  EXPECT_TRUE(gfx::BitmapsAreEqual(cursor1.GetBitmap(), cursor2.GetBitmap()));
+  EXPECT_EQ(cursor1, cursor2);
+}
+
+}  // namespace
+}  // namespace ui
diff --git a/ui/base/mojo/cursor_struct_traits_unittest.cc b/ui/base/mojo/cursor_struct_traits_unittest.cc
index 1510471..f37f01bd 100644
--- a/ui/base/mojo/cursor_struct_traits_unittest.cc
+++ b/ui/base/mojo/cursor_struct_traits_unittest.cc
@@ -10,6 +10,7 @@
 #include "ui/base/cursor/cursor.h"
 #include "ui/base/mojo/cursor.mojom.h"
 #include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
+#include "ui/gfx/skia_util.h"
 
 namespace ui {
 
@@ -23,9 +24,9 @@
 
 }  // namespace
 
-// Tests numeric cursor ids.
+// Test that basic cursor structs are passed correctly across the wire.
 TEST_F(CursorStructTraitsTest, TestBuiltIn) {
-  for (int i = 0; i < 43; ++i) {
+  for (int i = 0; i < static_cast<int>(ui::CursorType::kCustom); ++i) {
     ui::CursorType type = static_cast<ui::CursorType>(i);
     ui::Cursor input(type);
 
@@ -35,7 +36,7 @@
   }
 }
 
-// Test that we copy cursor bitmaps and metadata across the wire.
+// Test that cursor bitmaps and metadata are passed correctly across the wire.
 TEST_F(CursorStructTraitsTest, TestBitmapCursor) {
   ui::Cursor input(ui::CursorType::kCustom);
 
@@ -51,35 +52,27 @@
   input.set_device_scale_factor(kScale);
 
   ui::Cursor output;
-  ASSERT_TRUE(EchoCursor(input, &output));
+  EXPECT_TRUE(EchoCursor(input, &output));
+  EXPECT_EQ(input, output);
 
   EXPECT_EQ(ui::CursorType::kCustom, output.native_type());
   EXPECT_EQ(kScale, output.device_scale_factor());
   EXPECT_EQ(kHotspot, output.GetHotspot());
 
-  // Even if the pixel data is logically the same, expect that it has different
-  // generation ids.
-  EXPECT_FALSE(output.IsSameAs(input));
+  // Even though the pixel data is the same, the bitmap generation ids differ.
+  EXPECT_TRUE(gfx::BitmapsAreEqual(input.GetBitmap(), output.GetBitmap()));
+  EXPECT_NE(input.GetBitmap().getGenerationID(),
+            output.GetBitmap().getGenerationID());
 
-  // Make a copy of output. It should be the same as output.
+  // Make a copy of output; the bitmap generation ids should be the same.
   ui::Cursor copy = output;
-  EXPECT_TRUE(copy.IsSameAs(output));
-
-  // But make sure that the pixel data actually is equivalent.
-  ASSERT_EQ(input.GetBitmap().width(), output.GetBitmap().width());
-  ASSERT_EQ(input.GetBitmap().height(), output.GetBitmap().height());
-
-  for (int x = 0; x < input.GetBitmap().width(); ++x) {
-    for (int y = 0; y < input.GetBitmap().height(); ++y) {
-      EXPECT_EQ(input.GetBitmap().getColor(x, y),
-                output.GetBitmap().getColor(x, y));
-    }
-  }
+  EXPECT_EQ(output.GetBitmap().getGenerationID(),
+            copy.GetBitmap().getGenerationID());
+  EXPECT_EQ(input, output);
 }
 
-// Test that we deal with empty bitmaps. (When a cursor resource isn't loaded
-// in the renderer, the renderer will send a custom cursor with an empty
-// bitmap.)
+// Test that empty bitmaps are passed correctly over the wire. This happens when
+// renderers relay a custom cursor before the bitmap resource is loaded.
 TEST_F(CursorStructTraitsTest, TestEmptyCursor) {
   const gfx::Point kHotspot = gfx::Point(5, 2);
   const float kScale = 2.0f;
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index 43acfc9..ccc2372b 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -215,6 +215,8 @@
   clone->SetVisible(GetTargetVisibility());
   clone->SetFillsBoundsOpaquely(fills_bounds_opaquely_);
   clone->SetFillsBoundsCompletely(fills_bounds_completely_);
+  clone->SetRoundedCornerRadius(rounded_corner_radii());
+  clone->SetIsFastRoundedCorner(is_fast_rounded_corner());
   clone->set_name(name_);
 
   return clone;
@@ -575,6 +577,17 @@
     const std::array<uint32_t, 4>& corner_radii) {
   cc_layer_->SetRoundedCorner(corner_radii);
   ScheduleDraw();
+
+  for (const auto& mirror : mirrors_)
+    mirror->dest()->SetRoundedCornerRadius(corner_radii);
+}
+
+void Layer::SetIsFastRoundedCorner(bool enable) {
+  cc_layer_->SetIsFastRoundedCorner(enable);
+  ScheduleDraw();
+
+  for (const auto& mirror : mirrors_)
+    mirror->dest()->SetIsFastRoundedCorner(enable);
 }
 
 // static
@@ -646,6 +659,8 @@
       cc_layer_->SafeOpaqueBackgroundColor());
   new_layer->SetCacheRenderSurface(cc_layer_->cache_render_surface());
   new_layer->SetTrilinearFiltering(cc_layer_->trilinear_filtering());
+  new_layer->SetRoundedCorner(cc_layer_->corner_radii());
+  new_layer->SetIsFastRoundedCorner(cc_layer_->is_fast_rounded_corner());
 
   cc_layer_ = new_layer.get();
   if (content_layer_) {
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h
index d8718b0..9f55961 100644
--- a/ui/compositor/layer.h
+++ b/ui/compositor/layer.h
@@ -277,6 +277,14 @@
     return cc_layer_->corner_radii();
   }
 
+  // If set to true, this layer would not trigger a render surface (if possible)
+  // due to having a rounded corner resulting in a better performance at the
+  // cost of maybe having some blending artifacts.
+  void SetIsFastRoundedCorner(bool enable);
+  bool is_fast_rounded_corner() const {
+    return cc_layer_->is_fast_rounded_corner();
+  }
+
   // Converts a point from the coordinates of |source| to the coordinates of
   // |target|. Necessarily, |source| and |target| must inhabit the same Layer
   // tree.
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc
index f3befcc3..7cca4fc 100644
--- a/ui/compositor/layer_unittest.cc
+++ b/ui/compositor/layer_unittest.cc
@@ -761,6 +761,8 @@
   layer->SetLayerInverted(true);
   layer->AddCacheRenderSurfaceRequest();
   layer->AddTrilinearFilteringRequest();
+  layer->SetRoundedCornerRadius({1, 2, 4, 5});
+  layer->SetIsFastRoundedCorner(true);
 
   auto clone = layer->Clone();
 
@@ -775,16 +777,23 @@
   // Cloning should not preserve trilinear_filtering flag.
   EXPECT_NE(layer->cc_layer_for_testing()->trilinear_filtering(),
             clone->cc_layer_for_testing()->trilinear_filtering());
+  EXPECT_EQ(layer->rounded_corner_radii(), clone->rounded_corner_radii());
+  EXPECT_EQ(layer->is_fast_rounded_corner(), clone->is_fast_rounded_corner());
 
   layer->SetTransform(gfx::Transform());
   layer->SetColor(SK_ColorGREEN);
   layer->SetLayerInverted(false);
+  layer->SetIsFastRoundedCorner(false);
+  layer->SetRoundedCornerRadius({3, 6, 9, 12});
 
   // The clone is an independent copy, so state changes do not propagate.
   EXPECT_EQ(transform, clone->GetTargetTransform());
   EXPECT_EQ(SK_ColorRED, clone->background_color());
   EXPECT_EQ(SK_ColorRED, clone->GetTargetColor());
   EXPECT_TRUE(clone->layer_inverted());
+  EXPECT_FALSE(layer->is_fast_rounded_corner());
+  EXPECT_TRUE(clone->is_fast_rounded_corner());
+  EXPECT_NE(layer->rounded_corner_radii(), clone->rounded_corner_radii());
 
   constexpr SkColor kTransparent = SK_ColorTRANSPARENT;
   layer->SetColor(kTransparent);
@@ -893,6 +902,16 @@
   child->set_sync_bounds(true);
   child->SetBounds(new_bounds);
   EXPECT_EQ(new_bounds, mirror->bounds());
+
+  // Check for rounded corner mirror behavior
+  constexpr std::array<uint32_t, 4> kEmptyCornerRadii = {0, 0, 0, 0};
+  EXPECT_EQ(mirror->rounded_corner_radii(), kEmptyCornerRadii);
+  EXPECT_FALSE(mirror->is_fast_rounded_corner());
+  constexpr std::array<uint32_t, 4> corner_radii = {2, 3, 4, 5};
+  child->SetRoundedCornerRadius(corner_radii);
+  child->SetIsFastRoundedCorner(true);
+  EXPECT_EQ(mirror->rounded_corner_radii(), corner_radii);
+  EXPECT_TRUE(mirror->is_fast_rounded_corner());
 }
 
 // Tests for SurfaceLayer cloning and mirroring. This tests certain properties
@@ -1000,11 +1019,18 @@
   l1->SetVisible(false);
   l1->SetBounds(gfx::Rect(4, 5));
 
+  constexpr std::array<uint32_t, 4> kCornerRadii = {1, 2, 3, 4};
+  l1->SetRoundedCornerRadius(kCornerRadii);
+  l1->SetIsFastRoundedCorner(true);
+
   EXPECT_EQ(gfx::Point3F(), l1->cc_layer_for_testing()->transform_origin());
   EXPECT_TRUE(l1->cc_layer_for_testing()->DrawsContent());
   EXPECT_TRUE(l1->cc_layer_for_testing()->contents_opaque());
   EXPECT_TRUE(l1->cc_layer_for_testing()->hide_layer_and_subtree());
   EXPECT_EQ(gfx::Size(4, 5), l1->cc_layer_for_testing()->bounds());
+  EXPECT_TRUE(l1->cc_layer_for_testing()->HasRoundedCorner());
+  EXPECT_EQ(l1->cc_layer_for_testing()->corner_radii(), kCornerRadii);
+  EXPECT_TRUE(l1->cc_layer_for_testing()->is_fast_rounded_corner());
 
   cc::Layer* before_layer = l1->cc_layer_for_testing();
 
@@ -1023,6 +1049,9 @@
   EXPECT_TRUE(l1->cc_layer_for_testing()->contents_opaque());
   EXPECT_TRUE(l1->cc_layer_for_testing()->hide_layer_and_subtree());
   EXPECT_EQ(gfx::Size(4, 5), l1->cc_layer_for_testing()->bounds());
+  EXPECT_TRUE(l1->cc_layer_for_testing()->HasRoundedCorner());
+  EXPECT_EQ(l1->cc_layer_for_testing()->corner_radii(), kCornerRadii);
+  EXPECT_TRUE(l1->cc_layer_for_testing()->is_fast_rounded_corner());
   EXPECT_FALSE(callback1_run);
 
   bool callback2_run = false;
@@ -1042,6 +1071,9 @@
   EXPECT_TRUE(l1->cc_layer_for_testing()->contents_opaque());
   EXPECT_TRUE(l1->cc_layer_for_testing()->hide_layer_and_subtree());
   EXPECT_EQ(gfx::Size(4, 5), l1->cc_layer_for_testing()->bounds());
+  EXPECT_TRUE(l1->cc_layer_for_testing()->HasRoundedCorner());
+  EXPECT_EQ(l1->cc_layer_for_testing()->corner_radii(), kCornerRadii);
+  EXPECT_TRUE(l1->cc_layer_for_testing()->is_fast_rounded_corner());
   EXPECT_TRUE(callback2_run);
 
   before_layer = l1->cc_layer_for_testing();
@@ -1062,6 +1094,9 @@
   EXPECT_TRUE(l1->cc_layer_for_testing()->contents_opaque());
   EXPECT_TRUE(l1->cc_layer_for_testing()->hide_layer_and_subtree());
   EXPECT_EQ(gfx::Size(4, 5), l1->cc_layer_for_testing()->bounds());
+  EXPECT_TRUE(l1->cc_layer_for_testing()->HasRoundedCorner());
+  EXPECT_EQ(l1->cc_layer_for_testing()->corner_radii(), kCornerRadii);
+  EXPECT_TRUE(l1->cc_layer_for_testing()->is_fast_rounded_corner());
   EXPECT_FALSE(callback3_run);
 
   // Release the on |l1| mailbox to clean up the test.
diff --git a/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js b/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js
index ce5271c..f7e2c89 100644
--- a/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js
+++ b/ui/file_manager/file_manager/background/js/runtime_loaded_test_util.js
@@ -606,6 +606,61 @@
   return test.util.sync.sendEvent(contentWindow, targetQuery, event);
 };
 
+
+/**
+ * Sends a drag'n'drop set of events from |srcTarget| to |dstTarget|.
+ *
+ * @param {Window} contentWindow Window to be tested.
+ * @param {string} srcTarget Query to specify the element as the source to be
+ *   dragged.
+ * @param {string} dstTarget Query to specify the element as the destination
+ *   to drop.
+ * @param {boolean=} skipDrop True if it should only hover over dstTarget.
+ *   to drop.
+ * @return {boolean} True if the event is sent to the target, false otherwise.
+ */
+test.util.sync.fakeDragAndDrop =
+    (contentWindow, srcTarget, dstTarget, skipDrop) => {
+      const options = {
+        bubbles: true,
+        composed: true,
+        dataTransfer: new DataTransfer(),
+      };
+      const srcElement = contentWindow.document &&
+          contentWindow.document.querySelector(srcTarget);
+      const dstElement = contentWindow.document &&
+          contentWindow.document.querySelector(dstTarget);
+
+      if (!srcElement || !dstElement) {
+        return false;
+      }
+
+      // Get the middle of the src element, because some of Files app logic
+      // requires clientX and clientY.
+      const srcRect = srcElement.getBoundingClientRect();
+      const srcOptions = Object.assign(
+          {
+            clientX: srcRect.left + (srcRect.width / 2),
+            clientY: srcRect.top + (srcRect.height / 2),
+          },
+          options);
+
+      const dragStart = new DragEvent('dragstart', srcOptions);
+      const dragEnter = new DragEvent('dragenter', options);
+      const dragOver = new DragEvent('dragover', options);
+      const drop = new DragEvent('drop', options);
+      const dragEnd = new DragEvent('dragEnd', options);
+
+      srcElement.dispatchEvent(dragStart);
+      dstElement.dispatchEvent(dragEnter);
+      dstElement.dispatchEvent(dragOver);
+      if (!skipDrop) {
+        dstElement.dispatchEvent(drop);
+      }
+      srcElement.dispatchEvent(dragEnd);
+      return true;
+    };
+
 /**
  * Focuses to the element specified by |targetQuery|. This method does not
  * provide any guarantee whether the element is actually focused or not.
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.html b/ui/file_manager/file_manager/foreground/elements/files_quick_view.html
index 949d7712..3b40174 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_quick_view.html
+++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.html
@@ -24,7 +24,7 @@
         </div>
         <div id="file-path">[[filePath]]</div>
         <div class="buttons-group">
-           <paper-button id="open-button" on-tap="onOpenInNewButtonTap" hidden$="[[!hasTask]]" aria-label="$i18n{QUICK_VIEW_OPEN_IN_NEW_BUTTON_LABEL}" tabindex="0" has-tooltip>
+           <paper-button id="open-button" on-tap="onOpenInNewButtonTap" hidden$="[[!hasTask]]" aria-label="$i18n{QUICK_VIEW_OPEN_IN_NEW_BUTTON_LABEL}" tabindex="0">
              <span>$i18n{QUICK_VIEW_OPEN_IN_NEW_BUTTON_LABEL}</span>
            </paper-button>
            <files-icon-button toggles id="metadata-button" on-tap="onMetadataButtonTap_" active="{{metadataBoxActive}}" aria-label="$i18n{QUICK_VIEW_TOGGLE_METADATA_BOX_BUTTON_LABEL}" tabindex="0" has-tooltip>
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index 0835190..a57076b7 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -699,10 +699,11 @@
     }
     const location = root && fileManager.volumeManager.getLocationInfo(root);
     const writable = location && !location.isReadOnly;
-    const removable = location && location.rootType ===
-        VolumeManagerCommon.RootType.REMOVABLE;
-    event.canExecute = removable && (isUnrecognizedVolume || writable);
-    event.command.setHidden(!removable);
+    const isRoot = location && location.isRootEntry;
+    const removableRoot = location && isRoot &&
+        location.rootType === VolumeManagerCommon.RootType.REMOVABLE;
+    event.canExecute = removableRoot && (isUnrecognizedVolume || writable);
+    event.command.setHidden(!removableRoot);
   }
 });
 
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
index 44e5f887..f6492cc6 100644
--- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
@@ -1766,7 +1766,8 @@
       return new DropEffectAndLabel(
           DropEffectType.NONE, strf('OPENING_LINUX_FILES'));
     }
-    if (destinationLocationInfo.volumeInfo.isReadOnlyRemovableDevice) {
+    if (destinationLocationInfo.volumeInfo &&
+        destinationLocationInfo.volumeInfo.isReadOnlyRemovableDevice) {
       return new DropEffectAndLabel(DropEffectType.NONE,
                                     strf('DEVICE_WRITE_PROTECTED'));
     }
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html
index db662e1..2e2780c 100644
--- a/ui/file_manager/file_manager/main.html
+++ b/ui/file_manager/file_manager/main.html
@@ -243,6 +243,7 @@
       <cr-menu-item command="#share-with-linux"></cr-menu-item>
       <cr-menu-item command="#manage-linux-sharing"></cr-menu-item>
       <hr visibleif="full-page">
+      <cr-menu-item command="#format"></cr-menu-item>
       <cr-menu-item command="#rename"></cr-menu-item>
       <cr-menu-item command="#create-folder-shortcut"></cr-menu-item>
       <cr-menu-item command="#delete">$i18n{DELETE_BUTTON_LABEL}</cr-menu-item>
diff --git a/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js b/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
index 70e6789e..35bfb1a 100644
--- a/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
+++ b/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
@@ -798,6 +798,7 @@
   ];
   const partition1Menus = [
     ['#share-with-linux', true],
+    ['#format', true],
     ['#rename', false],
     ['#new-folder', true],
   ];
diff --git a/ui/file_manager/integration_tests/file_manager/transfer.js b/ui/file_manager/integration_tests/file_manager/transfer.js
index eccbba0..65d3b90 100644
--- a/ui/file_manager/integration_tests/file_manager/transfer.js
+++ b/ui/file_manager/integration_tests/file_manager/transfer.js
@@ -480,3 +480,79 @@
       '',
       (await remoteCall.waitForElement(appId, '.progress-frame label')).text);
 };
+
+/**
+ * Tests that we can drag a file from #file-list to #directory-tree.
+ * It copies the file from Downloads to Downloads/photos.
+ */
+testcase.transferDragAndDrop = async () => {
+  const entries = [ENTRIES.hello, ENTRIES.photos];
+
+  // Open files app.
+  const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS, entries, []);
+
+  // Expand Downloads to display "photos" folder in the directory tree.
+  await expandTreeItem(appId, '#directory-tree [entry-label="Downloads"]');
+
+  // Drag has to start in the file list column "name" text content, otherwise it
+  // starts a selection instead of a drag.
+  const src =
+      `#file-list li[file-name="${ENTRIES.hello.nameText}"] .entry-name`;
+  const dst = '#directory-tree [entry-label="photos"]';
+
+  // Select the file to be dragged.
+  chrome.test.assertTrue(
+      await remoteCall.callRemoteTestUtil('fakeMouseClick', appId, [src]),
+      'fakeMouseClick failed');
+
+  // Drag and drop it.
+  chrome.test.assertTrue(
+      await remoteCall.callRemoteTestUtil('fakeDragAndDrop', appId, [src, dst]),
+      'fakeDragAndDrop failed');
+
+  // Navigate to the dst folder.
+  chrome.test.assertTrue(
+      !!await remoteCall.callRemoteTestUtil('fakeMouseClick', appId, [dst]),
+      'fakeMouseClick failed');
+
+  // Wait for navigation to finish.
+  await remoteCall.waitUntilCurrentDirectoryIsChanged(
+      appId, '/My files/Downloads/photos');
+
+  // Wait for the expected files to appear in the file list.
+  await remoteCall.waitForFiles(
+      appId, TestEntryInfo.getExpectedRows([ENTRIES.hello]),
+      {ignoreLastModifiedTime: true});
+};
+
+/**
+ * Tests that we can drag a file from #file-list and hover above USB root as
+ * EntryList without raising an error.
+ */
+testcase.transferDragAndHover = async () => {
+  const entries = [ENTRIES.hello, ENTRIES.photos];
+
+  await sendTestMessage({name: 'mountUsbWithPartitions'});
+  await sendTestMessage({name: 'mountFakeUsb'});
+
+  // Open files app.
+  const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS, entries, []);
+
+  // Drag has to start in the file list column "name" text content, otherwise it
+  // starts a selection instead of a drag.
+  const src =
+      `#file-list li[file-name="${ENTRIES.hello.nameText}"] .entry-name`;
+  const dst1 = '#directory-tree [entry-label="Drive Label"]';
+  const dst2 = '#directory-tree [entry-label="fake-usb"]';
+
+  // Wait for USB roots to be ready.
+  await remoteCall.waitForElement(appId, dst1);
+  await remoteCall.waitForElement(appId, dst2);
+
+  // Drag and hover it.
+  const skipDrop = true;
+  chrome.test.assertTrue(
+      await remoteCall.callRemoteTestUtil(
+          'fakeDragAndDrop', appId, [src, dst1, skipDrop]),
+      'fakeDragAndDrop failed');
+};
diff --git a/ui/gl/gl_stub_api.cc b/ui/gl/gl_stub_api.cc
index 144bc30..534a291 100644
--- a/ui/gl/gl_stub_api.cc
+++ b/ui/gl/gl_stub_api.cc
@@ -6,15 +6,6 @@
 
 namespace gl {
 
-namespace {
-
-void GenHelper(GLsizei count, GLuint* objects) {
-  for (GLsizei i = 0; i < count; ++i)
-    objects[i] = i + 1;
-}
-
-}  // anonymous namespace
-
 GLStubApi::GLStubApi() {}
 
 GLStubApi::~GLStubApi() = default;
diff --git a/ui/gl/gl_stub_api.h b/ui/gl/gl_stub_api.h
index 01bd331..3b3baba 100644
--- a/ui/gl/gl_stub_api.h
+++ b/ui/gl/gl_stub_api.h
@@ -72,8 +72,17 @@
   GLboolean glUnmapBufferFn(GLenum target) override;
 
  private:
+  // The only consumers of GLStubApi are GpuChannelTestCommon (gpu_unittests)
+  // and GPU fuzzers. We get a new GLStubApi for every case executed by
+  // fuzzers, so we don't have to worry about ID exhaustion.
+  void GenHelper(GLsizei count, GLuint* objects) {
+    for (GLsizei i = 0; i < count; ++i)
+      objects[i] = next_id_++;
+  }
+
   std::string version_;
   std::string extensions_;
+  GLuint next_id_ = 1;
 
   DISALLOW_COPY_AND_ASSIGN(GLStubApi);
 };
diff --git a/ui/message_center/BUILD.gn b/ui/message_center/BUILD.gn
index 0ea28e02..76779020 100644
--- a/ui/message_center/BUILD.gn
+++ b/ui/message_center/BUILD.gn
@@ -123,6 +123,8 @@
         "views/proportional_image_view.h",
         "views/slide_out_controller.cc",
         "views/slide_out_controller.h",
+        "views/timestamp_view.cc",
+        "views/timestamp_view.h",
       ]
       if (!is_chromeos) {
         sources += [
@@ -225,6 +227,7 @@
         "views/message_popup_collection_unittest.cc",
         "views/notification_view_md_unittest.cc",
         "views/slide_out_controller_unittest.cc",
+        "views/timestamp_view_unittest.cc",
       ]
       if (!is_chromeos) {
         sources += [
@@ -237,6 +240,7 @@
         # fonts used by bounded_label_unittest.cc.
         "//ui/compositor",
         "//ui/display",
+        "//ui/strings",
         "//ui/views",
         "//ui/views:test_support",
       ]
diff --git a/ui/message_center/views/notification_header_view.cc b/ui/message_center/views/notification_header_view.cc
index 5bae6eb9..2fe528d13 100644
--- a/ui/message_center/views/notification_header_view.cc
+++ b/ui/message_center/views/notification_header_view.cc
@@ -18,6 +18,7 @@
 #include "ui/message_center/public/cpp/message_center_constants.h"
 #include "ui/message_center/vector_icons.h"
 #include "ui/message_center/views/notification_control_buttons_view.h"
+#include "ui/message_center/views/timestamp_view.h"
 #include "ui/strings/grit/ui_strings.h"
 #include "ui/views/animation/ink_drop_stub.h"
 #include "ui/views/border.h"
@@ -62,13 +63,6 @@
 // Bullet character. The divider symbol between different parts of the header.
 constexpr wchar_t kNotificationHeaderDivider[] = L" \u2022 ";
 
-// base::TimeBase has similar constants, but some of them are missing.
-constexpr int64_t kMinuteInMillis = 60LL * 1000LL;
-constexpr int64_t kHourInMillis = 60LL * kMinuteInMillis;
-constexpr int64_t kDayInMillis = 24LL * kHourInMillis;
-// In Android, DateUtils.YEAR_IN_MILLIS is 364 days.
-constexpr int64_t kYearInMillis = 364LL * kDayInMillis;
-
 // "Roboto-Regular, 12sp" is specified in the mock.
 constexpr int kHeaderTextFontSize = 12;
 
@@ -119,35 +113,6 @@
   node_data->SetName(tooltip_text());
 }
 
-// Do relative time string formatting that is similar to
-// com.java.android.widget.DateTimeView.updateRelativeTime.
-// Chromium has its own base::TimeFormat::Simple(), but none of the formats
-// supported by the function is similar to Android's one.
-base::string16 FormatToRelativeTime(base::Time past) {
-  base::Time now = base::Time::Now();
-  int64_t duration = (now - past).InMilliseconds();
-  if (duration < kMinuteInMillis) {
-    return l10n_util::GetStringUTF16(
-        IDS_MESSAGE_NOTIFICATION_NOW_STRING_SHORTEST);
-  } else if (duration < kHourInMillis) {
-    int count = static_cast<int>(duration / kMinuteInMillis);
-    return l10n_util::GetPluralStringFUTF16(
-        IDS_MESSAGE_NOTIFICATION_DURATION_MINUTES_SHORTEST, count);
-  } else if (duration < kDayInMillis) {
-    int count = static_cast<int>(duration / kHourInMillis);
-    return l10n_util::GetPluralStringFUTF16(
-        IDS_MESSAGE_NOTIFICATION_DURATION_HOURS_SHORTEST, count);
-  } else if (duration < kYearInMillis) {
-    int count = static_cast<int>(duration / kDayInMillis);
-    return l10n_util::GetPluralStringFUTF16(
-        IDS_MESSAGE_NOTIFICATION_DURATION_DAYS_SHORTEST, count);
-  } else {
-    int count = static_cast<int>(duration / kYearInMillis);
-    return l10n_util::GetPluralStringFUTF16(
-        IDS_MESSAGE_NOTIFICATION_DURATION_YEARS_SHORTEST, count);
-  }
-}
-
 gfx::FontList GetHeaderTextFontList() {
   gfx::Font default_font;
   int font_size_delta = kHeaderTextFontSize - default_font.GetFontSize();
@@ -266,7 +231,7 @@
   AddChildView(timestamp_divider_);
 
   // Timestamp view
-  timestamp_view_ = new views::Label(base::string16());
+  timestamp_view_ = new TimestampView();
   timestamp_view_->SetFontList(font_list);
   timestamp_view_->SetLineHeight(font_list_height);
   timestamp_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
@@ -354,8 +319,8 @@
     node_data->AddState(ax::mojom::State::kExpanded);
 }
 
-void NotificationHeaderView::SetTimestamp(base::Time past) {
-  timestamp_view_->SetText(FormatToRelativeTime(past));
+void NotificationHeaderView::SetTimestamp(base::Time timestamp) {
+  timestamp_view_->SetTimestamp(timestamp);
   has_timestamp_ = true;
   UpdateSummaryTextVisibility();
 }
diff --git a/ui/message_center/views/notification_header_view.h b/ui/message_center/views/notification_header_view.h
index edca12d..feb4ac4 100644
--- a/ui/message_center/views/notification_header_view.h
+++ b/ui/message_center/views/notification_header_view.h
@@ -14,11 +14,12 @@
 namespace views {
 class ImageView;
 class Label;
-}
+}  // namespace views
 
 namespace message_center {
 
 class NotificationControlButtonsView;
+class TimestampView;
 
 class MESSAGE_CENTER_EXPORT NotificationHeaderView : public views::Button {
  public:
@@ -29,7 +30,7 @@
   void SetAppNameElideBehavior(gfx::ElideBehavior elide_behavior);
   void SetProgress(int progress);
   void SetOverflowIndicator(int count);
-  void SetTimestamp(base::Time past);
+  void SetTimestamp(base::Time timestamp);
   void SetExpandButtonEnabled(bool enabled);
   void SetExpanded(bool expanded);
   void SetSettingsButtonEnabled(bool enabled);
@@ -67,7 +68,7 @@
   views::Label* summary_text_divider_ = nullptr;
   views::Label* summary_text_view_ = nullptr;
   views::Label* timestamp_divider_ = nullptr;
-  views::Label* timestamp_view_ = nullptr;
+  TimestampView* timestamp_view_ = nullptr;
   views::ImageView* app_icon_view_ = nullptr;
   views::ImageView* expand_button_ = nullptr;
 
diff --git a/ui/message_center/views/timestamp_view.cc b/ui/message_center/views/timestamp_view.cc
new file mode 100644
index 0000000..cc8d477
--- /dev/null
+++ b/ui/message_center/views/timestamp_view.cc
@@ -0,0 +1,71 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/message_center/views/timestamp_view.h"
+
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/strings/grit/ui_strings.h"
+
+namespace message_center {
+
+namespace {
+
+// base::TimeBase has similar constants, but some of them are missing.
+constexpr int64_t kMinuteInMillis = 60LL * 1000LL;
+constexpr int64_t kHourInMillis = 60LL * kMinuteInMillis;
+constexpr int64_t kDayInMillis = 24LL * kHourInMillis;
+// In Android, DateUtils.YEAR_IN_MILLIS is 364 days.
+constexpr int64_t kYearInMillis = 364LL * kDayInMillis;
+
+// Do relative time string formatting that is similar to
+// com.java.android.widget.DateTimeView.updateRelativeTime.
+// Chromium has its own base::TimeFormat::Simple(), but none of the formats
+// supported by the function is similar to Android's one.
+base::string16 FormatToRelativeTime(base::TimeDelta delta) {
+  int64_t duration = std::abs(delta.InMilliseconds());
+  bool past = delta <= base::TimeDelta();
+  if (duration < kMinuteInMillis) {
+    return l10n_util::GetStringUTF16(
+        IDS_MESSAGE_NOTIFICATION_NOW_STRING_SHORTEST);
+  } else if (duration < kHourInMillis) {
+    int count = static_cast<int>(duration / kMinuteInMillis);
+    return l10n_util::GetPluralStringFUTF16(
+        past ? IDS_MESSAGE_NOTIFICATION_DURATION_MINUTES_SHORTEST
+             : IDS_MESSAGE_NOTIFICATION_DURATION_MINUTES_SHORTEST_FUTURE,
+        count);
+  } else if (duration < kDayInMillis) {
+    int count = static_cast<int>(duration / kHourInMillis);
+    return l10n_util::GetPluralStringFUTF16(
+        past ? IDS_MESSAGE_NOTIFICATION_DURATION_HOURS_SHORTEST
+             : IDS_MESSAGE_NOTIFICATION_DURATION_HOURS_SHORTEST_FUTURE,
+        count);
+  } else if (duration < kYearInMillis) {
+    // TODO(https://crbug.com/914432): Use a calendar to calculate this.
+    int count = static_cast<int>(duration / kDayInMillis);
+    return l10n_util::GetPluralStringFUTF16(
+        past ? IDS_MESSAGE_NOTIFICATION_DURATION_DAYS_SHORTEST
+             : IDS_MESSAGE_NOTIFICATION_DURATION_DAYS_SHORTEST_FUTURE,
+        count);
+  } else {
+    int count = static_cast<int>(duration / kYearInMillis);
+    return l10n_util::GetPluralStringFUTF16(
+        past ? IDS_MESSAGE_NOTIFICATION_DURATION_YEARS_SHORTEST
+             : IDS_MESSAGE_NOTIFICATION_DURATION_YEARS_SHORTEST_FUTURE,
+        count);
+  }
+}
+
+}  // namespace
+
+TimestampView::TimestampView() = default;
+
+TimestampView::~TimestampView() = default;
+
+void TimestampView::SetTimestamp(base::Time timestamp) {
+  SetText(FormatToRelativeTime(timestamp - base::Time::Now()));
+}
+
+}  // namespace message_center
diff --git a/ui/message_center/views/timestamp_view.h b/ui/message_center/views/timestamp_view.h
new file mode 100644
index 0000000..9a322f18
--- /dev/null
+++ b/ui/message_center/views/timestamp_view.h
@@ -0,0 +1,29 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_MESSAGE_CENTER_VIEWS_TIMESTAMP_VIEW_H_
+#define UI_MESSAGE_CENTER_VIEWS_TIMESTAMP_VIEW_H_
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "ui/message_center/message_center_export.h"
+#include "ui/views/controls/label.h"
+
+namespace message_center {
+
+class MESSAGE_CENTER_EXPORT TimestampView : public views::Label {
+ public:
+  TimestampView();
+  ~TimestampView() override;
+
+  // Formats |timestamp| relative to base::Time::Now().
+  void SetTimestamp(base::Time timestamp);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TimestampView);
+};
+
+}  // namespace message_center
+
+#endif  // UI_MESSAGE_CENTER_VIEWS_TIMESTAMP_VIEW_H_
diff --git a/ui/message_center/views/timestamp_view_unittest.cc b/ui/message_center/views/timestamp_view_unittest.cc
new file mode 100644
index 0000000..e6be720
--- /dev/null
+++ b/ui/message_center/views/timestamp_view_unittest.cc
@@ -0,0 +1,167 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/message_center/views/timestamp_view.h"
+
+#include "base/test/scoped_task_environment.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/strings/grit/ui_strings.h"
+#include "ui/views/test/views_test_base.h"
+
+namespace message_center {
+
+namespace {
+
+// In Android, DateUtils.YEAR_IN_MILLIS is 364 days.
+constexpr int64_t kYearInMillis = 364LL * base::Time::kMillisecondsPerDay;
+constexpr base::TimeDelta kTimeAdvance = base::TimeDelta::FromMilliseconds(1);
+
+}  // namespace
+
+class TimestampViewTest : public views::ViewsTestBase {
+ public:
+  TimestampViewTest() = default;
+  ~TimestampViewTest() override = default;
+
+  // ViewsTestBase:
+  void SetUp() override {
+    // Setup a mocked time environment.
+    scoped_task_environment_ = new ScopedTaskEnvironment(
+        ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
+        ScopedTaskEnvironment::NowSource::MAIN_THREAD_MOCK_TIME);
+    set_scoped_task_environment(base::WrapUnique(scoped_task_environment_));
+
+    // Advance time a little bit so that TimeTicks::Now().is_null() becomes
+    // false.
+    scoped_task_environment_->FastForwardBy(kTimeAdvance);
+
+    ViewsTestBase::SetUp();
+
+    views::Widget::InitParams params =
+        CreateParams(views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+    params.bounds = gfx::Rect(200, 200);
+    params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+    widget_.Init(params);
+    views::View* container = new views::View();
+    widget_.SetContentsView(container);
+
+    timestamp_view_ = new TimestampView();
+    container->AddChildView(timestamp_view_);
+
+    widget_.Show();
+  }
+
+  void TearDown() override {
+    widget_.Close();
+    ViewsTestBase::TearDown();
+  }
+
+ protected:
+  TimestampView* view() { return timestamp_view_; }
+
+ private:
+  TimestampView* timestamp_view_ = nullptr;
+  views::Widget widget_;
+  ScopedTaskEnvironment* scoped_task_environment_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(TimestampViewTest);
+};
+
+TEST_F(TimestampViewTest, FormatToRelativeTime) {
+  // Test 30 seconds in the future.
+  view()->SetTimestamp(base::Time::Now() + base::TimeDelta::FromSeconds(30));
+  EXPECT_EQ(
+      l10n_util::GetStringUTF16(IDS_MESSAGE_NOTIFICATION_NOW_STRING_SHORTEST),
+      view()->text());
+  // Test 30 seconds in the past.
+  view()->SetTimestamp(base::Time::Now() + base::TimeDelta::FromSeconds(-30));
+  EXPECT_EQ(
+      l10n_util::GetStringUTF16(IDS_MESSAGE_NOTIFICATION_NOW_STRING_SHORTEST),
+      view()->text());
+
+  // Test 60 seconds in the future.
+  view()->SetTimestamp(base::Time::Now() + base::TimeDelta::FromSeconds(60));
+  EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
+                IDS_MESSAGE_NOTIFICATION_DURATION_MINUTES_SHORTEST_FUTURE, 1),
+            view()->text());
+  // Test 60 seconds in the past.
+  view()->SetTimestamp(base::Time::Now() + base::TimeDelta::FromSeconds(-60));
+  EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
+                IDS_MESSAGE_NOTIFICATION_DURATION_MINUTES_SHORTEST, 1),
+            view()->text());
+
+  // Test 5 minutes in the future.
+  view()->SetTimestamp(base::Time::Now() + base::TimeDelta::FromMinutes(5));
+  EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
+                IDS_MESSAGE_NOTIFICATION_DURATION_MINUTES_SHORTEST_FUTURE, 5),
+            view()->text());
+  // Test 5 minutes in the past.
+  view()->SetTimestamp(base::Time::Now() + base::TimeDelta::FromMinutes(-5));
+  EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
+                IDS_MESSAGE_NOTIFICATION_DURATION_MINUTES_SHORTEST, 5),
+            view()->text());
+
+  // Test 60 minutes in the future.
+  view()->SetTimestamp(base::Time::Now() + base::TimeDelta::FromMinutes(60));
+  EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
+                IDS_MESSAGE_NOTIFICATION_DURATION_HOURS_SHORTEST_FUTURE, 1),
+            view()->text());
+  // Test 60 minutes in the past.
+  view()->SetTimestamp(base::Time::Now() + base::TimeDelta::FromMinutes(-60));
+  EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
+                IDS_MESSAGE_NOTIFICATION_DURATION_HOURS_SHORTEST, 1),
+            view()->text());
+
+  // Test 10 hours in the future.
+  view()->SetTimestamp(base::Time::Now() + base::TimeDelta::FromHours(10));
+  EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
+                IDS_MESSAGE_NOTIFICATION_DURATION_HOURS_SHORTEST_FUTURE, 10),
+            view()->text());
+  // Test 10 hours in the past.
+  view()->SetTimestamp(base::Time::Now() + base::TimeDelta::FromHours(-10));
+  EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
+                IDS_MESSAGE_NOTIFICATION_DURATION_HOURS_SHORTEST, 10),
+            view()->text());
+
+  // Test 24 hours in the future.
+  view()->SetTimestamp(base::Time::Now() + base::TimeDelta::FromHours(24));
+  EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
+                IDS_MESSAGE_NOTIFICATION_DURATION_DAYS_SHORTEST_FUTURE, 1),
+            view()->text());
+  // Test 24 hours in the past.
+  view()->SetTimestamp(base::Time::Now() + base::TimeDelta::FromHours(-24));
+  EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
+                IDS_MESSAGE_NOTIFICATION_DURATION_DAYS_SHORTEST, 1),
+            view()->text());
+
+  // Test 1 year in the future.
+  view()->SetTimestamp(base::Time::Now() +
+                       base::TimeDelta::FromMilliseconds(kYearInMillis));
+  EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
+                IDS_MESSAGE_NOTIFICATION_DURATION_YEARS_SHORTEST_FUTURE, 1),
+            view()->text());
+  // Test 1 year in the past.
+  view()->SetTimestamp(base::Time::Now() +
+                       base::TimeDelta::FromMilliseconds(-kYearInMillis));
+  EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
+                IDS_MESSAGE_NOTIFICATION_DURATION_YEARS_SHORTEST, 1),
+            view()->text());
+
+  // Test 10 years in the future.
+  view()->SetTimestamp(base::Time::Now() +
+                       base::TimeDelta::FromMilliseconds(kYearInMillis * 10));
+  EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
+                IDS_MESSAGE_NOTIFICATION_DURATION_YEARS_SHORTEST_FUTURE, 10),
+            view()->text());
+  // Test 10 years in the past.
+  view()->SetTimestamp(base::Time::Now() +
+                       base::TimeDelta::FromMilliseconds(-kYearInMillis * 10));
+  EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
+                IDS_MESSAGE_NOTIFICATION_DURATION_YEARS_SHORTEST, 10),
+            view()->text());
+}
+
+}  // namespace message_center
diff --git a/ui/ozone/platform/wayland/test/test_data_source.cc b/ui/ozone/platform/wayland/test/test_data_source.cc
index ade78494..a0ef41e7 100644
--- a/ui/ozone/platform/wayland/test/test_data_source.cc
+++ b/ui/ozone/platform/wayland/test/test_data_source.cc
@@ -5,6 +5,7 @@
 #include "ui/ozone/platform/wayland/test/test_data_source.h"
 
 #include <wayland-server-core.h>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/files/file_util.h"
@@ -30,13 +31,13 @@
       bytes.insert(bytes.end(), chunk, chunk + bytes_read);
       continue;
     }
-    if (!bytes_read)
-      return bytes;
     if (bytes_read < 0) {
-      LOG(ERROR) << "Failed to read selection data from clipboard.";
-      return std::vector<uint8_t>();
+      PLOG(ERROR) << "Failed to read data";
+      bytes.clear();
     }
+    break;
   }
+  return bytes;
 }
 
 void CreatePipe(base::ScopedFD* read_pipe, base::ScopedFD* write_pipe) {
@@ -70,8 +71,7 @@
 TestDataSource::TestDataSource(wl_resource* resource)
     : ServerObject(resource),
       task_runner_(
-          base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()})),
-      read_data_weak_ptr_factory_(this) {}
+          base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()})) {}
 
 TestDataSource::~TestDataSource() {}
 
@@ -79,30 +79,23 @@
   NOTIMPLEMENTED();
 }
 
-void TestDataSource::ReadData(ReadDataCallback callback) {
+void TestDataSource::ReadData(const std::string& mime_type,
+                              ReadDataCallback callback) {
   base::ScopedFD read_fd;
   base::ScopedFD write_fd;
   CreatePipe(&read_fd, &write_fd);
 
   // 1. Send the SEND event to notify client's DataSource that it's time
   // to send us the drag data thrhough the write_fd file descriptor.
-  wl_data_source_send_send(resource(), kTextMimeTypeUtf8, write_fd.get());
+  wl_data_source_send_send(resource(), mime_type.c_str(), write_fd.get());
   wl_client_flush(wl_resource_get_client(resource()));
 
   // 2. Schedule the ReadDataOnWorkerThread task. The result of read
-  // operation will be delivered through TestDataSource::DataReadCb,
-  // which will then call the callback function requested by the caller.
-  PostTaskAndReplyWithResult(
+  // operation will be then passed in to the callback requested by the caller.
+  base::PostTaskAndReplyWithResult(
       task_runner_.get(), FROM_HERE,
       base::BindOnce(&ReadDataOnWorkerThread, std::move(read_fd)),
-      base::BindOnce(&TestDataSource::DataReadCb,
-                     read_data_weak_ptr_factory_.GetWeakPtr(),
-                     std::move(callback)));
-}
-
-void TestDataSource::DataReadCb(ReadDataCallback callback,
-                                const std::vector<uint8_t>& data) {
-  std::move(callback).Run(data);
+      std::move(callback));
 }
 
 void TestDataSource::OnCancelled() {
diff --git a/ui/ozone/platform/wayland/test/test_data_source.h b/ui/ozone/platform/wayland/test/test_data_source.h
index 4d62962..32592071 100644
--- a/ui/ozone/platform/wayland/test/test_data_source.h
+++ b/ui/ozone/platform/wayland/test/test_data_source.h
@@ -5,12 +5,12 @@
 #ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_DATA_SOURCE_H_
 #define UI_OZONE_PLATFORM_WAYLAND_TEST_TEST_DATA_SOURCE_H_
 
+#include <wayland-server-protocol-core.h>
+
 #include <memory>
 #include <string>
 #include <vector>
 
-#include <wayland-server-protocol-core.h>
-
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "ui/ozone/platform/wayland/test/server_object.h"
@@ -32,17 +32,13 @@
 
   void Offer(const std::string& mime_type);
 
-  using ReadDataCallback =
-      base::OnceCallback<void(const std::vector<uint8_t>&)>;
-  void ReadData(ReadDataCallback);
+  using ReadDataCallback = base::OnceCallback<void(std::vector<uint8_t>&&)>;
+  void ReadData(const std::string& mime_type, ReadDataCallback callback);
 
   void OnCancelled();
 
  private:
-  void DataReadCb(ReadDataCallback callback, const std::vector<uint8_t>& data);
-
   const scoped_refptr<base::SequencedTaskRunner> task_runner_;
-  base::WeakPtrFactory<TestDataSource> read_data_weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(TestDataSource);
 };
diff --git a/ui/ozone/platform/wayland/wayland_data_device_unittest.cc b/ui/ozone/platform/wayland/wayland_data_device_unittest.cc
index 5aff53a6..54c5905 100644
--- a/ui/ozone/platform/wayland/wayland_data_device_unittest.cc
+++ b/ui/ozone/platform/wayland/wayland_data_device_unittest.cc
@@ -29,7 +29,7 @@
 // OzonePlatform::GetPlatformClipboard.
 class MockClipboardClient {
  public:
-  MockClipboardClient(WaylandConnection* connection) {
+  explicit MockClipboardClient(WaylandConnection* connection) {
     DCHECK(connection);
     // See comment above for reasoning to access the WaylandConnection
     // directly from here.
@@ -99,19 +99,20 @@
   // ... and the server reads it.
   base::RunLoop run_loop;
   auto callback = base::BindOnce(
-      [](base::RunLoop* loop, const std::vector<uint8_t>& data) {
+      [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
         std::string string_data(data.begin(), data.end());
         EXPECT_EQ(wl::kSampleClipboardText, string_data);
         loop->Quit();
       },
       &run_loop);
-  data_device_manager_->data_source()->ReadData(std::move(callback));
+  data_device_manager_->data_source()->ReadData(wl::kTextMimeTypeUtf8,
+                                                std::move(callback));
   run_loop.Run();
 }
 
 TEST_P(WaylandDataDeviceManagerTest, ReadFromClibpard) {
-  // TODO: implement this in terms of an actual wl_surface that gets
-  // focused and compositor sends data_device data to it.
+  // TODO(nickdiego): implement this in terms of an actual wl_surface that
+  // gets focused and compositor sends data_device data to it.
   auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
   data_offer->OnOffer(wl::kTextMimeTypeUtf8);
   data_device_manager_->data_device()->OnSelection(data_offer);
@@ -150,10 +151,9 @@
   window_->set_pointer_focus(true);
 
   // The client starts dragging.
-  std::unique_ptr<OSExchangeData> os_exchange_data =
-      std::make_unique<OSExchangeData>();
+  OSExchangeData os_exchange_data;
   int operation = DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE;
-  connection_->StartDrag(*os_exchange_data, operation);
+  connection_->StartDrag(os_exchange_data, operation);
 
   WaylandDataSource::DragDataMap data;
   data[wl::kTextMimeTypeUtf8] = wl::kSampleTextForDragAndDrop;
@@ -163,13 +163,45 @@
   // The server reads the data and the callback gets it.
   base::RunLoop run_loop;
   auto callback = base::BindOnce(
-      [](base::RunLoop* loop, const std::vector<uint8_t>& data) {
+      [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
         std::string result(data.begin(), data.end());
         EXPECT_EQ(wl::kSampleTextForDragAndDrop, result);
         loop->Quit();
       },
       &run_loop);
-  data_device_manager_->data_source()->ReadData(std::move(callback));
+  data_device_manager_->data_source()->ReadData(wl::kTextMimeTypeUtf8,
+                                                std::move(callback));
+  run_loop.Run();
+  window_->set_pointer_focus(restored_focus);
+}
+
+TEST_P(WaylandDataDeviceManagerTest, StartDragWithWrongMimeType) {
+  bool restored_focus = window_->has_pointer_focus();
+  window_->set_pointer_focus(true);
+
+  // The client starts dragging offering data with wl::kTextMimeTypeUtf8
+  // mime type.
+  OSExchangeData os_exchange_data;
+  int operation = DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE;
+  connection_->StartDrag(os_exchange_data, operation);
+
+  WaylandDataSource::DragDataMap data;
+  data[wl::kTextMimeTypeUtf8] = wl::kSampleTextForDragAndDrop;
+  connection_->drag_data_source()->SetDragData(data);
+  Sync();
+
+  // The server should get an empty data buffer in ReadData callback
+  // when trying to read it.
+  base::RunLoop run_loop;
+  auto callback = base::BindOnce(
+      [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
+        std::string result(data.begin(), data.end());
+        EXPECT_EQ("", result);
+        loop->Quit();
+      },
+      &run_loop);
+  data_device_manager_->data_source()->ReadData(wl::kTextMimeTypeText,
+                                                std::move(callback));
   run_loop.Run();
   window_->set_pointer_focus(restored_focus);
 }
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd
index 7017d9c..6de181ea 100644
--- a/ui/strings/ui_strings.grd
+++ b/ui/strings/ui_strings.grd
@@ -728,6 +728,18 @@
       <message name="IDS_MESSAGE_NOTIFICATION_DURATION_YEARS_SHORTEST" desc="Phrase describing a time duration using years that is as short as possible, preferrably one character. Should be same as AndroidPlatform msgId 7848711145196397042. (frameworks/base/core/res/res/values/strings.xml:plurals:duration_years_shortest) [ICU Syntax]">
         {YEARS, plural, =1 {1y} other {#y}}
       </message>
+      <message name="IDS_MESSAGE_NOTIFICATION_DURATION_MINUTES_SHORTEST_FUTURE" desc="Phrase describing a time duration using minutes that is as short as possible, preferrably one character. This version should be a future point in time. Should be same as AndroidPlatform msgId 3277614521231489951. (frameworks/base/core/res/res/values/strings.xml:plurals:duration_minutes_shortest_future) [ICU Syntax]">
+        {MINUTES, plural, =1 {in 1m} other {in #m}}
+      </message>
+      <message name="IDS_MESSAGE_NOTIFICATION_DURATION_HOURS_SHORTEST_FUTURE" desc="Phrase describing a time duration using hours that is as short as possible, preferrably one character. This version should be a future point in time. Should be same as AndroidPlatform msgId 2152452368397489370. (frameworks/base/core/res/res/values/strings.xml:plurals:duration_hours_shortest_future) [ICU Syntax]">
+        {HOURS, plural, =1 {in 1h} other {in #h}}
+      </message>
+      <message name="IDS_MESSAGE_NOTIFICATION_DURATION_DAYS_SHORTEST_FUTURE" desc="Phrase describing a time duration using days that is as short as possible, preferrably one character. This version should be a future point in time. Should be same as AndroidPlatform msgId 8088331502820295701. (frameworks/base/core/res/res/values/strings.xml:plurals:duration_days_shortest_future) [ICU Syntax]">
+        {DAYS, plural, =1 {in 1d} other {in #d}}
+      </message>
+      <message name="IDS_MESSAGE_NOTIFICATION_DURATION_YEARS_SHORTEST_FUTURE" desc="Phrase describing a time duration using years that is as short as possible, preferrably one character. This version should be a future point in time. Should be same as AndroidPlatform msgId 2317006667145250301. (frameworks/base/core/res/res/values/strings.xml:plurals:duration_years_shortest_future) [ICU Syntax]">
+        {YEARS, plural, =1 {in 1y} other {in #y}}
+      </message>
       <message name="IDS_MESSAGE_CENTER_BLOCK_ALL_NOTIFICATIONS_SITE" desc="The label for the radio button to block all the notifications from this notification origin.">
         Block all notifications from this site
       </message>
diff --git a/ui/views/controls/combobox/combobox.cc b/ui/views/controls/combobox/combobox.cc
index 9b0c450..8c4cb159 100644
--- a/ui/views/controls/combobox/combobox.cc
+++ b/ui/views/controls/combobox/combobox.cc
@@ -626,10 +626,10 @@
   // Allow |menu_runner_| to be set by the testing API, but if this method is
   // ever invoked recursively, ensure the old menu is closed.
   if (!menu_runner_ || menu_runner_->IsRunning()) {
-    menu_runner_.reset(
-        new MenuRunner(menu_model_.get(), MenuRunner::COMBOBOX,
-                       base::Bind(&Combobox::OnMenuClosed,
-                                  base::Unretained(this), original_state)));
+    menu_runner_.reset(new MenuRunner(
+        menu_model_.get(), MenuRunner::COMBOBOX,
+        base::BindRepeating(&Combobox::OnMenuClosed, base::Unretained(this),
+                            original_state)));
   }
   menu_runner_->RunMenuAt(GetWidget(), nullptr, bounds, MENU_ANCHOR_TOPLEFT,
                           source_type);
diff --git a/ui/views/controls/menu/menu_controller.h b/ui/views/controls/menu/menu_controller.h
index 6169d04..78e4224 100644
--- a/ui/views/controls/menu/menu_controller.h
+++ b/ui/views/controls/menu/menu_controller.h
@@ -362,9 +362,6 @@
 
   ~MenuController() override;
 
-  // Runs the platform specific bits of the message loop.
-  void RunMessageLoop();
-
   // Invokes AcceleratorPressed() on the hot tracked view if there is one.
   // Returns true if AcceleratorPressed() was invoked.
   bool SendAcceleratorToHotTrackedView();
diff --git a/ui/views/controls/menu/menu_model_adapter.cc b/ui/views/controls/menu/menu_model_adapter.cc
index 03186888..6fa4fcd 100644
--- a/ui/views/controls/menu/menu_model_adapter.cc
+++ b/ui/views/controls/menu/menu_model_adapter.cc
@@ -13,10 +13,12 @@
 namespace views {
 
 MenuModelAdapter::MenuModelAdapter(ui::MenuModel* menu_model)
-    : MenuModelAdapter(menu_model, base::Closure() /*null callback*/) {}
+    : MenuModelAdapter(menu_model, base::RepeatingClosure() /*null callback*/) {
+}
 
-MenuModelAdapter::MenuModelAdapter(ui::MenuModel* menu_model,
-                                   const base::Closure& on_menu_closed_callback)
+MenuModelAdapter::MenuModelAdapter(
+    ui::MenuModel* menu_model,
+    const base::RepeatingClosure& on_menu_closed_callback)
     : menu_model_(menu_model),
       triggerable_event_flags_(ui::EF_LEFT_MOUSE_BUTTON |
                                ui::EF_RIGHT_MOUSE_BUTTON),
diff --git a/ui/views/controls/menu/menu_model_adapter.h b/ui/views/controls/menu/menu_model_adapter.h
index 240525c..2e4b8f9 100644
--- a/ui/views/controls/menu/menu_model_adapter.h
+++ b/ui/views/controls/menu/menu_model_adapter.h
@@ -30,7 +30,7 @@
   // reflected in the created MenuItemView.
   explicit MenuModelAdapter(ui::MenuModel* menu_model);
   MenuModelAdapter(ui::MenuModel* menu_model,
-                   const base::Closure& on_menu_closed_callback);
+                   const base::RepeatingClosure& on_menu_closed_callback);
   ~MenuModelAdapter() override;
 
   // Populate a MenuItemView menu with the ui::MenuModel items
@@ -108,7 +108,7 @@
   std::map<MenuItemView*, ui::MenuModel*> menu_map_;
 
   // Optional callback triggered during OnMenuClosed().
-  base::Closure on_menu_closed_callback_;
+  base::RepeatingClosure on_menu_closed_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(MenuModelAdapter);
 };
diff --git a/ui/views/controls/menu/menu_runner.cc b/ui/views/controls/menu/menu_runner.cc
index bd16bfc..b0a2f3d 100644
--- a/ui/views/controls/menu/menu_runner.cc
+++ b/ui/views/controls/menu/menu_runner.cc
@@ -14,7 +14,7 @@
 
 MenuRunner::MenuRunner(ui::MenuModel* menu_model,
                        int32_t run_types,
-                       const base::Closure& on_menu_closed_callback)
+                       const base::RepeatingClosure& on_menu_closed_callback)
     : run_types_(run_types),
       impl_(
           internal::MenuRunnerImplInterface::Create(menu_model,
diff --git a/ui/views/controls/menu/menu_runner.h b/ui/views/controls/menu/menu_runner.h
index 967f6f2..549d859 100644
--- a/ui/views/controls/menu/menu_runner.h
+++ b/ui/views/controls/menu/menu_runner.h
@@ -114,7 +114,8 @@
   // The MenuModelDelegate of |menu_model| will be overwritten by this call.
   MenuRunner(ui::MenuModel* menu_model,
              int32_t run_types,
-             const base::Closure& on_menu_closed_callback = base::Closure());
+             const base::RepeatingClosure& on_menu_closed_callback =
+                 base::RepeatingClosure());
 
   // Creates a runner for a custom-created toolkit-views menu.
   MenuRunner(MenuItemView* menu, int32_t run_types);
diff --git a/ui/views/controls/menu/menu_runner_cocoa_unittest.mm b/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
index 89c0fc28..4f9dd1e 100644
--- a/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
+++ b/ui/views/controls/menu/menu_runner_cocoa_unittest.mm
@@ -110,8 +110,8 @@
     native_view_subview_count_ =
         [[parent_->GetNativeView().GetNativeNSView() subviews] count];
 
-    base::Closure on_close = base::Bind(&MenuRunnerCocoaTest::MenuCloseCallback,
-                                        base::Unretained(this));
+    base::RepeatingClosure on_close = base::BindRepeating(
+        &MenuRunnerCocoaTest::MenuCloseCallback, base::Unretained(this));
     if (GetParam() == MenuType::NATIVE)
       runner_ = new internal::MenuRunnerImplCocoa(menu_.get(), on_close);
     else
@@ -296,7 +296,7 @@
     QuitAsyncRunLoop();
   }
 
-  base::Closure quit_closure_;
+  base::RepeatingClosure quit_closure_;
 
   DISALLOW_COPY_AND_ASSIGN(MenuRunnerCocoaTest);
 };
diff --git a/ui/views/controls/menu/menu_runner_impl.cc b/ui/views/controls/menu/menu_runner_impl.cc
index bab3051..ad08635 100644
--- a/ui/views/controls/menu/menu_runner_impl.cc
+++ b/ui/views/controls/menu/menu_runner_impl.cc
@@ -28,7 +28,7 @@
 MenuRunnerImplInterface* MenuRunnerImplInterface::Create(
     ui::MenuModel* menu_model,
     int32_t run_types,
-    const base::Closure& on_menu_closed_callback) {
+    const base::RepeatingClosure& on_menu_closed_callback) {
   return new MenuRunnerImplAdapter(menu_model, on_menu_closed_callback);
 }
 #endif
diff --git a/ui/views/controls/menu/menu_runner_impl_adapter.cc b/ui/views/controls/menu/menu_runner_impl_adapter.cc
index 8b6c0a5..4feef7b 100644
--- a/ui/views/controls/menu/menu_runner_impl_adapter.cc
+++ b/ui/views/controls/menu/menu_runner_impl_adapter.cc
@@ -12,7 +12,7 @@
 
 MenuRunnerImplAdapter::MenuRunnerImplAdapter(
     ui::MenuModel* menu_model,
-    const base::Closure& on_menu_done_callback)
+    const base::RepeatingClosure& on_menu_done_callback)
     : menu_model_adapter_(
           new MenuModelAdapter(menu_model, on_menu_done_callback)),
       impl_(new MenuRunnerImpl(menu_model_adapter_->CreateMenu())) {}
diff --git a/ui/views/controls/menu/menu_runner_impl_adapter.h b/ui/views/controls/menu/menu_runner_impl_adapter.h
index e70d7b60..c1b15458c 100644
--- a/ui/views/controls/menu/menu_runner_impl_adapter.h
+++ b/ui/views/controls/menu/menu_runner_impl_adapter.h
@@ -23,7 +23,7 @@
 class VIEWS_EXPORT MenuRunnerImplAdapter : public MenuRunnerImplInterface {
  public:
   MenuRunnerImplAdapter(ui::MenuModel* menu_model,
-                        const base::Closure& on_menu_closed_callback);
+                        const base::RepeatingClosure& on_menu_closed_callback);
 
   // MenuRunnerImplInterface:
   bool IsRunning() const override;
diff --git a/ui/views/controls/menu/menu_runner_impl_cocoa.h b/ui/views/controls/menu/menu_runner_impl_cocoa.h
index 599000d..0104753 100644
--- a/ui/views/controls/menu/menu_runner_impl_cocoa.h
+++ b/ui/views/controls/menu/menu_runner_impl_cocoa.h
@@ -25,7 +25,7 @@
 class VIEWS_EXPORT MenuRunnerImplCocoa : public MenuRunnerImplInterface {
  public:
   MenuRunnerImplCocoa(ui::MenuModel* menu,
-                      const base::Closure& on_menu_closed_callback);
+                      const base::RepeatingClosure& on_menu_closed_callback);
 
   bool IsRunning() const override;
   void Release() override;
@@ -55,7 +55,7 @@
   base::TimeTicks closing_event_time_;
 
   // Invoked before RunMenuAt() returns, except upon a Release().
-  base::Closure on_menu_closed_callback_;
+  base::RepeatingClosure on_menu_closed_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(MenuRunnerImplCocoa);
 };
diff --git a/ui/views/controls/menu/menu_runner_impl_cocoa.mm b/ui/views/controls/menu/menu_runner_impl_cocoa.mm
index f67cdcbd..4886786 100644
--- a/ui/views/controls/menu/menu_runner_impl_cocoa.mm
+++ b/ui/views/controls/menu/menu_runner_impl_cocoa.mm
@@ -122,7 +122,7 @@
 MenuRunnerImplInterface* MenuRunnerImplInterface::Create(
     ui::MenuModel* menu_model,
     int32_t run_types,
-    const base::Closure& on_menu_closed_callback) {
+    const base::RepeatingClosure& on_menu_closed_callback) {
   if ((run_types & MenuRunner::CONTEXT_MENU) &&
       !(run_types & MenuRunner::IS_NESTED)) {
     return new MenuRunnerImplCocoa(menu_model, on_menu_closed_callback);
@@ -132,7 +132,7 @@
 
 MenuRunnerImplCocoa::MenuRunnerImplCocoa(
     ui::MenuModel* menu,
-    const base::Closure& on_menu_closed_callback)
+    const base::RepeatingClosure& on_menu_closed_callback)
     : running_(false),
       delete_after_run_(false),
       closing_event_time_(base::TimeTicks()),
diff --git a/ui/views/controls/menu/menu_runner_impl_interface.h b/ui/views/controls/menu/menu_runner_impl_interface.h
index f6e5bd0..9661f40 100644
--- a/ui/views/controls/menu/menu_runner_impl_interface.h
+++ b/ui/views/controls/menu/menu_runner_impl_interface.h
@@ -26,7 +26,7 @@
   static MenuRunnerImplInterface* Create(
       ui::MenuModel* menu_model,
       int32_t run_types,
-      const base::Closure& on_menu_closed_callback);
+      const base::RepeatingClosure& on_menu_closed_callback);
 
   // Returns true if we're in a nested run loop running the menu.
   virtual bool IsRunning() const = 0;
diff --git a/ui/views/controls/scroll_view_unittest.cc b/ui/views/controls/scroll_view_unittest.cc
index 377b8fa..6f0a067b 100644
--- a/ui/views/controls/scroll_view_unittest.cc
+++ b/ui/views/controls/scroll_view_unittest.cc
@@ -325,7 +325,7 @@
   // Disable scrollbar hiding (i.e. disable overlay scrollbars) by default.
   bool use_overlay_scrollers_ = false;
 
-  base::Closure quit_closure_;
+  base::RepeatingClosure quit_closure_;
 
 #if defined(OS_MACOSX)
   std::unique_ptr<ui::test::ScopedPreferredScrollerStyle> scroller_style_;
diff --git a/ui/views/linux_ui/linux_ui.h b/ui/views/linux_ui/linux_ui.h
index 9206e18..c1b3a57b 100644
--- a/ui/views/linux_ui/linux_ui.h
+++ b/ui/views/linux_ui/linux_ui.h
@@ -79,8 +79,8 @@
     kRightClick,
   };
 
-  typedef base::Callback<ui::NativeTheme*(aura::Window* window)>
-      NativeThemeGetter;
+  using NativeThemeGetter =
+      base::RepeatingCallback<ui::NativeTheme*(aura::Window* window)>;
 
   ~LinuxUI() override {}
 
@@ -114,7 +114,7 @@
   virtual ui::NativeTheme* GetNativeTheme(aura::Window* window) const = 0;
 
   // Used to set an override NativeTheme.
-  virtual void SetNativeThemeOverride(const NativeThemeGetter& callback) = 0;
+  virtual void SetNativeThemeOverride(NativeThemeGetter callback) = 0;
 
   // Returns whether we should be using the native theme provided by this
   // object by default.
diff --git a/ui/views/mus/desktop_window_tree_host_mus.cc b/ui/views/mus/desktop_window_tree_host_mus.cc
index 3b0cda498..22a3a4b 100644
--- a/ui/views/mus/desktop_window_tree_host_mus.cc
+++ b/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -151,10 +151,10 @@
 };
 
 void OnMoveLoopEnd(bool* out_success,
-                   base::Closure quit_closure,
+                   base::OnceClosure quit_closure,
                    bool in_success) {
   *out_success = in_success;
-  quit_closure.Run();
+  std::move(quit_closure).Run();
 }
 
 }  // namespace
diff --git a/ui/views/test/x11_property_change_waiter.cc b/ui/views/test/x11_property_change_waiter.cc
index 5747ee6b..f4ca1952 100644
--- a/ui/views/test/x11_property_change_waiter.cc
+++ b/ui/views/test/x11_property_change_waiter.cc
@@ -4,6 +4,8 @@
 
 #include "ui/views/test/x11_property_change_waiter.h"
 
+#include <utility>
+
 #include "base/run_loop.h"
 #include "ui/base/x/x11_window_event_manager.h"
 #include "ui/events/platform/platform_event_source.h"
@@ -64,7 +66,7 @@
 
   wait_ = false;
   if (!quit_closure_.is_null())
-    quit_closure_.Run();
+    std::move(quit_closure_).Run();
   return ui::POST_DISPATCH_PERFORM_DEFAULT;
 }
 
diff --git a/ui/views/test/x11_property_change_waiter.h b/ui/views/test/x11_property_change_waiter.h
index 7f1eec3f..1ab020a 100644
--- a/ui/views/test/x11_property_change_waiter.h
+++ b/ui/views/test/x11_property_change_waiter.h
@@ -53,7 +53,7 @@
   bool wait_;
 
   // Ends the run loop.
-  base::Closure quit_closure_;
+  base::OnceClosure quit_closure_;
 
   std::unique_ptr<ui::ScopedEventDispatcher> dispatcher_;
 
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
index 58f5681..bc93e06 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
@@ -343,8 +343,8 @@
 }
 
 void QuitNestedLoopAndCloseWidget(std::unique_ptr<Widget> widget,
-                                  base::Closure* quit_runloop) {
-  quit_runloop->Run();
+                                  base::OnceClosure quit_runloop) {
+  std::move(quit_runloop).Run();
 }
 
 // Verifies that a widget can be destroyed when running a nested message-loop.
@@ -360,11 +360,9 @@
   // task will be executed from the nested loop initiated with the call to
   // |RunWithDispatcher()| below.
   base::RunLoop run_loop;
-  base::Closure quit_runloop = run_loop.QuitClosure();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&QuitNestedLoopAndCloseWidget, std::move(widget),
-                     base::Unretained(&quit_runloop)));
+      FROM_HERE, base::BindOnce(&QuitNestedLoopAndCloseWidget,
+                                std::move(widget), run_loop.QuitClosure()));
   run_loop.Run();
 }
 
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
index 6f98928..d460531 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -2366,8 +2366,7 @@
   return gfx::ToEnclosingRect(rect_in_pixels);
 }
 
-std::unique_ptr<base::Closure>
-DesktopWindowTreeHostX11::DisableEventListening() {
+base::OnceClosure DesktopWindowTreeHostX11::DisableEventListening() {
   // Allows to open multiple file-pickers. See https://crbug.com/678982
   modal_dialog_counter_++;
   if (modal_dialog_counter_ == 1) {
@@ -2377,9 +2376,8 @@
         window(), std::make_unique<aura::NullWindowTargeter>());
   }
 
-  return std::make_unique<base::Closure>(
-      base::Bind(&DesktopWindowTreeHostX11::EnableEventListening,
-                 weak_factory_.GetWeakPtr()));
+  return base::BindOnce(&DesktopWindowTreeHostX11::EnableEventListening,
+                        weak_factory_.GetWeakPtr());
 }
 
 void DesktopWindowTreeHostX11::EnableEventListening() {
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
index c547609..43bd1f4e 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
@@ -86,7 +86,7 @@
   static void CleanUpWindowList(void (*func)(aura::Window* window));
 
   // Disables event listening to make |dialog| modal.
-  std::unique_ptr<base::Closure> DisableEventListening();
+  base::OnceClosure DisableEventListening();
 
   // Returns a map of KeyboardEvent code to KeyboardEvent key values.
   base::flat_map<std::string, std::string> GetKeyboardLayoutMap() override;
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
index eb61fb3..f6a6d7b 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11_unittest.cc
@@ -162,12 +162,6 @@
   return false;
 }
 
-// Flush the message loop.
-void RunAllPendingInMessageLoop() {
-  base::RunLoop run_loop;
-  run_loop.RunUntilIdle();
-}
-
 }  // namespace
 
 class DesktopWindowTreeHostX11Test : public ViewsTestBase {
@@ -259,7 +253,7 @@
     }
 
     // Ensure that the task which is posted when a window is resized is run.
-    RunAllPendingInMessageLoop();
+    base::RunLoop().RunUntilIdle();
 
     // xvfb does not support Xrandr so we cannot check the maximized window's
     // bounds.
diff --git a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
index 593f24d..fb7313d4 100644
--- a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
+++ b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.cc
@@ -234,7 +234,7 @@
   grab_input_window_ = x11::None;
 
   in_move_loop_ = false;
-  quit_closure_.Run();
+  std::move(quit_closure_).Run();
 }
 
 bool X11WholeScreenMoveLoop::GrabPointer(gfx::NativeCursor cursor) {
diff --git a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h
index 37c718e..62631fa2 100644
--- a/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h
+++ b/ui/views/widget/desktop_aura/x11_whole_screen_move_loop.h
@@ -84,7 +84,7 @@
   // Whether the pointer was grabbed on |grab_input_window_|.
   bool grabbed_pointer_;
 
-  base::Closure quit_closure_;
+  base::OnceClosure quit_closure_;
 
   // Keeps track of whether the move-loop is cancled by the user (e.g. by
   // pressing escape).
diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc
index 6bc26ab..533f137 100644
--- a/ui/views/widget/widget_unittest.cc
+++ b/ui/views/widget/widget_unittest.cc
@@ -7,6 +7,7 @@
 #include <set>
 
 #include "base/bind.h"
+#include "base/callback.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
@@ -2182,22 +2183,22 @@
 // destroyed.
 class CloseDestroysWidget : public Widget {
  public:
-  explicit CloseDestroysWidget(bool* destroyed)
-      : destroyed_(destroyed) {
+  CloseDestroysWidget(bool* destroyed, base::OnceClosure quit_closure)
+      : destroyed_(destroyed), quit_closure_(std::move(quit_closure)) {
+    DCHECK(destroyed_);
+    DCHECK(quit_closure_);
   }
 
   ~CloseDestroysWidget() override {
-    if (destroyed_) {
-      *destroyed_ = true;
-      base::RunLoop::QuitCurrentDeprecated();
-    }
+    *destroyed_ = true;
+    std::move(quit_closure_).Run();
   }
 
   void Detach() { destroyed_ = NULL; }
 
  private:
-  // If non-null set to true from destructor.
   bool* destroyed_;
+  base::OnceClosure quit_closure_;
 
   DISALLOW_COPY_AND_ASSIGN(CloseDestroysWidget);
 };
@@ -2243,7 +2244,9 @@
 // Verifies Close() results in destroying.
 TEST_F(DesktopWidgetTest, CloseDestroys) {
   bool destroyed = false;
-  CloseDestroysWidget* widget = new CloseDestroysWidget(&destroyed);
+  base::RunLoop run_loop;
+  CloseDestroysWidget* widget =
+      new CloseDestroysWidget(&destroyed, run_loop.QuitClosure());
   Widget::InitParams params =
       CreateParams(views::Widget::InitParams::TYPE_MENU);
   params.opacity = Widget::InitParams::OPAQUE_WINDOW;
@@ -2253,7 +2256,7 @@
   widget->Close();
   EXPECT_FALSE(destroyed);
   // Run the message loop as Close() asynchronously deletes.
-  base::RunLoop().Run();
+  run_loop.Run();
   EXPECT_TRUE(destroyed);
   // Close() should destroy the widget. If not we'll cleanup to avoid leaks.
   if (!destroyed) {
diff --git a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
index 5b8ba4f..3b4cff4c 100644
--- a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
+++ b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
@@ -14,13 +14,16 @@
         --cr-toolbar-height: 56px;
         --paper-icon-button-ink-color: white;
         align-items: center;
-        /* TODO(dbeam): default background-color instead of external styling. */
+        background-color: var(--google-blue-700);
         color: #fff;
         display: flex;
         height: var(--cr-toolbar-height);
       }
 
       :host-context([dark]) {
+        background-color: rgba(255, 255, 255, .04);
+        border-bottom: var(--cr-separator-line);
+        box-sizing: border-box;
         color: var(--cr-secondary-text-color);
       }
 
diff --git a/ui/webui/resources/css/md_colors.css b/ui/webui/resources/css/md_colors.css
index 28a2dc1..9750520 100644
--- a/ui/webui/resources/css/md_colors.css
+++ b/ui/webui/resources/css/md_colors.css
@@ -9,10 +9,13 @@
   --md-loading-message-color: #6e6e6e;
   /* --google-blue-700, rewritten as a native custom property for speed. */
   --md-toolbar-color: rgb(51, 103, 214);
+  --md-toolbar-height: 56px;
 }
 
 html[dark] {
   --md-background-color: rgb(32, 33, 36);  /* --google-grey-900 */
   --md-loading-message-color: #9AA0A6;  /* --google-grey-refresh-500 */
+  /* --cr-separator-line */
+  --md-toolbar-border: 1px solid rgba(255, 255, 255, .1);
   --md-toolbar-color: rgba(255, 255, 255, .04);
 }