diff --git a/BUILD.gn b/BUILD.gn
index 19b5031..607e439 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -169,6 +169,8 @@
       "//mojo",
       "//mojo:mojo_unittests",
       "//net:net_perftests",
+      "//third_party/angle/src/tests:angle_end2end_tests",
+      "//third_party/angle/src/tests:angle_unittests",
       "//third_party/blink/renderer/controller:webkit_unit_tests",
       "//third_party/blink/renderer/platform/wtf:wtf_unittests",
       "//ui/gl:gl_unittests",
@@ -198,8 +200,6 @@
       "//media/capture:capture_unittests",
       "//media/cast:cast_unittests",
       "//storage:storage_unittests",
-      "//third_party/angle/src/tests:angle_end2end_tests",
-      "//third_party/angle/src/tests:angle_unittests",
       "//third_party/angle/src/tests:angle_white_box_tests",
       "//third_party/blink/common:blink_common_unittests",
       "//third_party/blink/renderer/platform:blink_platform_unittests",
diff --git a/DEPS b/DEPS
index 5dff4331..fa69ead 100644
--- a/DEPS
+++ b/DEPS
@@ -126,11 +126,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': 'ac285b1c2ae3155cd9c7c21283e2cbf7f3010cfa',
+  'skia_revision': 'da5e03954dd3f7c009b413750d438f2eb9657aa2',
   # 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': '29cec8c865f7eee774f859047055ceceba94c764',
+  'v8_revision': 'dd4d1d6417279a9bfe14a1b75dfdd4dcd60c9c0c',
   # 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.
@@ -138,15 +138,15 @@
   # 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': '983e446921946734fe47217c345a8fe2f079319d',
+  'angle_revision': '6fc22a13d45d59348d71674b11ebdb4444134201',
   # 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': '73c3124cc249c2d8810f4c02717366b6f2489255',
+  'swiftshader_revision': 'de16f327d051dd5a33b3b7c4666feea071cd877a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'bff397d7343e011bb3033404440fbe8cd537e560',
+  'pdfium_revision': '2347b79c37817b04cfde4944747ed99fb602c352',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -237,7 +237,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': '354205b3dc2356546571edbde45db7acde6ab730',
+  'spv_tools_revision': '0187c190b58ced2aab3bb54f4603a2c61be5b666',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -253,7 +253,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.
-  'dawn_revision': 'f872e6924cbb7ff75738b9ad6560cdb789a91ac1',
+  'dawn_revision': 'a594f8fdb4d78c06ae1cf5fa4adbcc1210af9b4d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -314,7 +314,7 @@
       'packages': [
           {
               'package': 'chromium/android_webview/tools/cts_archive',
-              'version': '3JR1LoM5xpNK_jcnwciobRW9H8TM3SUxuSGQJBjt6AUC',
+              'version': 'svYF6kVCr4ZLwvgZjFTwSkw3bv08SQ9DhqYnpwcCCugC',
           },
       ],
       'condition': 'checkout_android',
@@ -732,7 +732,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '9a7a9053e8f7f5a6eea2ccaa7964732ba95ef642',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '01a85176b3e4e5541e23aecc0306b788a42faa9a',
       'condition': 'checkout_linux',
   },
 
@@ -986,7 +986,7 @@
   },
 
   'src/third_party/libvpx/source/libvpx':
-    Var('chromium_git') + '/webm/libvpx.git' + '@' +  'ce4336c2ab60d185b431345987b2188511760e54',
+    Var('chromium_git') + '/webm/libvpx.git' + '@' +  'e2381829e984c58e54a7ad0580c168cb7432ef92',
 
   'src/third_party/libwebm/source':
     Var('chromium_git') + '/webm/libwebm.git' + '@' + 'e4931ebc0a816458c18a6734e91a4d1b5acd5c56',
@@ -1296,7 +1296,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@7567f837ecd0f6bfbad2a5e1b21f60f806e8543f',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@37d412aa18ee17f2d453ab8351b1bd6c910d5a2d',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 1d35d467..8ea23ec 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -657,9 +657,13 @@
   // is used to post onPageStarted. We handle shouldOverrideUrlLoading
   // via a sync IPC.
   if (navigation_handle->IsInMainFrame()) {
+    // Use Synchronous mode for the navigation interceptor, since this class
+    // doesn't actually call into an arbitrary client, it just posts a task to
+    // call onPageStarted. shouldOverrideUrlLoading happens earlier (see
+    // ContentBrowserClient::ShouldOverrideUrlLoading).
     throttles.push_back(
         navigation_interception::InterceptNavigationDelegate::CreateThrottleFor(
-            navigation_handle));
+            navigation_handle, navigation_interception::SynchronyMode::kSync));
     throttles.push_back(std::make_unique<PolicyBlacklistNavigationThrottle>(
         navigation_handle, browser_context_.get()));
   }
diff --git a/android_webview/browser/net/aw_cookie_store_wrapper.cc b/android_webview/browser/net/aw_cookie_store_wrapper.cc
index d5cbf30f..afa6edb 100644
--- a/android_webview/browser/net/aw_cookie_store_wrapper.cc
+++ b/android_webview/browser/net/aw_cookie_store_wrapper.cc
@@ -47,12 +47,6 @@
   GetCookieStore()->GetAllCookiesAsync(std::move(callback));
 }
 
-void DeleteCookieAsyncOnCookieThread(const GURL& url,
-                                     const std::string& cookie_name,
-                                     base::OnceClosure callback) {
-  GetCookieStore()->DeleteCookieAsync(url, cookie_name, std::move(callback));
-}
-
 void DeleteCanonicalCookieAsyncOnCookieThread(
     const net::CanonicalCookie& cookie,
     net::CookieStore::DeleteCallback callback) {
@@ -133,15 +127,6 @@
                      CreateWrappedGetCookieListCallback(std::move(callback))));
 }
 
-void AwCookieStoreWrapper::DeleteCookieAsync(const GURL& url,
-                                             const std::string& cookie_name,
-                                             base::OnceClosure callback) {
-  DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
-  PostTaskToCookieStoreTaskRunner(
-      base::BindOnce(&DeleteCookieAsyncOnCookieThread, url, cookie_name,
-                     CreateWrappedClosureCallback(std::move(callback))));
-}
-
 void AwCookieStoreWrapper::DeleteCanonicalCookieAsync(
     const net::CanonicalCookie& cookie,
     DeleteCallback callback) {
diff --git a/android_webview/browser/net/aw_cookie_store_wrapper.h b/android_webview/browser/net/aw_cookie_store_wrapper.h
index bef80a5..dc55e5a 100644
--- a/android_webview/browser/net/aw_cookie_store_wrapper.h
+++ b/android_webview/browser/net/aw_cookie_store_wrapper.h
@@ -55,9 +55,6 @@
                                      const net::CookieOptions& options,
                                      GetCookieListCallback callback) override;
   void GetAllCookiesAsync(GetCookieListCallback callback) override;
-  void DeleteCookieAsync(const GURL& url,
-                         const std::string& cookie_name,
-                         base::OnceClosure callback) override;
   void DeleteCanonicalCookieAsync(const net::CanonicalCookie& cookie,
                                   DeleteCallback callback) override;
   void DeleteAllCreatedInTimeRangeAsync(
diff --git a/android_webview/tools/cts_archive/cipd.yaml b/android_webview/tools/cts_archive/cipd.yaml
index 1ba0f5e..9b095a7 100644
--- a/android_webview/tools/cts_archive/cipd.yaml
+++ b/android_webview/tools/cts_archive/cipd.yaml
@@ -11,3 +11,7 @@
   - file: arm64/M/android-cts-arm_64-4607285.zip
   - file: arm64/N/android-cts-arm_64-5075646.zip
   - file: arm64/O/android-cts-arm_64-5075719.zip
+  - file: x86/L/android-cts-x86-5.1_r28.zip
+  - file: x86/M/android-cts-x86-6.0_r32.zip
+  - file: x86/N/android-cts-x86-7.0_r28.zip
+  - file: x86/O/android-cts-x86-8.0_r16.zip
diff --git a/android_webview/tools/cts_archive/version.txt b/android_webview/tools/cts_archive/version.txt
index 9459d4b..5625e59d 100644
--- a/android_webview/tools/cts_archive/version.txt
+++ b/android_webview/tools/cts_archive/version.txt
@@ -1 +1 @@
-1.1
+1.2
diff --git a/android_webview/tools/cts_config/webview_cts_gcs_path.json b/android_webview/tools/cts_config/webview_cts_gcs_path.json
index 29d0906..664b2a1 100644
--- a/android_webview/tools/cts_config/webview_cts_gcs_path.json
+++ b/android_webview/tools/cts_config/webview_cts_gcs_path.json
@@ -3,11 +3,19 @@
   {
     " The format of this file is as follows.  The excludes and includes lists under test_runs are mutually exclusive, if not specified, all tests in apk will run.":
     {
-      "<arch>": {
-        "<android SDK Code, such as L, M, N, ...>": {
-          "filename": "<relative path to cts_archive_dir of cts zip>",
-          "_origin":  "<branch@buildid>",
-          "unzip_dir":   "<relative path to work directory where cts should be unzipped to>",
+      "<android SDK Code, such as L, M, N, ...>": {
+        "arch": {
+	  "<arch1>": {
+            "filename": "<relative path to cts_archive_dir of cts zip>",
+            "_origin":  "<branch@buildid>",
+            "unzip_dir":   "<relative path to work directory where cts should be unzipped to>"
+	  },
+	  "<arch2>": {
+            "filename": "<relative path to cts_archive_dir of cts zip>",
+            "_origin":  "<branch@buildid>",
+            "unzip_dir":   "<relative path to work directory where cts should be unzipped to>"
+	  }
+	},
           "test_runs": [
           {
             "apk": "location of the test apk in the cts zip file",
@@ -26,14 +34,21 @@
           }]
         }
       }
-    }
   },
-  "arm64": {
-    "L": {
-      "filename": "arm64/L/android-cts-arm_64-4607260.zip",
-      "_origin": "aosp-lollipop-mr1-cts-dev@4607260",
-      "unzip_dir": "arm64/L/4607260/",
-      "test_runs": [
+  "L": {
+    "arch": {
+      "arm64": {
+        "filename": "arm64/L/android-cts-arm_64-4607260.zip",
+        "_origin": "aosp-lollipop-mr1-cts-dev@4607260",
+        "unzip_dir": "arm64/L/4607260/"
+      },
+      "x86": {
+        "filename": "x86/L/android-cts-x86-5.1_r28.zip",
+        "_origin": "aosp-lollipop-mr1-cts-release@5.1_r28",
+        "unzip_dir": "x86/L/5.1_r28/"
+      }
+    },
+    "test_runs": [
       {
         "apk": "android-cts/repository/testcases/CtsWebkitTestCases.apk",
         "excludes": [
@@ -94,12 +109,21 @@
           "match": "android.widget.cts.RemoteViewsActivityTest#testWebView"
         }]
       }]
+  },
+  "M": {
+    "arch": {
+      "arm64": {
+        "filename": "arm64/M/android-cts-arm_64-4607285.zip",
+        "_origin": "aosp-marshmallow-cts-dev@4607285",
+        "unzip_dir": "arm64/M/4607285/"
+      },
+      "x86": {
+      "filename": "x86/M/android-cts-x86-6.0_r32.zip",
+      "_origin": "aosp-marshmallow-cts-release@6.0_r32",
+      "unzip_dir": "x86/M/6.0_r32/"
+      }
     },
-    "M": {
-      "filename": "arm64/M/android-cts-arm_64-4607285.zip",
-      "_origin": "aosp-marshmallow-cts-dev@4607285",
-      "unzip_dir": "arm64/M/4607285/",
-      "test_runs": [
+    "test_runs": [
       {
         "apk": "android-cts/repository/testcases/CtsWebkitTestCases.apk",
         "excludes": [
@@ -160,11 +184,20 @@
           "match": "android.widget.cts.RemoteViewsActivityTest#testWebView"
         }]
       }]
+  },
+  "N": {
+    "arch": {
+      "arm64": {
+        "filename": "arm64/N/android-cts-arm_64-5075646.zip",
+        "_origin": "aosp-nougat-cts-dev@5075646",
+        "unzip_dir": "arm64/N/5075646/"
+      },
+      "x86": {
+      "filename": "x86/N/android-cts-x86-7.0_r28.zip",
+      "_origin": "aosp-nougat-cts-release@7.0_r28",
+      "unzip_dir": "x86/N/7.0_r28/"
+      }
     },
-    "N": {
-      "filename": "arm64/N/android-cts-arm_64-5075646.zip",
-      "_origin": "aosp-nougat-cts-dev@5075646",
-      "unzip_dir": "arm64/N/5075646/",
       "test_runs": [
       {
         "apk": "android-cts/testcases/CtsWebkitTestCases.apk",
@@ -182,11 +215,20 @@
           "match": "android.widget.cts.RemoteViewsActivityTest#testWebView"
         }]
       }]
+  },
+  "O": {
+    "arch": {
+      "arm64": {
+        "filename": "arm64/O/android-cts-arm_64-5075719.zip",
+        "_origin": "aosp-oreo-cts-dev@5075719",
+        "unzip_dir": "arm64/O/5075719/"
+      },
+      "x86": {
+      "filename": "x86/O/android-cts-x86-8.0_r16.zip",
+      "_origin": "aosp-oreo-cts-release@8.0_r16",
+      "unzip_dir": "x86/O/8.0_r16/"
+      }
     },
-    "O": {
-      "filename": "arm64/O/android-cts-arm_64-5075719.zip",
-      "_origin": "aosp-oreo-cts-dev@5075719",
-      "unzip_dir": "arm64/O/5075719/",
       "test_runs": [
       {
         "apk": "android-cts/testcases/CtsWebkitTestCases.apk",
@@ -200,6 +242,5 @@
       {
         "apk": "android-cts/testcases/CtsWebViewStartupApp.apk"
       }]
-    }
   }
 }
diff --git a/android_webview/tools/run_cts.py b/android_webview/tools/run_cts.py
index 2a9fff8..11f26bef 100755
--- a/android_webview/tools/run_cts.py
+++ b/android_webview/tools/run_cts.py
@@ -35,8 +35,11 @@
 
 _EXPECTED_FAILURES_FILE = os.path.join(
     os.path.dirname(__file__), 'cts_config', 'expected_failure_on_bot.json')
+
 _WEBVIEW_CTS_GCS_PATH_FILE = os.path.join(
     os.path.dirname(__file__), 'cts_config', 'webview_cts_gcs_path.json')
+_ARCH_SPECIFIC_CTS_INFO = ["filename", "unzip_dir", "_origin"]
+
 _CTS_ARCHIVE_DIR = os.path.join(os.path.dirname(__file__), 'cts_archive')
 
 _SDK_PLATFORM_DICT = {
@@ -49,13 +52,22 @@
     version_codes.OREO_MR1: 'O'
 }
 
-# TODO(aluo): support 'x86' and 'x86_64'
+# The test apks are apparently compatible across all architectures, the
+# arm vs x86 split is to match the current cts releases and in case things
+# start to diverge in the future.  Keeping the arm64 (instead of arm) dict
+# key to avoid breaking the bots that specify --arch arm64 to invoke the tests.
 _SUPPORTED_ARCH_DICT = {
-    abis.ARM_64: 'arm64',
+    # TODO(aluo): Investigate how to force WebView abi on platforms supporting
+    # multiple abis.
     # The test apks under 'arm64' support both arm and arm64 devices.
     abis.ARM: 'arm64',
+    abis.ARM_64: 'arm64',
+    # The test apks under 'x86' support both x86 and x86_64 devices.
+    abis.X86: 'x86',
+    abis.X86_64: 'x86'
 }
 
+
 FILE_FILTER_OPT = '--test-launcher-filter-file'
 TEST_FILTER_OPT = '--test-filter'
 ISOLATED_FILTER_OPT = '--isolated-script-test-filter'
@@ -68,7 +80,10 @@
   with open(_WEBVIEW_CTS_GCS_PATH_FILE) as f:
     cts_gcs_path_info = json.load(f)
   try:
-    return cts_gcs_path_info[arch][platform][item]
+    if item in _ARCH_SPECIFIC_CTS_INFO:
+      return cts_gcs_path_info[platform]['arch'][arch][item]
+    else:
+      return cts_gcs_path_info[platform][item]
   except KeyError:
     raise Exception('No %s info available for arch:%s, android:%s' %
                     (item, arch, platform))
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index fb4107b..e87884f 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -702,6 +702,15 @@
   presenter_.SetExpandArrowViewVisibility(should_show);
 }
 
+app_list::AppListViewState AppListControllerImpl::CalculateStateAfterShelfDrag(
+    const ui::GestureEvent& gesture_in_screen,
+    float launcher_above_shelf_bottom_amount) const {
+  if (presenter_.GetView())
+    return presenter_.GetView()->CalculateStateAfterShelfDrag(
+        gesture_in_screen, launcher_above_shelf_bottom_amount);
+  return app_list::AppListViewState::CLOSED;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Methods of |client_|:
 
diff --git a/ash/app_list/app_list_controller_impl.h b/ash/app_list/app_list_controller_impl.h
index ce85fc78..b6f251f 100644
--- a/ash/app_list/app_list_controller_impl.h
+++ b/ash/app_list/app_list_controller_impl.h
@@ -255,9 +255,14 @@
   // Returns current visibility of the Assistant page.
   bool IsShowingEmbeddedAssistantUI() const;
 
-  // Update the visibility of expand arrow view.
+  // Updates the visibility of expand arrow view.
   void UpdateExpandArrowVisibility();
 
+  // Get updated app list view state after dragging from shelf.
+  app_list::AppListViewState CalculateStateAfterShelfDrag(
+      const ui::GestureEvent& gesture_in_screen,
+      float launcher_above_shelf_bottom_amount) const;
+
  private:
   syncer::StringOrdinal GetOemFolderPos();
   std::unique_ptr<app_list::AppListItem> CreateAppListItem(
diff --git a/ash/app_list/presenter/app_list_presenter_impl.h b/ash/app_list/presenter/app_list_presenter_impl.h
index 7d1c13dc..a33c2fb 100644
--- a/ash/app_list/presenter/app_list_presenter_impl.h
+++ b/ash/app_list/presenter/app_list_presenter_impl.h
@@ -57,6 +57,7 @@
 
   // Returns app list view if one exists, or NULL otherwise.
   AppListView* GetView() { return view_; }
+  const AppListView* GetView() const { return view_; }
 
   // Show the app list window on the display with the given id. If
   // |event_time_stamp| is not 0, it means |Show()| was triggered by one of the
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 2558adb9..1c7b78b 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -69,10 +69,6 @@
 // order to transition to the next state.
 constexpr int kAppListThresholdDenominator = 3;
 
-// The velocity the app list must be dragged in order to transition to the next
-// state, measured in DIPs/event.
-constexpr int kAppListDragVelocityThreshold = 6;
-
 // The scroll offset in order to transition from PEEKING to FULLSCREEN
 constexpr int kAppListMinScrollToSwitchStates = 20;
 
@@ -736,7 +732,7 @@
   // Change the app list state based on where the drag ended. If fling velocity
   // was over the threshold, snap to the next state in the direction of the
   // fling.
-  if (std::abs(last_fling_velocity_) >= kAppListDragVelocityThreshold) {
+  if (std::abs(last_fling_velocity_) >= kDragVelocityThreshold) {
     // If the user releases drag with velocity over the threshold, snap to
     // the next state, ignoring the drag release position.
 
@@ -1514,6 +1510,49 @@
   return display_bounds.height() - display.work_area().y() + display_bounds.y();
 }
 
+AppListViewState AppListView::CalculateStateAfterShelfDrag(
+    const ui::GestureEvent& gesture_in_screen,
+    float launcher_above_shelf_bottom_amount) const {
+  AppListViewState app_list_state = AppListViewState::PEEKING;
+  if (gesture_in_screen.type() == ui::ET_SCROLL_FLING_START &&
+      fabs(gesture_in_screen.details().velocity_y()) > kDragVelocityThreshold) {
+    // If the scroll sequence terminates with a fling, show the fullscreen app
+    // list if the fling was fast enough and in the correct direction, otherwise
+    // close it.
+    app_list_state = gesture_in_screen.details().velocity_y() < 0
+                         ? AppListViewState::FULLSCREEN_ALL_APPS
+                         : AppListViewState::CLOSED;
+  } else {
+    // Snap the app list to corresponding state according to the snapping
+    // thresholds.
+    if (is_tablet_mode_) {
+      app_list_state =
+          launcher_above_shelf_bottom_amount > kDragSnapToFullscreenThreshold
+              ? AppListViewState::FULLSCREEN_ALL_APPS
+              : AppListViewState::CLOSED;
+    } else {
+      if (launcher_above_shelf_bottom_amount <= kDragSnapToClosedThreshold)
+        app_list_state = AppListViewState::CLOSED;
+      else if (launcher_above_shelf_bottom_amount <=
+               kDragSnapToPeekingThreshold)
+        app_list_state = AppListViewState::PEEKING;
+      else
+        app_list_state = AppListViewState::FULLSCREEN_ALL_APPS;
+    }
+  }
+
+  // Deal with the situation of dragging app list from shelf while typing in
+  // the search box.
+  if (app_list_state == AppListViewState::FULLSCREEN_ALL_APPS) {
+    ash::AppListState active_state =
+        app_list_main_view_->contents_view()->GetActiveState();
+    if (active_state == ash::AppListState::kStateSearchResults)
+      app_list_state = AppListViewState::FULLSCREEN_SEARCH;
+  }
+
+  return app_list_state;
+}
+
 void AppListView::UpdateChildViewsYPositionAndOpacity() {
   if (app_list_state_ == AppListViewState::CLOSED)
     return;
diff --git a/ash/app_list/views/app_list_view.h b/ash/app_list/views/app_list_view.h
index c8654749..589343c 100644
--- a/ash/app_list/views/app_list_view.h
+++ b/ash/app_list/views/app_list_view.h
@@ -86,6 +86,19 @@
   // its state.
   static constexpr int kScrollIgnoreTimeMs = 500;
 
+  // The snapping threshold for dragging app list from shelf in tablet mode,
+  // measured in DIPs.
+  static constexpr int kDragSnapToFullscreenThreshold = 320;
+
+  // The snapping thresholds for dragging app list from shelf in laptop mode,
+  // measured in DIPs.
+  static constexpr int kDragSnapToClosedThreshold = 144;
+  static constexpr int kDragSnapToPeekingThreshold = 561;
+
+  // The velocity the app list must be dragged in order to transition to the
+  // next state, measured in DIPs/event.
+  static constexpr int kDragVelocityThreshold = 6;
+
   struct InitParams {
     gfx::NativeView parent = nullptr;
     int initial_apps_page = 0;
@@ -215,6 +228,12 @@
   // Returns the height of app list in fullscreen state.
   int GetFullscreenStateHeight() const;
 
+  // Calculates and returns the app list view state after dragging from shelf
+  // ends.
+  AppListViewState CalculateStateAfterShelfDrag(
+      const ui::GestureEvent& gesture_in_screen,
+      float launcher_above_shelf_bottom_amount) const;
+
   views::Widget* get_fullscreen_widget_for_test() const {
     return fullscreen_widget_;
   }
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc
index 7282294..54ba038 100644
--- a/ash/app_list/views/apps_grid_view.cc
+++ b/ash/app_list/views/apps_grid_view.cc
@@ -2264,6 +2264,12 @@
   if (strcmp(sender->GetClassName(), AppListItemView::kViewClassName))
     return;
 
+  if (contents_view_->GetAppsContainerView()
+          ->app_list_folder_view()
+          ->IsAnimationRunning()) {
+    return;
+  }
+
   // Always set the previous activated_folder_item_view_ to be visible. This
   // prevents a case where the item would remain hidden due the
   // |activated_folder_item_view_| changing during the animation. We only
diff --git a/ash/magnifier/magnification_controller.cc b/ash/magnifier/magnification_controller.cc
index 601b19f6..ad1458b4 100644
--- a/ash/magnifier/magnification_controller.cc
+++ b/ash/magnifier/magnification_controller.cc
@@ -4,6 +4,7 @@
 
 #include "ash/magnifier/magnification_controller.h"
 
+#include <algorithm>
 #include <memory>
 #include <utility>
 #include <vector>
@@ -490,14 +491,14 @@
     SwitchTargetRootWindow(current_root, true);
 }
 
-ui::EventRewriteStatus MagnificationController::RewriteEvent(
+ui::EventDispatchDetails MagnificationController::RewriteEvent(
     const ui::Event& event,
-    std::unique_ptr<ui::Event>* rewritten_event) {
+    const Continuation continuation) {
   if (!IsEnabled())
-    return ui::EVENT_REWRITE_CONTINUE;
+    return SendEvent(continuation, &event);
 
   if (!event.IsTouchEvent())
-    return ui::EVENT_REWRITE_CONTINUE;
+    return SendEvent(continuation, &event);
 
   const ui::TouchEvent* touch_event = event.AsTouchEvent();
 
@@ -516,7 +517,7 @@
         touch_event_copy.unique_event_id(), false /* event_consumed */,
         false /* is_source_touch_event_set_non_blocking */);
   } else {
-    return ui::EVENT_REWRITE_DISCARD;
+    return DiscardEvent(continuation);
   }
 
   // User can change zoom level with two fingers pinch and pan around with two
@@ -547,12 +548,13 @@
       // TouchExplorationController confused. Send cancelled event for recorded
       // touch events to the next event rewriter here instead of rewriting an
       // event in the stream.
-      SendEventToEventSource(root_window_->GetHost()->GetEventSource(),
-                             &touch_cancel_event);
+      ui::EventDispatchDetails details =
+          SendEvent(continuation, &touch_cancel_event);
+      if (details.dispatcher_destroyed || details.target_destroyed)
+        return details;
     }
     press_event_map_.clear();
   }
-
   bool discard = consume_touch_event_;
 
   // Reset state once no point is touched on the screen.
@@ -570,16 +572,9 @@
   }
 
   if (discard)
-    return ui::EVENT_REWRITE_DISCARD;
+    return DiscardEvent(continuation);
 
-  return ui::EVENT_REWRITE_CONTINUE;
-}
-
-ui::EventRewriteStatus MagnificationController::NextDispatchEvent(
-    const ui::Event& last_event,
-    std::unique_ptr<ui::Event>* new_event) {
-  NOTREACHED();
-  return ui::EVENT_REWRITE_CONTINUE;
+  return SendEvent(continuation, &event);
 }
 
 bool MagnificationController::Redraw(const gfx::PointF& position,
diff --git a/ash/magnifier/magnification_controller.h b/ash/magnifier/magnification_controller.h
index 119d396..98d1451 100644
--- a/ash/magnifier/magnification_controller.h
+++ b/ash/magnifier/magnification_controller.h
@@ -164,12 +164,9 @@
   void OnTouchEvent(ui::TouchEvent* event) override;
 
   // ui::EventRewriter overrides:
-  ui::EventRewriteStatus RewriteEvent(
+  ui::EventDispatchDetails RewriteEvent(
       const ui::Event& event,
-      std::unique_ptr<ui::Event>* new_event) override;
-  ui::EventRewriteStatus NextDispatchEvent(
-      const ui::Event& last_event,
-      std::unique_ptr<ui::Event>* new_event) override;
+      const Continuation continuation) override;
 
   // Redraws the magnification window with the given origin position and the
   // given scale. Returns true if the window is changed; otherwise, false.
diff --git a/ash/public/cpp/shelf_types.h b/ash/public/cpp/shelf_types.h
index fdf2c1f2..d21997bd 100644
--- a/ash/public/cpp/shelf_types.h
+++ b/ash/public/cpp/shelf_types.h
@@ -53,15 +53,13 @@
   // The default transparent background.
   SHELF_BACKGROUND_DEFAULT,
 
-  // The background when a window is maximized.
+  // The background when a window is maximized or two windows are maximized
+  // for a split view.
   SHELF_BACKGROUND_MAXIMIZED,
 
   // The background when fullscreen app list is visible.
   SHELF_BACKGROUND_APP_LIST,
 
-  // The background when split view mode is active.
-  SHELF_BACKGROUND_SPLIT_VIEW,
-
   // The background when OOBE is active.
   SHELF_BACKGROUND_OOBE,
 
diff --git a/ash/shelf/app_list_button_unittest.cc b/ash/shelf/app_list_button_unittest.cc
index 0a846c7..fa0bbb0 100644
--- a/ash/shelf/app_list_button_unittest.cc
+++ b/ash/shelf/app_list_button_unittest.cc
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "ash/app_list/test/app_list_test_helper.h"
+#include "ash/app_list/views/app_list_view.h"
 #include "ash/assistant/assistant_controller.h"
 #include "ash/assistant/assistant_ui_controller.h"
 #include "ash/assistant/model/assistant_ui_model.h"
@@ -15,7 +16,6 @@
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
 #include "ash/shelf/shelf.h"
-#include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shelf/shelf_view.h"
 #include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shell.h"
@@ -79,7 +79,7 @@
   // Swiping up less than the threshold should trigger a peeking app list.
   gfx::Point end = start;
   end.set_y(shelf->GetIdealBounds().bottom() -
-            ShelfLayoutManager::kAppListDragSnapToPeekingThreshold + 10);
+            app_list::AppListView::kDragSnapToPeekingThreshold + 10);
   GetEventGenerator()->GestureScrollSequence(
       start, end, base::TimeDelta::FromMilliseconds(100), 4 /* steps */);
   GetAppListTestHelper()->WaitUntilIdle();
@@ -93,7 +93,7 @@
 
   // Swiping above the threshold should trigger a fullscreen app list.
   end.set_y(shelf->GetIdealBounds().bottom() -
-            ShelfLayoutManager::kAppListDragSnapToPeekingThreshold - 10);
+            app_list::AppListView::kDragSnapToPeekingThreshold - 10);
   GetEventGenerator()->GestureScrollSequence(
       start, end, base::TimeDelta::FromMilliseconds(100), 4 /* steps */);
   base::RunLoop().RunUntilIdle();
diff --git a/ash/shelf/shelf_background_animator.cc b/ash/shelf/shelf_background_animator.cc
index e9619baeb..46c7599 100644
--- a/ash/shelf/shelf_background_animator.cc
+++ b/ash/shelf/shelf_background_animator.cc
@@ -149,8 +149,6 @@
       return kShelfTranslucentMaximizedWindow;
     case SHELF_BACKGROUND_APP_LIST:
       return kShelfTranslucentOverAppList;
-    case SHELF_BACKGROUND_SPLIT_VIEW:
-      return ShelfBackgroundAnimator::kMaxAlpha;
     case SHELF_BACKGROUND_OOBE:
       return SK_AlphaTRANSPARENT;
     case SHELF_BACKGROUND_LOGIN:
@@ -227,7 +225,6 @@
       duration_ms = 500;
       break;
     case SHELF_BACKGROUND_MAXIMIZED:
-    case SHELF_BACKGROUND_SPLIT_VIEW:
     case SHELF_BACKGROUND_OOBE:
     case SHELF_BACKGROUND_LOGIN:
     case SHELF_BACKGROUND_LOGIN_NONBLURRED_WALLPAPER:
@@ -273,7 +270,6 @@
       shelf_target_color = darken_wallpaper(kShelfTranslucentColorDarkenAlpha);
       break;
     case SHELF_BACKGROUND_MAXIMIZED:
-    case SHELF_BACKGROUND_SPLIT_VIEW:
       shelf_target_color = darken_wallpaper(kShelfOpaqueColorDarkenAlpha);
       break;
     case SHELF_BACKGROUND_OOBE:
diff --git a/ash/shelf/shelf_background_animator_unittest.cc b/ash/shelf/shelf_background_animator_unittest.cc
index 42dc95a..22b2c91 100644
--- a/ash/shelf/shelf_background_animator_unittest.cc
+++ b/ash/shelf/shelf_background_animator_unittest.cc
@@ -26,8 +26,6 @@
 namespace ash {
 namespace {
 
-static auto kMaxAlpha = ShelfBackgroundAnimator::kMaxAlpha;
-
 // A valid color value that is distinct from any final animation state values.
 // Used to check if color values are changed during animations.
 const SkColor kDummyColor = SK_ColorBLUE;
@@ -216,14 +214,6 @@
   EXPECT_EQ(kShelfTranslucentMaximizedWindow, observer_.GetBackgroundAlpha());
 }
 
-// Verify the alpha values for the SHELF_BACKGROUND_SPLIT_VIEW state.
-TEST_F(ShelfBackgroundAnimatorTest, SplitViewBackground) {
-  PaintBackground(SHELF_BACKGROUND_SPLIT_VIEW);
-
-  EXPECT_EQ(SHELF_BACKGROUND_SPLIT_VIEW, animator_->target_background_type());
-  EXPECT_EQ(kMaxAlpha, observer_.GetBackgroundAlpha());
-}
-
 // Verify the alpha values for the SHELF_BACKGROUND_APP_LIST state.
 TEST_F(ShelfBackgroundAnimatorTest, FullscreenAppListBackground) {
   PaintBackground(SHELF_BACKGROUND_APP_LIST);
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index b6d66c8..410a5f4 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -481,15 +481,12 @@
       return SHELF_BACKGROUND_DEFAULT;
   }
 
-  if (state_.visibility_state != SHELF_AUTO_HIDE &&
-      state_.window_state == wm::WORKSPACE_WINDOW_STATE_MAXIMIZED) {
+  if (Shell::Get()->IsSplitViewModeActive() ||
+      (state_.visibility_state != SHELF_AUTO_HIDE &&
+       state_.window_state == wm::WORKSPACE_WINDOW_STATE_MAXIMIZED)) {
     return SHELF_BACKGROUND_MAXIMIZED;
   }
 
-  // If split view mode is active, make the shelf fully opapue.
-  if (Shell::Get()->IsSplitViewModeActive())
-    return SHELF_BACKGROUND_SPLIT_VIEW;
-
   if (Shell::Get()->overview_controller() &&
       Shell::Get()->overview_controller()->IsSelecting()) {
     return SHELF_BACKGROUND_OVERVIEW;
@@ -1402,42 +1399,15 @@
   }
 
   using app_list::AppListViewState;
-  AppListViewState app_list_state = AppListViewState::PEEKING;
-  if (gesture_in_screen.type() == ui::ET_SCROLL_FLING_START &&
-      fabs(gesture_in_screen.details().velocity_y()) >
-          kAppListDragVelocityThreshold) {
-    // If the scroll sequence terminates with a fling, show the fullscreen app
-    // list if the fling was fast enough and in the correct direction, otherwise
-    // close it.
-    app_list_state = gesture_in_screen.details().velocity_y() < 0
-                         ? AppListViewState::FULLSCREEN_ALL_APPS
-                         : AppListViewState::CLOSED;
-  } else {
-    // Snap the app list to corresponding state according to the snapping
-    // thresholds.
-    if (IsTabletModeEnabled()) {
-      app_list_state = launcher_above_shelf_bottom_amount_ >
-                               kAppListDragSnapToFullscreenThreshold
-                           ? AppListViewState::FULLSCREEN_ALL_APPS
-                           : AppListViewState::CLOSED;
-    } else {
-      if (launcher_above_shelf_bottom_amount_ <=
-          kAppListDragSnapToClosedThreshold)
-        app_list_state = AppListViewState::CLOSED;
-      else if (launcher_above_shelf_bottom_amount_ <=
-               kAppListDragSnapToPeekingThreshold)
-        app_list_state = AppListViewState::PEEKING;
-      else
-        app_list_state = AppListViewState::FULLSCREEN_ALL_APPS;
-    }
-  }
+  AppListViewState app_list_state =
+      Shell::Get()->app_list_controller()->CalculateStateAfterShelfDrag(
+          gesture_in_screen, launcher_above_shelf_bottom_amount_);
 
   // Keep auto-hide shelf visible if failed to open the app list.
   base::Optional<Shelf::ScopedAutoHideLock> auto_hide_lock;
   if (app_list_state == AppListViewState::CLOSED)
     auto_hide_lock.emplace(shelf_);
   Shell::Get()->app_list_controller()->EndDragFromShelf(app_list_state);
-
   gesture_drag_status_ = GESTURE_DRAG_NONE;
 }
 
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index a62bc36..32bfaf4f 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -63,19 +63,6 @@
       public WallpaperControllerObserver,
       public LocaleChangeObserver {
  public:
-  // The snapping threshold for dragging app list from shelf in tablet mode,
-  // measured in DIPs.
-  static constexpr int kAppListDragSnapToFullscreenThreshold = 320;
-
-  // The snapping thresholds for dragging app list from shelf in laptop mode,
-  // measured in DIPs.
-  static constexpr int kAppListDragSnapToClosedThreshold = 144;
-  static constexpr int kAppListDragSnapToPeekingThreshold = 561;
-
-  // The velocity the app list must be dragged in order to change the state of
-  // the app list for fling event, measured in DIPs/event.
-  static constexpr int kAppListDragVelocityThreshold = 6;
-
   ShelfLayoutManager(ShelfWidget* shelf_widget, Shelf* shelf);
   ~ShelfLayoutManager() override;
 
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index a374c90..aeeb9e49 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -12,6 +12,7 @@
 #include "ash/app_list/app_list_controller_impl.h"
 #include "ash/app_list/home_launcher_gesture_handler.h"
 #include "ash/app_list/test/app_list_test_helper.h"
+#include "ash/app_list/views/app_list_view.h"
 #include "ash/focus_cycler.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
@@ -35,8 +36,6 @@
 #include "ash/window_factory.h"
 #include "ash/wm/lock_state_controller.h"
 #include "ash/wm/overview/overview_controller.h"
-#include "ash/wm/splitview/split_view_controller.h"
-#include "ash/wm/splitview/split_view_divider.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
@@ -1760,9 +1759,9 @@
   // Fling up that exceeds the velocity threshold should show the fullscreen app
   // list.
   StartScroll(start);
-  UpdateScroll(-ShelfLayoutManager::kAppListDragSnapToPeekingThreshold);
+  UpdateScroll(-app_list::AppListView::kDragSnapToPeekingThreshold);
   EndScroll(true /* is_fling */,
-            -(ShelfLayoutManager::kAppListDragVelocityThreshold + 10));
+            -(app_list::AppListView::kDragVelocityThreshold + 10));
   GetAppListTestHelper()->WaitUntilIdle();
   GetAppListTestHelper()->CheckVisibility(true);
   GetAppListTestHelper()->CheckState(
@@ -1775,9 +1774,9 @@
 
   // Fling down that exceeds the velocity threshold should close the app list.
   StartScroll(start);
-  UpdateScroll(-ShelfLayoutManager::kAppListDragSnapToPeekingThreshold);
+  UpdateScroll(-app_list::AppListView::kDragSnapToPeekingThreshold);
   EndScroll(true /* is_fling */,
-            ShelfLayoutManager::kAppListDragVelocityThreshold + 10);
+            app_list::AppListView::kDragVelocityThreshold + 10);
   GetAppListTestHelper()->WaitUntilIdle();
   GetAppListTestHelper()->CheckVisibility(false);
   GetAppListTestHelper()->CheckState(app_list::AppListViewState::CLOSED);
@@ -1785,9 +1784,9 @@
   // Fling the app list not exceed the velocity threshold, the state depends on
   // the drag amount.
   StartScroll(start);
-  UpdateScroll(-(ShelfLayoutManager::kAppListDragSnapToPeekingThreshold - 10));
+  UpdateScroll(-(app_list::AppListView::kDragSnapToPeekingThreshold - 10));
   EndScroll(true /* is_fling */,
-            -(ShelfLayoutManager::kAppListDragVelocityThreshold - 10));
+            -(app_list::AppListView::kDragVelocityThreshold - 10));
   GetAppListTestHelper()->WaitUntilIdle();
   GetAppListTestHelper()->CheckVisibility(true);
   GetAppListTestHelper()->CheckState(app_list::AppListViewState::PEEKING);
@@ -1807,8 +1806,7 @@
                  shelf_widget_bounds.bottom() + 1);
   gfx::Point end = gfx::Point(
       start.x(), shelf_widget_bounds.bottom() -
-                     ShelfLayoutManager::kAppListDragSnapToPeekingThreshold -
-                     10);
+                     app_list::AppListView::kDragSnapToPeekingThreshold - 10);
   ui::test::EventGenerator* generator = GetEventGenerator();
   constexpr base::TimeDelta kTimeDelta = base::TimeDelta::FromMilliseconds(100);
   constexpr int kNumScrollSteps = 4;
@@ -1830,7 +1828,7 @@
   start.set_y(
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area().y());
   end.set_y(shelf_widget_bounds.bottom() -
-            ShelfLayoutManager::kAppListDragSnapToClosedThreshold + 10);
+            app_list::AppListView::kDragSnapToClosedThreshold + 10);
   generator->GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
   GetAppListTestHelper()->WaitUntilIdle();
   GetAppListTestHelper()->CheckVisibility(false);
@@ -1845,7 +1843,7 @@
   EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
 
   StartScroll(GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint());
-  UpdateScroll(-ShelfLayoutManager::kAppListDragSnapToPeekingThreshold);
+  UpdateScroll(-app_list::AppListView::kDragSnapToPeekingThreshold);
   GetAppListTestHelper()->WaitUntilIdle();
   shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
   // Note, value -10 here has no specific meaning, it only used to make the
@@ -1872,7 +1870,7 @@
   gfx::Vector2d delta;
 
   // Swiping up less than the close threshold should close the app list.
-  delta.set_y(ShelfLayoutManager::kAppListDragSnapToClosedThreshold - 10);
+  delta.set_y(app_list::AppListView::kDragSnapToClosedThreshold - 10);
   gfx::Point end = start - delta;
   generator->GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
   EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
@@ -1882,7 +1880,7 @@
 
   // Swiping up more than the close threshold but less than peeking threshold
   // should keep the app list at PEEKING state.
-  delta.set_y(ShelfLayoutManager::kAppListDragSnapToPeekingThreshold - 10);
+  delta.set_y(app_list::AppListView::kDragSnapToPeekingThreshold - 10);
   end = start - delta;
   generator->GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
   EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
@@ -1897,7 +1895,7 @@
 
   // Swiping up more than the peeking threshold should keep the app list at
   // FULLSCREEN_ALL_APPS state.
-  delta.set_y(ShelfLayoutManager::kAppListDragSnapToPeekingThreshold + 10);
+  delta.set_y(app_list::AppListView::kDragSnapToPeekingThreshold + 10);
   end = start - delta;
   generator->GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
   EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
@@ -1928,7 +1926,7 @@
   // Swiping up on the auto-hide shelf to drag up the app list. Close the app
   // list on drag ended since the short drag distance but keep the previous
   // shown auto-hide shelf still visible.
-  delta.set_y(ShelfLayoutManager::kAppListDragSnapToClosedThreshold - 10);
+  delta.set_y(app_list::AppListView::kDragSnapToClosedThreshold - 10);
   end = start - delta;
   generator->GestureScrollSequence(start, end, kTimeDelta, kNumScrollSteps);
   GetAppListTestHelper()->WaitUntilIdle();
@@ -2366,52 +2364,6 @@
   EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, GetShelfWidget()->GetBackgroundType());
 }
 
-// Test the background color for split view mode.
-TEST_F(ShelfLayoutManagerTest, ShelfBackgroundColorInSplitView) {
-  // Split view is only enabled in tablet mode.
-  TabletModeControllerTestApi().EnterTabletMode();
-
-  std::unique_ptr<aura::Window> window1(CreateTestWindow());
-  window1->SetProperty(aura::client::kResizeBehaviorKey,
-                       ws::mojom::kResizeBehaviorCanResize |
-                           ws::mojom::kResizeBehaviorCanMaximize);
-  window1->Show();
-
-  SplitViewController* split_view_controller =
-      Shell::Get()->split_view_controller();
-  split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT);
-  EXPECT_EQ(SHELF_BACKGROUND_SPLIT_VIEW, GetShelfWidget()->GetBackgroundType());
-
-  std::unique_ptr<aura::Window> window2(CreateTestWindow());
-  window2->SetProperty(aura::client::kResizeBehaviorKey,
-                       ws::mojom::kResizeBehaviorCanResize |
-                           ws::mojom::kResizeBehaviorCanMaximize);
-  window2->Show();
-  split_view_controller->SnapWindow(window2.get(), SplitViewController::RIGHT);
-  EXPECT_EQ(SHELF_BACKGROUND_SPLIT_VIEW, GetShelfWidget()->GetBackgroundType());
-
-  // Should still keep SHELF_BACKGROUND_SPLIT_VIEW when both overview and
-  // splitview are active.
-  wm::WMEvent minimize_event(wm::WM_EVENT_MINIMIZE);
-  wm::GetWindowState(window1.get())->OnWMEvent(&minimize_event);
-  EXPECT_EQ(split_view_controller->IsSplitViewModeActive(), true);
-  EXPECT_EQ(split_view_controller->state(), SplitViewController::RIGHT_SNAPPED);
-  EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting());
-  EXPECT_EQ(SHELF_BACKGROUND_SPLIT_VIEW, GetShelfWidget()->GetBackgroundType());
-
-  // Drag the divider to left to end split view mode, which will maximize the
-  // the right snapped window.
-  gfx::Point drag_point = split_view_controller->split_view_divider()
-                              ->GetDividerBoundsInScreen(false)
-                              .CenterPoint();
-  split_view_controller->StartResize(drag_point);
-  drag_point.set_x(0);
-  split_view_controller->EndResize(drag_point);
-
-  EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting());
-  EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, GetShelfWidget()->GetBackgroundType());
-}
-
 // Verify that the shelf doesn't have the opaque background if it's auto-hide
 // status.
 TEST_F(ShelfLayoutManagerTest, ShelfBackgroundColorAutoHide) {
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index 895c5e8..004f192 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -240,9 +240,8 @@
       -shelf->SelectValueForShelfAlignment(0, 0, safety_margin),
       -shelf->SelectValueForShelfAlignment(safety_margin, 0, 0));
 
-  // Show rounded corners except in maximized and split modes.
-  if (background_type == SHELF_BACKGROUND_MAXIMIZED ||
-      background_type == SHELF_BACKGROUND_SPLIT_VIEW) {
+  // Show rounded corners except in maximized (which includes split view) mode.
+  if (background_type == SHELF_BACKGROUND_MAXIMIZED) {
     mask_ = nullptr;
     opaque_background_.SetMaskLayer(nullptr);
   } else {
diff --git a/ash/wallpaper/wallpaper_controller.cc b/ash/wallpaper/wallpaper_controller.cc
index 0efde9fd..d2b1063 100644
--- a/ash/wallpaper/wallpaper_controller.cc
+++ b/ash/wallpaper/wallpaper_controller.cc
@@ -1225,9 +1225,12 @@
 }
 
 void WallpaperController::RemoveAlwaysOnTopWallpaper() {
-  if (!is_always_on_top_wallpaper_)
+  if (!is_always_on_top_wallpaper_) {
+    DCHECK(!reload_always_on_top_wallpaper_callback_);
     return;
+  }
   is_always_on_top_wallpaper_ = false;
+  reload_always_on_top_wallpaper_callback_.Reset();
   ReloadWallpaper(/*clear_cache=*/false);
 }
 
@@ -1913,7 +1916,9 @@
   if (clear_cache)
     wallpaper_cache_map_.clear();
 
-  if (reload_preview_wallpaper_callback_)
+  if (reload_always_on_top_wallpaper_callback_)
+    reload_always_on_top_wallpaper_callback_.Run();
+  else if (reload_preview_wallpaper_callback_)
     reload_preview_wallpaper_callback_.Run();
   else if (current_user_)
     ShowUserWallpaper(std::move(current_user_));
@@ -2027,8 +2032,11 @@
     is_always_on_top_wallpaper_ = false;
     return;
   }
-  ShowWallpaperImage(image, info, /*preview_mode=*/false,
-                     /*always_on_top=*/true);
+  reload_always_on_top_wallpaper_callback_ =
+      base::BindRepeating(&WallpaperController::ShowWallpaperImage,
+                          weak_factory_.GetWeakPtr(), image, info,
+                          /*preview_mode=*/false, /*always_on_top=*/true);
+  reload_always_on_top_wallpaper_callback_.Run();
 }
 
 bool WallpaperController::MoveToLockedContainer() {
diff --git a/ash/wallpaper/wallpaper_controller.h b/ash/wallpaper/wallpaper_controller.h
index 3c95cde..039cf5f 100644
--- a/ash/wallpaper/wallpaper_controller.h
+++ b/ash/wallpaper/wallpaper_controller.h
@@ -632,6 +632,11 @@
   // change). Has the same lifetime with |confirm_preview_wallpaper_callback_|.
   base::RepeatingClosure reload_preview_wallpaper_callback_;
 
+  // Called when the always-on-top wallpaper needs to be reloaded (e.g. display
+  // size change). Non-empty if and only if |is_always_on_top_wallpaper_| is
+  // true.
+  base::RepeatingClosure reload_always_on_top_wallpaper_callback_;
+
   // If true, use a solid color wallpaper as if it is the decoded image.
   bool bypass_decode_for_testing_ = false;
 
diff --git a/ash/wallpaper/wallpaper_controller_unittest.cc b/ash/wallpaper/wallpaper_controller_unittest.cc
index 0b06fe1..7dd32eb 100644
--- a/ash/wallpaper/wallpaper_controller_unittest.cc
+++ b/ash/wallpaper/wallpaper_controller_unittest.cc
@@ -1659,8 +1659,7 @@
             GetDecodeFilePaths()[0]);
 }
 
-// Display size change should trigger reload for both user wallpaper and preview
-// wallpaper.
+// Display size change should trigger wallpaper reload.
 TEST_F(WallpaperControllerTest, ReloadWallpaper) {
   CreateAndSaveWallpapers(account_id_1);
 
@@ -1699,6 +1698,26 @@
   UpdateDisplay("800x600");
   RunAllTasksUntilIdle();
   EXPECT_EQ(1, GetWallpaperCount());
+  ClearWallpaperCount();
+  controller_->CancelPreviewWallpaper();
+  RunAllTasksUntilIdle();
+  EXPECT_EQ(1, GetWallpaperCount());
+
+  // Show an always-on-top wallpaper.
+  const base::FilePath image_path =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+          chromeos::switches::kGuestWallpaperLarge);
+  CreateDefaultWallpapers();
+  SetBypassDecode();
+  ClearWallpaperCount();
+  controller_->ShowAlwaysOnTopWallpaper(image_path);
+  RunAllTasksUntilIdle();
+  EXPECT_EQ(1, GetWallpaperCount());
+  // Rotating the display should trigger a wallpaper reload.
+  ClearWallpaperCount();
+  UpdateDisplay("800x600/r");
+  RunAllTasksUntilIdle();
+  EXPECT_EQ(1, GetWallpaperCount());
 }
 
 TEST_F(WallpaperControllerTest, UpdateCustomWallpaperLayout) {
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc
index c2f6c14..4e7536b 100644
--- a/ash/wm/overview/overview_item.cc
+++ b/ash/wm/overview/overview_item.cc
@@ -160,23 +160,6 @@
 }
 
 void OverviewItem::Shutdown() {
-  if (transform_window_.GetTopInset()) {
-    // Activating a window (even when it is the window that was active before
-    // overview) results in stacking it at the top. Maintain the label window
-    // stacking position above the item to make the header transformation more
-    // gradual upon exiting the overview mode.
-    aura::Window* widget_window = item_widget_->GetNativeWindow();
-
-    // |widget_window| was originally created in the same container as the
-    // |transform_window_| but when closing overview the |transform_window_|
-    // could have been reparented if a drag was active. Only change stacking
-    // if the windows still belong to the same container.
-    if (widget_window->parent() == transform_window_.window()->parent()) {
-      widget_window->parent()->StackChildAbove(widget_window,
-                                               transform_window_.window());
-    }
-  }
-
   // On swiping from the shelf, the caller handles the animation via calls to
   // UpdateYAndOpacity, so do not additional fade out or slide animation to the
   // window.
@@ -192,7 +175,9 @@
 
 void OverviewItem::PrepareForOverview() {
   transform_window_.PrepareForOverview();
-  RestackItemWidget();
+  aura::Window* widget_window = item_widget_->GetNativeWindow();
+  widget_window->parent()->StackChildBelow(widget_window,
+                                           GetWindowForStacking());
 }
 
 void OverviewItem::SlideWindowIn() {
@@ -479,12 +464,6 @@
   SetBounds(scaled_bounds, animation_type);
 }
 
-void OverviewItem::RestackItemWidget() {
-  aura::Window* widget_window = item_widget_->GetNativeWindow();
-  widget_window->parent()->StackChildAbove(widget_window,
-                                           GetWindowForStacking());
-}
-
 void OverviewItem::HandlePressEvent(const gfx::Point& location_in_screen) {
   // We allow switching finger while dragging, but do not allow dragging two or
   // more items.
@@ -564,8 +543,8 @@
         Shell::Get()->split_view_controller()->GetDefaultSnappedWindow();
     if (snapped_window->parent() == parent_window &&
         dragged_window->parent() == parent_window) {
-      parent_window->StackChildBelow(dragged_widget_window, snapped_window);
-      parent_window->StackChildBelow(dragged_window, dragged_widget_window);
+      parent_window->StackChildBelow(dragged_window, snapped_window);
+      parent_window->StackChildBelow(dragged_widget_window, dragged_window);
     }
   }
 
@@ -583,8 +562,8 @@
       }
     }
     if (overview_items[index].get() == this && stacking_target) {
-      parent_window->StackChildBelow(dragged_widget_window, stacking_target);
-      parent_window->StackChildBelow(dragged_window, dragged_widget_window);
+      parent_window->StackChildBelow(dragged_window, stacking_target);
+      parent_window->StackChildBelow(dragged_widget_window, dragged_window);
       break;
     }
   }
@@ -792,8 +771,7 @@
   item_widget_->set_focus_on_creation(false);
   item_widget_->Init(params_label);
   aura::Window* widget_window = item_widget_->GetNativeWindow();
-  // Stack the widget above the transform window so that it can block events.
-  widget_window->parent()->StackChildAbove(widget_window,
+  widget_window->parent()->StackChildBelow(widget_window,
                                            transform_window_.window());
 
   shadow_ = std::make_unique<ui::Shadow>();
@@ -874,8 +852,8 @@
   if (widget_window && widget_window->parent() == window->parent()) {
     // TODO(xdai): This might not work if there is an always on top window.
     // See crbug.com/733760.
-    widget_window->parent()->StackChildAtTop(widget_window);
-    widget_window->parent()->StackChildBelow(window, widget_window);
+    widget_window->parent()->StackChildAtTop(window);
+    widget_window->parent()->StackChildBelow(widget_window, window);
   }
 }
 
diff --git a/ash/wm/overview/overview_item.h b/ash/wm/overview/overview_item.h
index 6038aa71..49a27ee 100644
--- a/ash/wm/overview/overview_item.h
+++ b/ash/wm/overview/overview_item.h
@@ -146,12 +146,6 @@
 
   const gfx::Rect& target_bounds() const { return target_bounds_; }
 
-  // Stacks the |item_widget_| in the correct place. |item_widget_| may be
-  // initially stacked in the wrong place due to animation or if it is a
-  // minimized window, the overview minimized widget is not available on
-  // |item_widget_|'s creation.
-  void RestackItemWidget();
-
   // Shift the window item up and then animates it to its original spot. Used
   // to transition from the home launcher.
   void SlideWindowIn();
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc
index f823d52..6d59022 100644
--- a/ash/wm/overview/overview_session_unittest.cc
+++ b/ash/wm/overview/overview_session_unittest.cc
@@ -129,7 +129,7 @@
 
   void SetUp() override {
     AshTestBase::SetUp();
-
+    Shell::Get()->aura_env()->set_throttle_input_on_resize_for_testing(false);
     shelf_view_test_api_ = std::make_unique<ShelfViewTestAPI>(
         GetPrimaryShelf()->GetShelfViewForTesting());
     shelf_view_test_api_->SetAnimationDuration(1);
@@ -2099,14 +2099,14 @@
   EXPECT_EQ(parent, widget3->GetNativeWindow()->parent());
   EXPECT_EQ(parent, min_widget2->GetNativeWindow()->parent());
 
-  // Verify that the item widget is stacked above the window if not minimized.
-  // Verify that the item widget is stacked above the minimized widget if
+  // Verify that the item widget is stacked below the window if not minimized.
+  // Verify that the item widget is stacked below the minimized widget if
   // minimized.
-  EXPECT_GT(IndexOf(widget1->GetNativeWindow(), parent),
+  EXPECT_LT(IndexOf(widget1->GetNativeWindow(), parent),
             IndexOf(window.get(), parent));
-  EXPECT_GT(IndexOf(widget2->GetNativeWindow(), parent),
+  EXPECT_LT(IndexOf(widget2->GetNativeWindow(), parent),
             IndexOf(min_widget2->GetNativeWindow(), parent));
-  EXPECT_GT(IndexOf(widget3->GetNativeWindow(), parent),
+  EXPECT_LT(IndexOf(widget3->GetNativeWindow(), parent),
             IndexOf(window3.get(), parent));
 
   // Drag the first window. Verify that it's item widget is not stacked above
@@ -2133,51 +2133,6 @@
             IndexOf(widget2->GetNativeWindow(), parent));
 }
 
-// Tests that overview widgets are stacked in the correct order.
-TEST_F(OverviewSessionTest, OverviewWidgetStackingOrderWithDragging) {
-  std::unique_ptr<aura::Window> window1(CreateTestWindow());
-  std::unique_ptr<aura::Window> window2(CreateTestWindow());
-  std::unique_ptr<aura::Window> window3(CreateTestWindow());
-
-  EnterTabletMode();
-  ToggleOverview();
-  OverviewItem* item1 = GetWindowItemForWindow(0, window1.get());
-  OverviewItem* item2 = GetWindowItemForWindow(0, window2.get());
-  OverviewItem* item3 = GetWindowItemForWindow(0, window3.get());
-  views::Widget* widget1 = item_widget(item1);
-  views::Widget* widget2 = item_widget(item2);
-  views::Widget* widget3 = item_widget(item3);
-
-  // Initially the highest stacked widget is the most recently used window, in
-  // this case it is the most recently created window.
-  aura::Window* parent = window1->parent();
-  EXPECT_GT(IndexOf(widget3->GetNativeWindow(), parent),
-            IndexOf(widget2->GetNativeWindow(), parent));
-  EXPECT_GT(IndexOf(widget2->GetNativeWindow(), parent),
-            IndexOf(widget1->GetNativeWindow(), parent));
-
-  // Verify that during drag the dragged item widget is stacked above the other
-  // two.
-  const gfx::Point start_drag = item1->target_bounds().CenterPoint();
-  ui::test::EventGenerator* generator = GetEventGenerator();
-  generator->MoveMouseTo(start_drag);
-  generator->PressLeftButton();
-  generator->MoveMouseTo(gfx::Point());
-  generator->MoveMouseTo(start_drag);
-  EXPECT_GT(IndexOf(widget1->GetNativeWindow(), parent),
-            IndexOf(widget3->GetNativeWindow(), parent));
-  EXPECT_GT(IndexOf(widget1->GetNativeWindow(), parent),
-            IndexOf(widget2->GetNativeWindow(), parent));
-
-  // Verify that after release the ordering is the same as before dragging.
-  generator->ReleaseLeftButton();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_GT(IndexOf(widget3->GetNativeWindow(), parent),
-            IndexOf(widget2->GetNativeWindow(), parent));
-  EXPECT_GT(IndexOf(widget2->GetNativeWindow(), parent),
-            IndexOf(widget1->GetNativeWindow(), parent));
-}
-
 // Verify that a windows which enter overview mode have a visible backdrop, if
 // the window is to be letter or pillar fitted.
 TEST_F(OverviewSessionTest, Backdrop) {
diff --git a/ash/wm/overview/scoped_overview_transform_window.cc b/ash/wm/overview/scoped_overview_transform_window.cc
index 8b0f53a..00843ff 100644
--- a/ash/wm/overview/scoped_overview_transform_window.cc
+++ b/ash/wm/overview/scoped_overview_transform_window.cc
@@ -27,7 +27,6 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "ui/aura/client/aura_constants.h"
-#include "ui/aura/null_window_targeter.h"
 #include "ui/aura/window.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/layer_observer.h"
@@ -179,15 +178,12 @@
       original_mask_layer_(window_->layer()->layer_mask_layer()),
       weak_ptr_factory_(this) {
   type_ = GetWindowDimensionsType(window);
-  original_targeter_ =
-      window_->SetEventTargeter(std::make_unique<aura::NullWindowTargeter>());
-  null_targeter_ = window_->targeter();
+  original_event_targeting_policy_ = window_->event_targeting_policy();
+  window_->SetEventTargetingPolicy(ws::mojom::EventTargetingPolicy::NONE);
 }
 
 ScopedOverviewTransformWindow::~ScopedOverviewTransformWindow() {
-  if (null_targeter_ == window_->targeter())
-    window_->SetEventTargeter(std::move(original_targeter_));
-
+  window_->SetEventTargetingPolicy(original_event_targeting_policy_);
   UpdateMask(/*show=*/false);
   StopObservingImplicitAnimations();
 }
diff --git a/ash/wm/overview/scoped_overview_transform_window.h b/ash/wm/overview/scoped_overview_transform_window.h
index 464f1bfd..b5affb5 100644
--- a/ash/wm/overview/scoped_overview_transform_window.h
+++ b/ash/wm/overview/scoped_overview_transform_window.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "services/ws/public/mojom/window_tree_constants.mojom.h"
 #include "ui/compositor/layer_animation_observer.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
@@ -20,8 +21,7 @@
 
 namespace aura {
 class Window;
-class WindowTargeter;
-}  // namespace aura
+}
 
 namespace gfx {
 class Rect;
@@ -209,6 +209,11 @@
   // The original opacity of the window before entering overview mode.
   float original_opacity_;
 
+  // For the duration of this object |window_| event targeting policy will be
+  // sent to NONE. Store the original so we can change it back when destroying
+  // this object.
+  ws::mojom::EventTargetingPolicy original_event_targeting_policy_;
+
   // Specifies how the window is laid out in the grid.
   GridWindowFillMode type_ = GridWindowFillMode::kNormal;
 
@@ -232,15 +237,6 @@
   // The original mask layer of the window before entering overview mode.
   ui::Layer* original_mask_layer_ = nullptr;
 
-  // Stores the targeter for the window. For the duration of this object,
-  // |window_|'s event targeter will be replaced by a NullWindowTargeter to
-  // prevent events from reaching |window_|.
-  // TODO(sammiequon): Investigate if we can use a custom event targeter on
-  // windows for overview mode and remove the need for the extra widget which
-  // blocks events in OverviewItem.
-  std::unique_ptr<aura::WindowTargeter> original_targeter_;
-  aura::WindowTargeter* null_targeter_ = nullptr;
-
   base::WeakPtrFactory<ScopedOverviewTransformWindow> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ScopedOverviewTransformWindow);
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_test_api.cc b/ash/wm/tablet_mode/tablet_mode_controller_test_api.cc
index 0f56c03..26fa3319 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_test_api.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller_test_api.cc
@@ -5,8 +5,6 @@
 #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
 
 #include "ash/shell.h"
-#include "ash/wm/tablet_mode/tablet_mode_window_manager.h"
-#include "ash/wm/tablet_mode/tablet_mode_window_state.h"
 #include "base/run_loop.h"
 #include "base/time/default_tick_clock.h"
 #include "services/ws/public/cpp/input_devices/input_device_client_test_api.h"
@@ -85,14 +83,4 @@
       tick_clock()->NowTicks());
 }
 
-bool TabletModeControllerTestApi::GetDeferBoundsUpdates(aura::Window* window) {
-  TabletModeWindowManager* window_manager = tablet_mode_window_manager();
-  if (window_manager == nullptr)
-    return false;
-  TabletModeWindowManager::WindowToState window_state_map =
-      window_manager->window_state_map_;
-  auto iter = window_state_map.find(window);
-  return iter != window_state_map.end() && iter->second->defer_bounds_updates_;
-}
-
 }  // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_test_api.h b/ash/wm/tablet_mode/tablet_mode_controller_test_api.h
index 8a403d3..f6be0ae 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_test_api.h
+++ b/ash/wm/tablet_mode/tablet_mode_controller_test_api.h
@@ -45,8 +45,6 @@
   void CloseLid();
   void SetTabletMode(bool on);
 
-  bool GetDeferBoundsUpdates(aura::Window* window);
-
   // Sets the event blocker on the tablet mode controller.
   void set_event_blocker(
       std::unique_ptr<InternalInputDevicesEventBlocker> blocker) {
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
index a87b3c9..c7d13eb 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -142,10 +142,6 @@
 
   base::UserActionTester* user_action_tester() { return &user_action_tester_; }
 
-  bool GetDeferBoundsUpdates(aura::Window* window) {
-    return test_api_->GetDeferBoundsUpdates(window);
-  }
-
   // Creates a test window snapped on the left in desktop mode.
   std::unique_ptr<aura::Window> CreateDesktopWindowSnappedLeft() {
     std::unique_ptr<aura::Window> window = CreateTestWindow();
@@ -1119,7 +1115,6 @@
   tablet_mode_controller()->EnableTabletModeWindowManager(true);
   EXPECT_EQ(SplitViewController::NO_SNAP, split_view_controller->state());
   EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting());
-  EXPECT_FALSE(GetDeferBoundsUpdates(window.get()));
 }
 
 // Test that if the active window is snapped on the left before tablet mode,
@@ -1133,7 +1128,6 @@
   EXPECT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller->state());
   EXPECT_EQ(window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting());
-  EXPECT_FALSE(GetDeferBoundsUpdates(window.get()));
 }
 
 // Test that if the active window is snapped on the right before tablet mode,
@@ -1147,7 +1141,6 @@
   EXPECT_EQ(SplitViewController::RIGHT_SNAPPED, split_view_controller->state());
   EXPECT_EQ(window.get(), split_view_controller->right_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting());
-  EXPECT_FALSE(GetDeferBoundsUpdates(window.get()));
 }
 
 // Test that if before tablet mode, the active window is snapped on the left and
@@ -1165,8 +1158,6 @@
   EXPECT_EQ(left_window.get(), split_view_controller->left_window());
   EXPECT_EQ(right_window.get(), split_view_controller->right_window());
   EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting());
-  EXPECT_FALSE(GetDeferBoundsUpdates(left_window.get()));
-  EXPECT_FALSE(GetDeferBoundsUpdates(right_window.get()));
 }
 
 // Test that if before tablet mode, the active window is snapped on the right
@@ -1184,8 +1175,6 @@
   EXPECT_EQ(left_window.get(), split_view_controller->left_window());
   EXPECT_EQ(right_window.get(), split_view_controller->right_window());
   EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting());
-  EXPECT_FALSE(GetDeferBoundsUpdates(left_window.get()));
-  EXPECT_FALSE(GetDeferBoundsUpdates(right_window.get()));
 }
 
 // Test that if before tablet mode, the active window is an ARC window snapped
@@ -1204,8 +1193,6 @@
   tablet_mode_controller()->EnableTabletModeWindowManager(true);
   EXPECT_EQ(SplitViewController::NO_SNAP, split_view_controller->state());
   EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting());
-  EXPECT_FALSE(GetDeferBoundsUpdates(left_window.get()));
-  EXPECT_FALSE(GetDeferBoundsUpdates(right_window.get()));
 }
 
 // Test that if before tablet mode, the active window is snapped on the left,
@@ -1229,9 +1216,6 @@
   EXPECT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller->state());
   EXPECT_EQ(left_window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting());
-  EXPECT_FALSE(GetDeferBoundsUpdates(left_window.get()));
-  EXPECT_TRUE(GetDeferBoundsUpdates(right_window.get()));
-  EXPECT_TRUE(GetDeferBoundsUpdates(extra_right_window.get()));
 }
 
 // Test that if overview is triggered on entering tablet mode, then the app list
@@ -1246,41 +1230,4 @@
   EXPECT_TRUE(app_list_controller->IsVisible());
 }
 
-// Test that bounds updates are deferred for windows in overview.
-TEST_F(TabletModeControllerTest, DeferBoundsUpdatesForWindowsInOverview) {
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
-  std::unique_ptr<aura::Window> window1 = CreateTestWindow();
-  std::unique_ptr<aura::Window> window2 = CreateTestWindow();
-  std::unique_ptr<aura::Window> window3 = CreateTestWindow();
-  ASSERT_FALSE(GetDeferBoundsUpdates(window1.get()));
-  ASSERT_FALSE(GetDeferBoundsUpdates(window2.get()));
-  ASSERT_FALSE(GetDeferBoundsUpdates(window3.get()));
-  Shell::Get()->overview_controller()->ToggleOverview();
-  EXPECT_TRUE(GetDeferBoundsUpdates(window1.get()));
-  EXPECT_TRUE(GetDeferBoundsUpdates(window2.get()));
-  EXPECT_TRUE(GetDeferBoundsUpdates(window3.get()));
-}
-
-// Test that bounds updates are deferred for windows in overview, in the case
-// that there are two snapped windows when overview is started.
-TEST_F(TabletModeControllerTest,
-       DeferBoundsUpdatesForWindowsInOverviewEnteredFromSplitView) {
-  SplitViewController* split_view_controller =
-      Shell::Get()->split_view_controller();
-  tablet_mode_controller()->EnableTabletModeWindowManager(true);
-  std::unique_ptr<aura::Window> window1 = CreateTestWindow();
-  std::unique_ptr<aura::Window> window2 = CreateTestWindow();
-  std::unique_ptr<aura::Window> window3 = CreateTestWindow();
-  split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT);
-  split_view_controller->SnapWindow(window2.get(), SplitViewController::RIGHT);
-  ASSERT_FALSE(GetDeferBoundsUpdates(window1.get()));
-  ASSERT_FALSE(GetDeferBoundsUpdates(window2.get()));
-  ASSERT_FALSE(GetDeferBoundsUpdates(window3.get()));
-  Shell::Get()->overview_controller()->ToggleOverview();
-  ASSERT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller->state());
-  EXPECT_FALSE(GetDeferBoundsUpdates(window1.get()));
-  EXPECT_TRUE(GetDeferBoundsUpdates(window2.get()));
-  EXPECT_TRUE(GetDeferBoundsUpdates(window3.get()));
-}
-
 }  // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.cc b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
index 5ec6055..f8da6635 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
@@ -115,33 +115,8 @@
 }
 
 void TabletModeWindowManager::OnOverviewModeStarting() {
-  SplitViewController* split_view_controller =
-      Shell::Get()->split_view_controller();
-  aura::Window* left_snapped_window = split_view_controller->left_window();
-  aura::Window* right_snapped_window = split_view_controller->right_window();
-  // Defer bounds updates for windows in overview.
-  for (auto& pair : window_state_map_) {
-    aura::Window* window = pair.first;
-    // If |overview_upcoming_for_split_view_| is true, then overview is starting
-    // because a snapped active window from desktop mode was carried over to
-    // split view on entering tablet mode. Then that window should be skipped
-    // (see https://crbug.com/926602). If |overview_upcoming_for_split_view_| is
-    // false and split view is active, then there are two snapped windows of
-    // which one is about to enter overview and therefore should not be skipped.
-    // In that case, there is no simple way to determine which of the two
-    // snapped windows will be put in overview, but fortunately, an upcoming
-    // call to OnSplitViewStateChanged() can be relied upon to set
-    // |defer_bounds_updates| to false in the window that remains snapped, and
-    // so here we can simply set |defer_bounds_updates| to true in all windows.
-    // Finally, if |overview_upcoming_for_split_view_| is false and split view
-    // is not active, then, of course, there are no snapped windows to skip.
-    if (overview_upcoming_for_split_view_ &&
-        (window == left_snapped_window || window == right_snapped_window))
-      continue;
-    SetDeferBoundsUpdates(window, /*defer_bounds_updates=*/true);
-  }
-
-  overview_upcoming_for_split_view_ = false;
+  for (auto& pair : window_state_map_)
+    SetDeferBoundsUpdates(pair.first, /*defer_bounds_updates=*/true);
 }
 
 void TabletModeWindowManager::OnOverviewModeEnding(
@@ -386,9 +361,7 @@
   SplitViewController* split_view_controller =
       Shell::Get()->split_view_controller();
   split_view_controller->SnapWindow(windows[0], curr_win_snap_pos);
-  if (prev_win_snap_pos == SplitViewController::NONE)
-    overview_upcoming_for_split_view_ = true;
-  else
+  if (prev_win_snap_pos != SplitViewController::NONE)
     split_view_controller->SnapWindow(windows[1], prev_win_snap_pos);
 
   for (auto* window : windows)
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.h b/ash/wm/tablet_mode/tablet_mode_window_manager.h
index 44fbcc7..a2c93af 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager.h
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager.h
@@ -97,8 +97,6 @@
   TabletModeWindowManager();
 
  private:
-  friend class TabletModeControllerTestApi;
-
   using WindowToState = std::map<aura::Window*, TabletModeWindowState*>;
 
   // Maximize all windows, except that a snapped active window shall become
@@ -159,10 +157,6 @@
   // True if overview exit type is |kWindowDragged|.
   bool exit_overview_by_window_drag_ = false;
 
-  // True if overview is going to be started because a snapped active window
-  // from desktop mode was carried over to split view on entering tablet mode.
-  bool overview_upcoming_for_split_view_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(TabletModeWindowManager);
 };
 
diff --git a/ash/wm/tablet_mode/tablet_mode_window_state.h b/ash/wm/tablet_mode/tablet_mode_window_state.h
index 41b367a..2d5af86 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_state.h
+++ b/ash/wm/tablet_mode/tablet_mode_window_state.h
@@ -54,8 +54,6 @@
   }
 
  private:
-  friend class TabletModeControllerTestApi;
-
   // Updates the window to |new_state_type| and resulting bounds:
   // Either full screen, maximized centered or minimized. If the state does not
   // change, only the bounds will be changed. If |animate| is set, the bound
diff --git a/ash/ws/window_service_delegate_impl_unittest.cc b/ash/ws/window_service_delegate_impl_unittest.cc
index 54c1f10d..78c88b3 100644
--- a/ash/ws/window_service_delegate_impl_unittest.cc
+++ b/ash/ws/window_service_delegate_impl_unittest.cc
@@ -92,6 +92,7 @@
   // AshTestBase:
   void SetUp() override {
     AshTestBase::SetUp();
+    Shell::Get()->aura_env()->set_throttle_input_on_resize_for_testing(false);
     NonClientFrameViewAsh::use_empty_minimum_size_for_test_ = true;
     top_level_ = CreateTestWindow(gfx::Rect(100, 100, 100, 100));
     ASSERT_TRUE(top_level_);
diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc
index bf2a18a5..1d1845d 100644
--- a/base/json/json_reader.cc
+++ b/base/json/json_reader.cc
@@ -55,6 +55,11 @@
   return root ? std::make_unique<Value>(std::move(*root)) : nullptr;
 }
 
+std::unique_ptr<Value> JSONReader::ReadDeprecated(StringPiece json,
+                                                  int options,
+                                                  int max_depth) {
+  return Read(json, options, max_depth);
+}
 
 // static
 std::unique_ptr<Value> JSONReader::ReadAndReturnError(
@@ -81,6 +86,18 @@
 }
 
 // static
+std::unique_ptr<Value> JSONReader::ReadAndReturnErrorDeprecated(
+    StringPiece json,
+    int options,
+    int* error_code_out,
+    std::string* error_msg_out,
+    int* error_line_out,
+    int* error_column_out) {
+  return ReadAndReturnError(json, options, error_code_out, error_msg_out,
+                            error_line_out, error_column_out);
+}
+
+// static
 std::string JSONReader::ErrorCodeToString(JsonParseError error_code) {
   switch (error_code) {
     case JSON_NO_ERROR:
diff --git a/base/json/json_reader.h b/base/json/json_reader.h
index 2c6bd3e..83279d0 100644
--- a/base/json/json_reader.h
+++ b/base/json/json_reader.h
@@ -91,19 +91,40 @@
 
   ~JSONReader();
 
+  // Work in progress. Please use ReadDeprecated() for now.
+  // https://crbug.com/925165
+  // A new version of Read() that returns a Value will be available as soon as
+  // all existing callers have been migrated to ReadDeprecated().
+  static std::unique_ptr<Value> Read(StringPiece json,
+                                     int options = JSON_PARSE_RFC,
+                                     int max_depth = kStackMaxDepth);
+
   // Reads and parses |json|, returning a Value.
   // If |json| is not a properly formed JSON string, returns nullptr.
   // Wrap this in base::FooValue::From() to check the Value is of type Foo and
   // convert to a FooValue at the same time.
-  static std::unique_ptr<Value> Read(StringPiece json,
-                                     int options = JSON_PARSE_RFC,
-                                     int max_depth = kStackMaxDepth);
+  static std::unique_ptr<Value> ReadDeprecated(StringPiece json,
+                                               int options = JSON_PARSE_RFC,
+                                               int max_depth = kStackMaxDepth);
+
+  // Work in progress. Please use ReadAndReturnErrorDeprecated() for now.
+  // https://crbug.com/925165
+  // A new version of ReadAndReturnError() that returns a Value will be
+  // available as soon as all existing callers have been migrated to
+  // ReadAndReturnErrorDeprecated().
+  static std::unique_ptr<Value> ReadAndReturnError(
+      StringPiece json,
+      int options,  // JSONParserOptions
+      int* error_code_out,
+      std::string* error_msg_out,
+      int* error_line_out = nullptr,
+      int* error_column_out = nullptr);
 
   // Reads and parses |json| like Read(). |error_code_out| and |error_msg_out|
   // are optional. If specified and nullptr is returned, they will be populated
   // an error code and a formatted error message (including error location if
   // appropriate). Otherwise, they will be unmodified.
-  static std::unique_ptr<Value> ReadAndReturnError(
+  static std::unique_ptr<Value> ReadAndReturnErrorDeprecated(
       StringPiece json,
       int options,  // JSONParserOptions
       int* error_code_out,
diff --git a/base/process/process_unittest.cc b/base/process/process_unittest.cc
index 18db689..6812646 100644
--- a/base/process/process_unittest.cc
+++ b/base/process/process_unittest.cc
@@ -271,7 +271,13 @@
 // backgrounding and restoring.
 // Note: a platform may not be willing or able to lower the priority of
 // a process. The calls to SetProcessBackground should be noops then.
-TEST_F(ProcessTest, SetProcessBackgrounded) {
+// Flaky on Windows: https://crbug.com/931721.
+#if defined(OS_WIN)
+#define MAYBE_SetProcessBackgrounded DISABLED_SetProcessBackgrounded
+#else
+#define MAYBE_SetProcessBackgrounded SetProcessBackgrounded
+#endif
+TEST_F(ProcessTest, MAYBE_SetProcessBackgrounded) {
   if (!Process::CanBackgroundProcesses())
     return;
   Process process(SpawnChild("SimpleChildProcess"));
@@ -299,9 +305,15 @@
   EXPECT_EQ(old_priority, new_priority);
 }
 
+// Flaky on Windows: https://crbug.com/931721.
+#if defined(OS_WIN)
+#define MAYBE_SetProcessBackgroundedSelf DISABLED_SetProcessBackgroundedSelf
+#else
+#define MAYBE_SetProcessBackgroundedSelf SetProcessBackgroundedSelf
+#endif
 // Same as SetProcessBackgrounded but to this very process. It uses
 // a different code path at least for Windows.
-TEST_F(ProcessTest, SetProcessBackgroundedSelf) {
+TEST_F(ProcessTest, MAYBE_SetProcessBackgroundedSelf) {
   if (!Process::CanBackgroundProcesses())
     return;
   Process process = Process::Current();
diff --git a/base/threading/platform_thread_unittest.cc b/base/threading/platform_thread_unittest.cc
index 96ea662..2ef69fe 100644
--- a/base/threading/platform_thread_unittest.cc
+++ b/base/threading/platform_thread_unittest.cc
@@ -289,7 +289,9 @@
 #if defined(OS_WIN)
 // Test changing a created thread's priority, with the
 // kWindowsThreadModeBackground feature enabled.
-TEST(PlatformThreadTest, SetCurrentThreadPriorityWithThreadModeBackground) {
+// Flaky: https://crbug.com/931706
+TEST(PlatformThreadTest,
+     DISABLED_SetCurrentThreadPriorityWithThreadModeBackground) {
   test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(
       features::kWindowsThreadModeBackground);
@@ -299,8 +301,9 @@
 // Test changing a created thread's priority, with the
 // kWindowsThreadModeBackground feature enabled, in an IDLE_PRIORITY_CLASS
 // process (regression test for https://crbug.com/901483).
+// Flaky: https://crbug.com/931706
 TEST(PlatformThreadTest,
-     SetCurrentThreadPriorityWithThreadModeBackgroundIdleProcess) {
+     DISABLED_SetCurrentThreadPriorityWithThreadModeBackgroundIdleProcess) {
   ::SetPriorityClass(Process::Current().Handle(), IDLE_PRIORITY_CLASS);
 
   test::ScopedFeatureList scoped_feature_list;
diff --git a/build/config/fuchsia/testing_sandbox_policy b/build/config/fuchsia/testing_sandbox_policy
index 2f1327f..51946e8 100644
--- a/build/config/fuchsia/testing_sandbox_policy
+++ b/build/config/fuchsia/testing_sandbox_policy
@@ -15,6 +15,7 @@
       "fuchsia.ui.input.ImeVisibilityService",
       "fuchsia.ui.policy.Presenter",
       "fuchsia.ui.scenic.Scenic",
+      "fuchsia.ui.viewsv1.ViewManager",
       "fuchsia.vulkan.loader.Loader"
   ]
 }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 11aa860..6d7d00b 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-ed8a157e58cafeb6f4b58dcbb4e597778bb7c869
\ No newline at end of file
+b66dfd8c0b90b2b9205b30ccd7469c21091f66c2
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 8562cec8..2cb4b92 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-c8c284db89064bbf546ba4ef24aa81d9862f63c2
\ No newline at end of file
+9fc3d6768829331dc1545b106ee2f51b07d98781
\ No newline at end of file
diff --git a/cc/paint/discardable_image_map_unittest.cc b/cc/paint/discardable_image_map_unittest.cc
index ba62110..a83f1397 100644
--- a/cc/paint/discardable_image_map_unittest.cc
+++ b/cc/paint/discardable_image_map_unittest.cc
@@ -1082,8 +1082,8 @@
     gfx::ColorSpace::CreateDisplayP3D65(),
 };
 
-INSTANTIATE_TEST_CASE_P(ColorSpace,
-                        DiscardableImageMapColorSpaceTest,
-                        testing::ValuesIn(test_color_spaces));
+INSTANTIATE_TEST_SUITE_P(ColorSpace,
+                         DiscardableImageMapColorSpaceTest,
+                         testing::ValuesIn(test_color_spaces));
 
 }  // namespace cc
diff --git a/cc/paint/oop_pixeltest.cc b/cc/paint/oop_pixeltest.cc
index 80d4105f..d30f65e 100644
--- a/cc/paint/oop_pixeltest.cc
+++ b/cc/paint/oop_pixeltest.cc
@@ -1650,11 +1650,11 @@
   RunTest();
 }
 
-INSTANTIATE_TEST_CASE_P(P, OopImagePixelTest, ::testing::Bool());
-INSTANTIATE_TEST_CASE_P(P, OopClearPixelTest, ::testing::Bool());
-INSTANTIATE_TEST_CASE_P(P, OopRecordShaderPixelTest, ::testing::Bool());
-INSTANTIATE_TEST_CASE_P(P, OopRecordFilterPixelTest, ::testing::Bool());
-INSTANTIATE_TEST_CASE_P(P, OopPathPixelTest, ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(P, OopImagePixelTest, ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(P, OopClearPixelTest, ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(P, OopRecordShaderPixelTest, ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(P, OopRecordFilterPixelTest, ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(P, OopPathPixelTest, ::testing::Bool());
 
 }  // namespace
 }  // namespace cc
diff --git a/cc/paint/paint_cache_unittest.cc b/cc/paint/paint_cache_unittest.cc
index fa8448d8..678a8e7 100644
--- a/cc/paint/paint_cache_unittest.cc
+++ b/cc/paint/paint_cache_unittest.cc
@@ -121,7 +121,7 @@
   EXPECT_TRUE(service_cache.empty());
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     P,
     PaintCacheTest,
     ::testing::Range(static_cast<uint32_t>(0),
diff --git a/cc/paint/paint_filter_unittest.cc b/cc/paint/paint_filter_unittest.cc
index a7380d221..a6d5b52 100644
--- a/cc/paint/paint_filter_unittest.cc
+++ b/cc/paint/paint_filter_unittest.cc
@@ -149,7 +149,7 @@
   }
 };
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     P,
     PaintFilterTest,
     ::testing::Range(static_cast<uint8_t>(PaintFilter::Type::kColorFilter),
diff --git a/cc/paint/paint_op_buffer_unittest.cc b/cc/paint/paint_op_buffer_unittest.cc
index 3b0f2ff..22a3bbbc 100644
--- a/cc/paint/paint_op_buffer_unittest.cc
+++ b/cc/paint/paint_op_buffer_unittest.cc
@@ -1705,7 +1705,7 @@
   PaintOpBuffer buffer_;
 };
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     P,
     PaintOpSerializationTest,
     ::testing::Range(static_cast<uint8_t>(0),
@@ -2945,9 +2945,9 @@
 
 class PaintFilterSerializationTest : public ::testing::TestWithParam<bool> {};
 
-INSTANTIATE_TEST_CASE_P(PaintFilterSerializationTests,
-                        PaintFilterSerializationTest,
-                        ::testing::Values(true, false));
+INSTANTIATE_TEST_SUITE_P(PaintFilterSerializationTests,
+                         PaintFilterSerializationTest,
+                         ::testing::Values(true, false));
 
 TEST_P(PaintFilterSerializationTest, Basic) {
   SkScalar scalars[9] = {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f};
diff --git a/cc/raster/raster_buffer_provider_perftest.cc b/cc/raster/raster_buffer_provider_perftest.cc
index 098c5b94..dc5fd57 100644
--- a/cc/raster/raster_buffer_provider_perftest.cc
+++ b/cc/raster/raster_buffer_provider_perftest.cc
@@ -561,12 +561,13 @@
   RunScheduleAndExecuteTasksTest("32_4", 32, 4);
 }
 
-INSTANTIATE_TEST_CASE_P(RasterBufferProviderPerfTests,
-                        RasterBufferProviderPerfTest,
-                        ::testing::Values(RASTER_BUFFER_PROVIDER_TYPE_ZERO_COPY,
-                                          RASTER_BUFFER_PROVIDER_TYPE_ONE_COPY,
-                                          RASTER_BUFFER_PROVIDER_TYPE_GPU,
-                                          RASTER_BUFFER_PROVIDER_TYPE_BITMAP));
+INSTANTIATE_TEST_SUITE_P(
+    RasterBufferProviderPerfTests,
+    RasterBufferProviderPerfTest,
+    ::testing::Values(RASTER_BUFFER_PROVIDER_TYPE_ZERO_COPY,
+                      RASTER_BUFFER_PROVIDER_TYPE_ONE_COPY,
+                      RASTER_BUFFER_PROVIDER_TYPE_GPU,
+                      RASTER_BUFFER_PROVIDER_TYPE_BITMAP));
 
 class RasterBufferProviderCommonPerfTest
     : public RasterBufferProviderPerfTestBase,
diff --git a/cc/raster/raster_buffer_provider_unittest.cc b/cc/raster/raster_buffer_provider_unittest.cc
index 25535e6..89332a7c 100644
--- a/cc/raster/raster_buffer_provider_unittest.cc
+++ b/cc/raster/raster_buffer_provider_unittest.cc
@@ -516,7 +516,7 @@
   histogram_tester.ExpectTotalCount(histogram, 1);
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     RasterBufferProviderTests,
     RasterBufferProviderTest,
     ::testing::Values(RASTER_BUFFER_PROVIDER_TYPE_ZERO_COPY,
diff --git a/cc/raster/single_thread_task_graph_runner_unittest.cc b/cc/raster/single_thread_task_graph_runner_unittest.cc
index e84fb19..ee5e001 100644
--- a/cc/raster/single_thread_task_graph_runner_unittest.cc
+++ b/cc/raster/single_thread_task_graph_runner_unittest.cc
@@ -33,12 +33,12 @@
   SingleThreadTaskGraphRunner single_thread_task_graph_runner_;
 };
 
-INSTANTIATE_TYPED_TEST_CASE_P(SingleThreadTaskGraphRunner,
-                              TaskGraphRunnerTest,
-                              SingleThreadTaskGraphRunnerTestDelegate);
-INSTANTIATE_TYPED_TEST_CASE_P(SingleThreadTaskGraphRunner,
-                              SingleThreadTaskGraphRunnerTest,
-                              SingleThreadTaskGraphRunnerTestDelegate);
+INSTANTIATE_TYPED_TEST_SUITE_P(SingleThreadTaskGraphRunner,
+                               TaskGraphRunnerTest,
+                               SingleThreadTaskGraphRunnerTestDelegate);
+INSTANTIATE_TYPED_TEST_SUITE_P(SingleThreadTaskGraphRunner,
+                               SingleThreadTaskGraphRunnerTest,
+                               SingleThreadTaskGraphRunnerTestDelegate);
 
 }  // namespace
 }  // namespace cc
diff --git a/cc/raster/synchronous_task_graph_runner_unittest.cc b/cc/raster/synchronous_task_graph_runner_unittest.cc
index 1d11e28..1cd4cc23 100644
--- a/cc/raster/synchronous_task_graph_runner_unittest.cc
+++ b/cc/raster/synchronous_task_graph_runner_unittest.cc
@@ -25,12 +25,12 @@
   SynchronousTaskGraphRunner synchronous_task_graph_runner_;
 };
 
-INSTANTIATE_TYPED_TEST_CASE_P(SynchronousTaskGraphRunner,
-                              TaskGraphRunnerTest,
-                              SynchronousTaskGraphRunnerTestDelegate);
-INSTANTIATE_TYPED_TEST_CASE_P(SynchronousTaskGraphRunner,
-                              SingleThreadTaskGraphRunnerTest,
-                              SynchronousTaskGraphRunnerTestDelegate);
+INSTANTIATE_TYPED_TEST_SUITE_P(SynchronousTaskGraphRunner,
+                               TaskGraphRunnerTest,
+                               SynchronousTaskGraphRunnerTestDelegate);
+INSTANTIATE_TYPED_TEST_SUITE_P(SynchronousTaskGraphRunner,
+                               SingleThreadTaskGraphRunnerTest,
+                               SynchronousTaskGraphRunnerTestDelegate);
 
 }  // namespace
 }  // namespace cc
diff --git a/cc/test/layer_tree_pixel_resource_test.h b/cc/test/layer_tree_pixel_resource_test.h
index e5a16f2..55f8500 100644
--- a/cc/test/layer_tree_pixel_resource_test.h
+++ b/cc/test/layer_tree_pixel_resource_test.h
@@ -43,8 +43,8 @@
   void InitializeFromTestCase(PixelResourceTestCase test_case);
 };
 
-#define INSTANTIATE_PIXEL_RESOURCE_TEST_CASE_P(framework_name)         \
-  INSTANTIATE_TEST_CASE_P(                                             \
+#define INSTANTIATE_PIXEL_RESOURCE_TEST_SUITE_P(framework_name)        \
+  INSTANTIATE_TEST_SUITE_P(                                            \
       PixelResourceTest, framework_name,                               \
       ::testing::Combine(                                              \
           ::testing::Values(SOFTWARE, GPU, ONE_COPY, ZERO_COPY),       \
diff --git a/cc/test/task_graph_runner_test_template.h b/cc/test/task_graph_runner_test_template.h
index 7c2f387f8f..0384fea 100644
--- a/cc/test/task_graph_runner_test_template.h
+++ b/cc/test/task_graph_runner_test_template.h
@@ -119,7 +119,7 @@
   TaskRunnerTestDelegate delegate_;
 };
 
-TYPED_TEST_CASE_P(TaskGraphRunnerTest);
+TYPED_TEST_SUITE_P(TaskGraphRunnerTest);
 
 TYPED_TEST_P(TaskGraphRunnerTest, Basic) {
   const int kNamespaceCount = TaskGraphRunnerTestBase::kNamespaceCount;
@@ -257,13 +257,16 @@
   }
 }
 
-REGISTER_TYPED_TEST_CASE_P(TaskGraphRunnerTest, Basic, Dependencies, Categorys);
+REGISTER_TYPED_TEST_SUITE_P(TaskGraphRunnerTest,
+                            Basic,
+                            Dependencies,
+                            Categorys);
 
 template <typename TaskRunnerTestDelegate>
 using SingleThreadTaskGraphRunnerTest =
     TaskGraphRunnerTest<TaskRunnerTestDelegate>;
 
-TYPED_TEST_CASE_P(SingleThreadTaskGraphRunnerTest);
+TYPED_TEST_SUITE_P(SingleThreadTaskGraphRunnerTest);
 
 TYPED_TEST_P(SingleThreadTaskGraphRunnerTest, Priority) {
   const int kNamespaceCount = TaskGraphRunnerTestBase::kNamespaceCount;
@@ -293,7 +296,7 @@
   }
 }
 
-REGISTER_TYPED_TEST_CASE_P(SingleThreadTaskGraphRunnerTest, Priority);
+REGISTER_TYPED_TEST_SUITE_P(SingleThreadTaskGraphRunnerTest, Priority);
 
 }  // namespace cc
 
diff --git a/cc/tiles/gpu_image_decode_cache_perftest.cc b/cc/tiles/gpu_image_decode_cache_perftest.cc
index 11e0e09..819d16bb 100644
--- a/cc/tiles/gpu_image_decode_cache_perftest.cc
+++ b/cc/tiles/gpu_image_decode_cache_perftest.cc
@@ -92,11 +92,11 @@
   std::unique_ptr<GpuImageDecodeCache> cache_;
 };
 
-INSTANTIATE_TEST_CASE_P(P,
-                        GpuImageDecodeCachePerfTest,
-                        testing::Values(TestMode::kGpu,
-                                        TestMode::kTransferCache,
-                                        TestMode::kSw));
+INSTANTIATE_TEST_SUITE_P(P,
+                         GpuImageDecodeCachePerfTest,
+                         testing::Values(TestMode::kGpu,
+                                         TestMode::kTransferCache,
+                                         TestMode::kSw));
 
 TEST_P(GpuImageDecodeCachePerfTest, DecodeWithColorConversion) {
   CreateCache(gfx::ColorSpace::CreateXYZD50().ToSkColorSpace());
@@ -121,10 +121,10 @@
 }
 
 using GpuImageDecodeCachePerfTestNoSw = GpuImageDecodeCachePerfTest;
-INSTANTIATE_TEST_CASE_P(P,
-                        GpuImageDecodeCachePerfTestNoSw,
-                        testing::Values(TestMode::kGpu,
-                                        TestMode::kTransferCache));
+INSTANTIATE_TEST_SUITE_P(P,
+                         GpuImageDecodeCachePerfTestNoSw,
+                         testing::Values(TestMode::kGpu,
+                                         TestMode::kTransferCache));
 
 TEST_P(GpuImageDecodeCachePerfTestNoSw, DecodeWithMips) {
   // Surface to render into.
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc
index 67b92f9..9f3983e1 100644
--- a/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -2839,14 +2839,14 @@
 bool false_array[] = {false};
 bool true_array[] = {true};
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     GpuImageDecodeCacheTestsInProcessRaster,
     GpuImageDecodeCacheTest,
     testing::Combine(testing::ValuesIn(test_color_types),
                      testing::ValuesIn(false_array) /* use_transfer_cache */,
                      testing::Bool() /* do_yuv_decode */));
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     GpuImageDecodeCacheTestsOOPR,
     GpuImageDecodeCacheTest,
     testing::Combine(testing::ValuesIn(test_color_types),
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index 05a2290e..1ae2d7e 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -4703,11 +4703,11 @@
   EXPECT_EQ(expect_lcd_text, grand_child_->CanUseLCDText());
 }
 
-INSTANTIATE_TEST_CASE_P(LayerTreeHostCommonTest,
-                        LCDTextTest,
-                        testing::Combine(testing::Bool(),
-                                         testing::Bool(),
-                                         testing::Bool()));
+INSTANTIATE_TEST_SUITE_P(LayerTreeHostCommonTest,
+                         LCDTextTest,
+                         testing::Combine(testing::Bool(),
+                                          testing::Bool(),
+                                          testing::Bool()));
 
 TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayerImpl) {
   FakeImplTaskRunnerProvider task_runner_provider;
diff --git a/cc/trees/layer_tree_host_pixeltest_blending.cc b/cc/trees/layer_tree_host_pixeltest_blending.cc
index e49a92b..41c663d 100644
--- a/cc/trees/layer_tree_host_pixeltest_blending.cc
+++ b/cc/trees/layer_tree_host_pixeltest_blending.cc
@@ -262,11 +262,11 @@
   SkColor misc_opaque_color_ = 0xffc86464;
 };
 
-INSTANTIATE_TEST_CASE_P(B,
-                        LayerTreeHostBlendingPixelTest,
-                        ::testing::Combine(::testing::Values(SOFTWARE,
-                                                             ZERO_COPY),
-                                           ::testing::ValuesIn(kBlendModes)));
+INSTANTIATE_TEST_SUITE_P(B,
+                         LayerTreeHostBlendingPixelTest,
+                         ::testing::Combine(::testing::Values(SOFTWARE,
+                                                              ZERO_COPY),
+                                            ::testing::ValuesIn(kBlendModes)));
 
 TEST_P(LayerTreeHostBlendingPixelTest, BlendingWithRoot) {
   const int kRootWidth = 2;
diff --git a/cc/trees/layer_tree_host_pixeltest_masks.cc b/cc/trees/layer_tree_host_pixeltest_masks.cc
index 5ba2606..a75e460 100644
--- a/cc/trees/layer_tree_host_pixeltest_masks.cc
+++ b/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -28,7 +28,7 @@
 
 using LayerTreeHostMasksPixelTest = ParameterizedPixelResourceTest;
 
-INSTANTIATE_PIXEL_RESOURCE_TEST_CASE_P(LayerTreeHostMasksPixelTest);
+INSTANTIATE_PIXEL_RESOURCE_TEST_SUITE_P(LayerTreeHostMasksPixelTest);
 
 class MaskContentLayerClient : public ContentLayerClient {
  public:
@@ -99,7 +99,7 @@
   }
 };
 
-INSTANTIATE_PIXEL_RESOURCE_TEST_CASE_P(LayerTreeHostLayerListPixelTest);
+INSTANTIATE_PIXEL_RESOURCE_TEST_SUITE_P(LayerTreeHostLayerListPixelTest);
 
 TEST_P(LayerTreeHostLayerListPixelTest, MaskWithEffect) {
   PropertyTrees property_trees;
@@ -470,7 +470,7 @@
 using LayerTreeHostMasksForBackdropFiltersPixelTest =
     ParameterizedPixelResourceTest;
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     PixelResourceTest,
     LayerTreeHostMasksForBackdropFiltersPixelTest,
     ::testing::Combine(
@@ -732,9 +732,9 @@
   bool force_shaders_;
 };
 
-INSTANTIATE_TEST_CASE_P(All,
-                        LayerTreeHostMaskAsBlendingPixelTest,
-                        ::testing::Range(0, 5));
+INSTANTIATE_TEST_SUITE_P(All,
+                         LayerTreeHostMaskAsBlendingPixelTest,
+                         ::testing::Range(0, 5));
 // Instantiate 5 test modes of the following:
 // 0: SOFTWARE (golden sample)
 // 1: GL
diff --git a/cc/trees/layer_tree_host_pixeltest_readback.cc b/cc/trees/layer_tree_host_pixeltest_readback.cc
index 5b32a7b0..3105105 100644
--- a/cc/trees/layer_tree_host_pixeltest_readback.cc
+++ b/cc/trees/layer_tree_host_pixeltest_readback.cc
@@ -450,7 +450,7 @@
       background.get(), base::FilePath(FILE_PATH_LITERAL("green.png")));
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     LayerTreeHostReadbackPixelTests,
     LayerTreeHostReadbackPixelTest,
     ::testing::Values(
@@ -547,7 +547,7 @@
       base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     LayerTreeHostReadbackDeviceScalePixelTests,
     LayerTreeHostReadbackDeviceScalePixelTest,
     ::testing::Values(
@@ -602,11 +602,11 @@
   }
 }
 
-INSTANTIATE_TEST_CASE_P(LayerTreeHostReadbackColorSpacePixelTests,
-                        LayerTreeHostReadbackColorSpacePixelTest,
-                        ::testing::Values(ReadbackTestConfig(
-                            LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL,
-                            READBACK_BITMAP)));
+INSTANTIATE_TEST_SUITE_P(LayerTreeHostReadbackColorSpacePixelTests,
+                         LayerTreeHostReadbackColorSpacePixelTest,
+                         ::testing::Values(ReadbackTestConfig(
+                             LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL,
+                             READBACK_BITMAP)));
 
 }  // namespace
 }  // namespace cc
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 3c49cde..4842664 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -251,6 +251,7 @@
     "$google_play_services_package:google_play_services_iid_java",
     "$google_play_services_package:google_play_services_tasks_java",
     "//base:base_java",
+    "//base:jni_java",
     "//chrome/android/third_party/compositor_animator:compositor_animator_java",
     "//chrome/android/webapk/libs/client:client_java",
     "//chrome/android/webapk/libs/common:common_java",
@@ -417,7 +418,10 @@
   # can provide their own implementations.
   jar_excluded_patterns = [ "*/AppHooksImpl.class" ]
 
-  annotation_processor_deps = [ "//third_party/android_deps:dagger_processor" ]
+  annotation_processor_deps = [
+    "//base/android/jni_generator:jni_processor",
+    "//third_party/android_deps:dagger_processor",
+  ]
 }
 
 android_library("bundle_canary_java") {
diff --git a/chrome/android/java/res/drawable/ic_sync_error_40dp.xml b/chrome/android/java/res/drawable/ic_sync_error_40dp.xml
new file mode 100644
index 0000000..6e32871
--- /dev/null
+++ b/chrome/android/java/res/drawable/ic_sync_error_40dp.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:width="40dp"
+    android:height="40dp"
+    android:viewportWidth="40"
+    android:viewportHeight="40"
+    tools:targetApi="21">
+
+    <group
+        android:translateX="8"
+        android:translateY="8">
+
+        <path
+            android:pathData="M10,6.35L10,4.26c-0.8,0.21 -1.55,0.54 -2.23,0.96l1.46,1.46c0.25,-0.12 0.5,-0.24 0.77,-0.33zM2.86,5.41l2.36,2.36C4.45,8.99 4,10.44 4,12c0,2.21 0.91,4.2 2.36,5.64L4,20h6v-6l-2.24,2.24C6.68,15.15 6,13.66 6,12c0,-1 0.25,-1.94 0.68,-2.77l8.08,8.08c-0.25,0.13 -0.5,0.25 -0.77,0.34v2.09c0.8,-0.21 1.55,-0.54 2.23,-0.96l2.36,2.36 1.27,-1.27L4.14,4.14 2.86,5.41zM20,4h-6v6l2.24,-2.24C17.32,8.85 18,10.34 18,12c0,1 -0.25,1.94 -0.68,2.77l1.46,1.46C19.55,15.01 20,13.56 20,12c0,-2.21 -0.91,-4.2 -2.36,-5.64L20,4z"
+            android:fillColor="@color/google_red_600"/>
+    </group>
+</vector>
diff --git a/chrome/android/java/res/drawable/ic_sync_green_40dp.xml b/chrome/android/java/res/drawable/ic_sync_green_40dp.xml
new file mode 100644
index 0000000..56026f8d
--- /dev/null
+++ b/chrome/android/java/res/drawable/ic_sync_green_40dp.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:width="40dp"
+    android:height="40dp"
+    android:viewportWidth="40"
+    android:viewportHeight="40"
+    tools:targetApi="21">
+
+    <group
+        android:translateX="8"
+        android:translateY="8">
+
+        <path
+            android:pathData="M7.875,16.188a5.838,5.838 0,0 1,0 -8.25,5.708 5.708,0 0,1 2.406,-1.444V4.486A7.711,7.711 0,0 0,6.5 6.563a7.776,7.776 0,0 0,0 11l-2.063,2.062h5.5v-5.5l-2.062,2.063zM17.5,6.563L19.563,4.5h-5.5V10l2.062,-2.063a5.838,5.838 0,0 1,0 8.25,5.708 5.708,0 0,1 -2.406,1.444v2.008a7.711,7.711 0,0 0,3.781 -2.076,7.776 7.776,0 0,0 0,-11z"
+            android:fillColor="@color/google_green_600"/>
+    </group>
+</vector>
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index 76ef14ae..36dea07 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -49,6 +49,7 @@
 
     <!-- TODO(https://crbug.com/919835): Clarify whether these colors can be reused. -->
     <color name="google_green_600">#1E8E3E</color>
+    <color name="google_red_600">#D93025</color>
     <color name="google_yellow_600">#F9AB00</color>
 
     <!-- Infobar colors -->
diff --git a/chrome/android/java/res/xml/main_preferences.xml b/chrome/android/java/res/xml/main_preferences.xml
index 7a65ef48..7d740122 100644
--- a/chrome/android/java/res/xml/main_preferences.xml
+++ b/chrome/android/java/res/xml/main_preferences.xml
@@ -15,10 +15,11 @@
         android:order="1"
         android:title="@string/sign_in_to_chrome"/>
     <org.chromium.chrome.browser.preferences.ChromeBasePreference
-        android:fragment="org.chromium.chrome.browser.preferences.SyncAndServicesPreferences"
         android:key="sync_and_services"
         android:order="2"
-        android:title="@string/prefs_sync_and_services"/>
+        android:layout="@layout/account_management_account_row"
+        android:title="@string/prefs_sync_and_services"
+        android:fragment="org.chromium.chrome.browser.preferences.SyncAndServicesPreferences"/>
 
     <PreferenceCategory
         android:key="basics_section"
diff --git a/chrome/android/java/res/xml/sync_and_services_preferences.xml b/chrome/android/java/res/xml/sync_and_services_preferences.xml
index f1e12e0a..28e7a4f 100644
--- a/chrome/android/java/res/xml/sync_and_services_preferences.xml
+++ b/chrome/android/java/res/xml/sync_and_services_preferences.xml
@@ -14,7 +14,8 @@
 
         <Preference
             android:key="sync_error_card"
-            android:icon="@drawable/sync_error"
+            android:layout="@layout/account_management_account_row"
+            android:icon="@drawable/ic_sync_error_40dp"
             android:title="@string/sync_error_card_title"/>
         <org.chromium.chrome.browser.preferences.ChromeSwitchPreference
             android:key="sync_requested"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 1045c60..cec59b7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -875,7 +875,7 @@
         super.initializeCompositor();
 
         setTabContentManager(new TabContentManager(this, getContentOffsetProvider(),
-                DeviceClassManager.enableSnapshots()));
+                getChromeApplication().getReferencePool(), DeviceClassManager.enableSnapshots()));
         mCompositorViewHolder.onNativeLibraryReady(getWindowAndroid(), getTabContentManager());
 
         if (isContextualSearchAllowed() && ContextualSearchFieldTrial.isEnabled()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java b/chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java
index 86f701a..69059143 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java
@@ -24,6 +24,7 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.favicon.FaviconHelper;
@@ -243,7 +244,11 @@
         } else {
             // 1-based index to keep in line with Desktop implementation.
             RecordUserAction.record(buildComputedAction("HistoryClick" + (position + 1)));
-            mNavigationController.goToNavigationIndex(entry.getIndex());
+            int index = entry.getIndex();
+            RecordHistogram.recordBooleanHistogram(
+                    "Navigation.BackForward.NavigatingToEntryMarkedToBeSkipped",
+                    mNavigationController.isEntryMarkedToBeSkipped(index));
+            mNavigationController.goToNavigationIndex(index);
         }
 
         mPopup.dismiss();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/background_task_scheduler/NativeBackgroundTask.java b/chrome/android/java/src/org/chromium/chrome/browser/background_task_scheduler/NativeBackgroundTask.java
index 53fe9f7..05d668f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/background_task_scheduler/NativeBackgroundTask.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/background_task_scheduler/NativeBackgroundTask.java
@@ -52,6 +52,9 @@
 
     /** The id of the task from {@link TaskParameters} used for metrics logging. */
     private int mTaskId;
+  
+    /** Make sure that we do not double record task finished metric */
+    private boolean mFinishMetricRecorded;
 
     @Override
     public final boolean onStartTask(
@@ -60,7 +63,7 @@
         mTaskId = taskParameters.getTaskId();
 
         TaskFinishedCallback wrappedCallback = needsReschedule -> {
-            BackgroundTaskSchedulerExternalUma.reportNativeTaskFinished(mTaskId);
+            recordTaskFinishedMetric();
             callback.taskFinished(needsReschedule);
         };
 
@@ -95,7 +98,7 @@
     public final boolean onStopTask(Context context, TaskParameters taskParameters) {
         ThreadUtils.assertOnUiThread();
         mTaskStopped = true;
-        BackgroundTaskSchedulerExternalUma.reportNativeTaskFinished(mTaskId);
+        recordTaskFinishedMetric();
         if (isNativeLoaded()) {
             return onStopTaskWithNative(context, taskParameters);
         } else {
@@ -233,4 +236,12 @@
     protected BrowserStartupController getBrowserStartupController() {
         return BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER);
     }
+  
+    private void recordTaskFinishedMetric() {
+      ThreadUtils.assertOnUiThread();
+      if (!mFinishMetricRecorded) {
+        mFinishMetricRecorded = true;
+        BackgroundTaskSchedulerExternalUma.reportNativeTaskFinished(mTaskId);
+      }
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java
index 6c16347..35bcfc4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java
@@ -12,12 +12,15 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.CommandLine;
+import org.chromium.base.DiscardableReferencePool;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.BitmapCache;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.native_page.NativePage;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.util.ConversionUtils;
 import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.display.DisplayAndroid;
 
@@ -30,11 +33,16 @@
  */
 @JNINamespace("android")
 public class TabContentManager {
+    // The default cache size is an upper limit to have at least 8 thumbnails
+    // (6 visible + 2 padding) at around 400Kb size.
+    private static final int DEFAULT_CACHE_SIZE = (int) (3.2 * ConversionUtils.BYTES_PER_MEGABYTE);
+
     private final float mThumbnailScale;
     private final int mFullResThumbnailsMaxSize;
     private final ContentOffsetProvider mContentOffsetProvider;
     private int[] mPriorityTabIds;
     private long mNativeTabContentManager;
+    private BitmapCache mThumbnailCache;
 
     private final ArrayList<ThumbnailChangeListener> mListeners =
             new ArrayList<ThumbnailChangeListener>();
@@ -74,7 +82,7 @@
      * @param contentOffsetProvider The provider of content parameter.
      */
     public TabContentManager(Context context, ContentOffsetProvider contentOffsetProvider,
-                boolean snapshotsEnabled) {
+            DiscardableReferencePool referencePool, boolean snapshotsEnabled) {
         mContentOffsetProvider = contentOffsetProvider;
         mSnapshotsEnabled = snapshotsEnabled;
 
@@ -115,6 +123,9 @@
 
         mPriorityTabIds = new int[mFullResThumbnailsMaxSize];
 
+        mThumbnailCache =
+                referencePool == null ? null : new BitmapCache(referencePool, DEFAULT_CACHE_SIZE);
+
         mNativeTabContentManager = nativeInit(defaultCacheSize,
                 approximationCacheSize, compressionQueueMaxSize, writeQueueMaxSize,
                 useApproximationThumbnails);
@@ -215,19 +226,41 @@
 
     /**
      * Call to get a thumbnail for a given tab ID from disk through a {@link Callback}. If there is
-     * no up to date thumbnail on the cache for the given tab, callback returns a null result.
-     * Currently this read a compressed file from disk and sends the Bitmap over the
-     * JNI boundary after decompressing. In its current form, should be used for experimental
+     * no up to date thumbnail on the native cache for the given tab, callback returns null.
+     * Currently this reads a compressed file from disk and sends the Bitmap over the
+     * JNI boundary after decompressing, also relying on a Java side limited size cache for better
+     * user experience. In its current form, should be used for experimental
      * purposes only.
-     * TODO(yusufo): Change the plumbing so that at the least a {@link android.net.Uri} is send
+     * TODO(yusufo): Change the plumbing so that at the least a {@link android.net.Uri} is sent
      * over JNI of an uncompressed file on disk.
-     * @param tabID The ID of the tab.
-     * @param callback The callback to send the {@link Bitmap} with.
+     * @param tab The tab to get the thumbnail for.
+     * @param callback The callback to send the {@link Bitmap} key with.
      */
-    public void getTabThumbnailWithCallback(int tabID, Callback<Bitmap> callback) {
+    public void getTabThumbnailWithCallback(Tab tab, Callback<String> callback) {
         if (mNativeTabContentManager == 0 || !mSnapshotsEnabled) return;
 
-        nativeGetTabThumbnailWithCallback(mNativeTabContentManager, tabID, callback);
+        final String url = tab.getUrl();
+        if (mThumbnailCache.getBitmap(url) != null) {
+            callback.onResult(url);
+            return;
+        }
+
+        Callback<Bitmap> bitmapCallback = result -> {
+            if (result != null) mThumbnailCache.putBitmap(url, result);
+            callback.onResult(url);
+        };
+
+        nativeGetTabThumbnailWithCallback(mNativeTabContentManager, tab.getId(), bitmapCallback);
+    }
+
+    /**
+     * This is a syncronous API to get an already cached thumbnail if possible.
+     * See {@link TabContentManager#getTabThumbnailWithCallback(Tab, Callback)} for caching.
+     * @param  key The key to use for getting a cached thumbnail.
+     * @return The currently cached thumbnail under the given key.
+     */
+    public Bitmap provideCachedThumbnailForKey(String key) {
+        return mThumbnailCache.getBitmap(key);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/device/DeviceClassManager.java b/chrome/android/java/src/org/chromium/chrome/browser/device/DeviceClassManager.java
index 4930d73..729a60f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/device/DeviceClassManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/device/DeviceClassManager.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.device;
 
 import org.chromium.base.CommandLine;
-import org.chromium.base.StrictModeContext;
 import org.chromium.base.SysUtils;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
@@ -96,10 +95,8 @@
     public static boolean enableAccessibilityLayout() {
         if (getInstance().mEnableAccessibilityLayout) return true;
         if (!AccessibilityUtil.isAccessibilityEnabled()) return false;
-        try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
-            return ChromePreferenceManager.getInstance().readBoolean(
-                    ChromePreferenceManager.ACCESSIBILITY_TAB_SWITCHER, true);
-        }
+        return ChromePreferenceManager.getInstance().readBoolean(
+                ChromePreferenceManager.ACCESSIBILITY_TAB_SWITCHER, true);
     }
 
     /**
@@ -115,10 +112,8 @@
     public static boolean enableAnimations() {
         if (!getInstance().mEnableAnimations) return false;
         if (!AccessibilityUtil.isAccessibilityEnabled()) return true;
-        try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
-            return !ChromePreferenceManager.getInstance().readBoolean(
-                    ChromePreferenceManager.ACCESSIBILITY_TAB_SWITCHER, true);
-        }
+        return !ChromePreferenceManager.getInstance().readBoolean(
+                ChromePreferenceManager.ACCESSIBILITY_TAB_SWITCHER, true);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/instantapps/InstantAppsHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/instantapps/InstantAppsHandler.java
index 53af1fe2..0c099bc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/instantapps/InstantAppsHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/instantapps/InstantAppsHandler.java
@@ -9,7 +9,6 @@
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
 import android.os.Build;
-import android.os.StrictMode;
 import android.os.SystemClock;
 import android.provider.Browser;
 
@@ -335,13 +334,8 @@
 
     /** @return Whether Chrome is the default browser on the device. */
     private boolean isChromeDefaultHandler(Context context) {
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        try {
-            return ChromePreferenceManager.getInstance().readBoolean(
-                    ChromePreferenceManager.CHROME_DEFAULT_BROWSER, false);
-        } finally {
-            StrictMode.setThreadPolicy(oldPolicy);
-        }
+        return ChromePreferenceManager.getInstance().readBoolean(
+                ChromePreferenceManager.CHROME_DEFAULT_BROWSER, false);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
index 16853ca3..a79d0f6b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
@@ -29,11 +29,13 @@
 import org.chromium.content_public.browser.MediaSessionObserver;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.media_session.mojom.MediaSessionAction;
+import org.chromium.services.media_session.MediaImage;
 import org.chromium.services.media_session.MediaMetadata;
 import org.chromium.ui.base.WindowAndroid;
 
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -242,9 +244,6 @@
             @Override
             public void mediaSessionMetadataChanged(MediaMetadata metadata) {
                 mPageMetadata = metadata;
-                mMediaImageManager.downloadImage(
-                        (mPageMetadata != null) ? mPageMetadata.getArtwork() : null,
-                        MediaSessionTabHelper.this);
                 updateNotificationMetadata();
             }
 
@@ -253,6 +252,12 @@
                 mMediaSessionActions = actions;
                 updateNotificationActions();
             }
+
+            @Override
+            public void mediaSessionArtworkChanged(List<MediaImage> images) {
+                mMediaImageManager.downloadImage(images, MediaSessionTabHelper.this);
+                updateNotificationMetadata();
+            }
         };
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
index 04b61308..5105d22 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
@@ -8,6 +8,7 @@
 import android.support.annotation.Nullable;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.base.StrictModeContext;
 import org.chromium.chrome.browser.crash.MinidumpUploadService.ProcessType;
 
 import java.util.Collections;
@@ -554,7 +555,9 @@
      * @return The value of the preference.
      */
     public int readInt(String key) {
-        return mSharedPreferences.getInt(key, 0);
+        try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
+            return mSharedPreferences.getInt(key, 0);
+        }
     }
 
     /**
@@ -589,7 +592,9 @@
      * @return The value of the preference if stored; defaultValue otherwise.
      */
     public long readLong(String key, long defaultValue) {
-        return mSharedPreferences.getLong(key, defaultValue);
+        try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
+            return mSharedPreferences.getLong(key, defaultValue);
+        }
     }
 
     /**
@@ -612,7 +617,9 @@
      * @return The value of the preference if stored; defaultValue otherwise.
      */
     public boolean readBoolean(String key, boolean defaultValue) {
-        return mSharedPreferences.getBoolean(key, defaultValue);
+        try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
+            return mSharedPreferences.getBoolean(key, defaultValue);
+        }
     }
 
     /**
@@ -635,7 +642,9 @@
      * @return The value of the preference if stored; defaultValue otherwise.
      */
     public String readString(String key, @Nullable String defaultValue) {
-        return mSharedPreferences.getString(key, defaultValue);
+        try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
+            return mSharedPreferences.getString(key, defaultValue);
+        }
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
index d6e06d3..8b886e4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
@@ -26,6 +26,7 @@
 import org.chromium.chrome.browser.search_engines.TemplateUrl;
 import org.chromium.chrome.browser.search_engines.TemplateUrlService;
 import org.chromium.chrome.browser.signin.SigninManager;
+import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.chrome.browser.util.FeatureUtilities;
 
 import java.util.HashMap;
@@ -35,7 +36,8 @@
  * The main settings screen, shown when the user first opens Settings.
  */
 public class MainPreferences extends PreferenceFragment
-        implements SigninManager.SignInStateObserver, TemplateUrlService.LoadListener {
+        implements TemplateUrlService.LoadListener, ProfileSyncService.SyncStateChangedListener,
+                   SigninManager.SignInStateObserver {
     public static final String PREF_ACCOUNT_SECTION = "account_section";
     public static final String PREF_SIGN_IN = "sign_in";
     public static final String PREF_SYNC_AND_SERVICES = "sync_and_services";
@@ -83,6 +85,10 @@
             SigninManager.get().addSignInStateObserver(this);
             mSignInPreference.registerForUpdates();
         }
+        ProfileSyncService syncService = ProfileSyncService.get();
+        if (syncService != null) {
+            syncService.addSyncStateChangedListener(this);
+        }
     }
 
     @Override
@@ -92,6 +98,10 @@
             SigninManager.get().removeSignInStateObserver(this);
             mSignInPreference.unregisterForUpdates();
         }
+        ProfileSyncService syncService = ProfileSyncService.get();
+        if (syncService != null) {
+            syncService.removeSyncStateChangedListener(this);
+        }
     }
 
     @Override
@@ -193,6 +203,7 @@
             removePreferenceIfPresent(PREF_SIGN_IN);
         }
 
+        updateSyncAndServicesPreference();
         updateSearchEnginePreference();
 
         if (HomepageManager.shouldShowHomepageSetting()) {
@@ -237,6 +248,15 @@
         if (preference != null) getPreferenceScreen().removePreference(preference);
     }
 
+    private void updateSyncAndServicesPreference() {
+        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.UNIFIED_CONSENT)) return;
+
+        ChromeBasePreference syncAndServices =
+                (ChromeBasePreference) findPreference(PREF_SYNC_AND_SERVICES);
+        syncAndServices.setIcon(SyncPreferenceUtils.getSyncStatusIcon(getActivity()));
+        syncAndServices.setSummary(SyncPreferenceUtils.getSyncStatusSummary(getActivity()));
+    }
+
     private void updateSearchEnginePreference() {
         if (!TemplateUrlService.getInstance().isLoaded()) {
             ChromeBasePreference searchEnginePref =
@@ -297,6 +317,11 @@
         updateSearchEnginePreference();
     }
 
+    @Override
+    public void syncStateChanged() {
+        updateSyncAndServicesPreference();
+    }
+
     @VisibleForTesting
     ManagedPreferenceDelegate getManagedPreferenceDelegateForTest() {
         return mManagedPreferenceDelegate;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SignInPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SignInPreference.java
index 794a3aa..6ec0fec 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SignInPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SignInPreference.java
@@ -247,12 +247,14 @@
 
         setLayoutResource(R.layout.account_management_account_row);
         setTitle(profileData.getFullNameOrEmail());
-        setSummary(SyncPreferenceUtils.getSyncStatusSummary(getContext()));
+        boolean unifiedConsent = ChromeFeatureList.isEnabled(ChromeFeatureList.UNIFIED_CONSENT);
+        setSummary(unifiedConsent ? accountName
+                                  : SyncPreferenceUtils.getSyncStatusSummary(getContext()));
         setFragment(AccountManagementFragment.class.getName());
         setIcon(profileData.getImage());
-        setWidgetLayoutResource(SyncPreferenceUtils.showSyncErrorIcon(getContext())
-                        ? R.layout.sync_error_widget
-                        : 0);
+        boolean showSyncError =
+                !unifiedConsent && SyncPreferenceUtils.showSyncErrorIcon(getContext());
+        setWidgetLayoutResource(showSyncError ? R.layout.sync_error_widget : 0);
         setViewEnabled(true);
 
         mSigninPromoController = null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncPreferenceUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncPreferenceUtils.java
index 7741be32..711d8a4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncPreferenceUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncPreferenceUtils.java
@@ -5,8 +5,11 @@
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
 import android.preference.Preference;
 import android.preference.PreferenceFragment;
+import android.support.annotation.Nullable;
+import android.support.v7.content.res.AppCompatResources;
 
 import org.chromium.base.BuildInfo;
 import org.chromium.base.metrics.RecordHistogram;
@@ -18,6 +21,7 @@
 import org.chromium.components.sync.AndroidSyncSettings;
 import org.chromium.components.sync.ProtocolErrorClientAction;
 import org.chromium.components.sync.StopSource;
+import org.chromium.ui.UiUtils;
 
 /**
  * Helper methods for sync preferences.
@@ -93,16 +97,37 @@
             if (profileSyncService.isPassphraseRequiredForDecryption()) {
                 return res.getString(R.string.sync_need_passphrase);
             }
+            if (ChromeFeatureList.isEnabled(ChromeFeatureList.UNIFIED_CONSENT)) {
+                return context.getString(R.string.sync_and_services_summary_sync_on);
+            }
             return context.getString(R.string.account_management_sync_summary, accountName);
         }
-
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.UNIFIED_CONSENT)) {
-            return context.getString(R.string.account_management_sync_off_summary, accountName);
-        }
         return context.getString(R.string.sync_is_disabled);
     }
 
     /**
+     * Returns an icon that represents the current sync state.
+     */
+    public static @Nullable Drawable getSyncStatusIcon(Context context) {
+        if (!ChromeSigninController.get().isSignedIn()) return null;
+
+        ProfileSyncService profileSyncService = ProfileSyncService.get();
+        if (profileSyncService == null || !AndroidSyncSettings.get().isSyncEnabled()) {
+            return UiUtils.getTintedDrawable(
+                    context, R.drawable.ic_sync_green_40dp, R.color.modern_grey_700);
+        }
+
+        if (profileSyncService.isEngineInitialized()
+                && (profileSyncService.hasUnrecoverableError()
+                        || profileSyncService.getAuthError() != GoogleServiceAuthError.State.NONE
+                        || profileSyncService.isPassphraseRequiredForDecryption())) {
+            return AppCompatResources.getDrawable(context, R.drawable.ic_sync_error_40dp);
+        }
+
+        return AppCompatResources.getDrawable(context, R.drawable.ic_sync_green_40dp);
+    }
+
+    /**
      * Enables or disables {@link ProfileSyncService} and optionally records metrics that the sync
      * was disabled from settings. Requires that {@link ProfileSyncService#get()} returns non-null
      * reference.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabGridViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabGridViewBinder.java
index aabc5431f..61267a3b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabGridViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabGridViewBinder.java
@@ -53,8 +53,10 @@
             });
         } else if (TabProperties.FAVICON == propertyKey) {
             holder.favicon.setImageBitmap(item.get(TabProperties.FAVICON));
-        } else if (TabProperties.THUMBNAIL_KEY_URI == propertyKey) {
-            // TODO(yusufo) : Add logic to get this from a cache.
+        } else if (TabProperties.THUMBNAIL_KEY == propertyKey) {
+            holder.thumbnail.setImageBitmap(
+                    item.get(TabProperties.THUMBNAIL_PROVIDER)
+                            .provideCachedThumbnailForKey(item.get(TabProperties.THUMBNAIL_KEY)));
         } else if (TabProperties.TAB_ID == propertyKey) {
             holder.setTabId(item.get(TabProperties.TAB_ID));
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabListMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabListMediator.java
index aecf30b3..a677793 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabListMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabListMediator.java
@@ -31,6 +31,15 @@
  * TODO(yusufo): Move some of the logic here to a parent component to make the above true.
  */
 class TabListMediator {
+    /**
+     * An interface to get the thumbnails to be shown inside the tab grid cards.
+     */
+    public interface ThumbnailProvider {
+        /**
+         * @return The thumbnail for the given key synchronously.
+         */
+        Bitmap provideCachedThumbnailForKey(String key);
+    }
     private final int mFaviconSize;
     private final FaviconHelper mFaviconHelper = new FaviconHelper();
     private final TabListModel mModel;
@@ -151,6 +160,9 @@
                         .with(TabProperties.TITLE, tab.getTitle())
                         .with(TabProperties.FAVICON, tab.getFavicon())
                         .with(TabProperties.IS_SELECTED, isSelected)
+                        .with(TabProperties.THUMBNAIL_PROVIDER,
+                                mTabContentManager::provideCachedThumbnailForKey)
+                        .with(TabProperties.THUMBNAIL_KEY, "")
                         .with(TabProperties.TAB_SELECTED_LISTENER, mTabSelectedListener)
                         .with(TabProperties.TAB_CLOSED_LISTENER, mTabClosedListener)
                         .build();
@@ -160,6 +172,10 @@
                 (image, iconUrl)
                         -> mModel.get(mModel.indexFromId(tab.getId()))
                                    .set(TabProperties.FAVICON, image));
+        mTabContentManager.getTabThumbnailWithCallback(tab,
+                result
+                -> mModel.get(mModel.indexFromId(tab.getId()))
+                           .set(TabProperties.THUMBNAIL_KEY, result));
         tab.addObserver(mTabObserver);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabProperties.java
index 2919511..d09e991 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabProperties.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/tab_list_ui/TabProperties.java
@@ -9,6 +9,7 @@
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModel.ReadableIntPropertyKey;
+import org.chromium.ui.modelutil.PropertyModel.ReadableObjectPropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey;
 import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
 
@@ -27,13 +28,16 @@
     public static final WritableObjectPropertyKey<Bitmap> FAVICON =
             new WritableObjectPropertyKey<>();
 
-    public static final WritableObjectPropertyKey<String> THUMBNAIL_KEY_URI =
+    public static final WritableObjectPropertyKey<String> THUMBNAIL_KEY =
             new WritableObjectPropertyKey<>();
 
+    public static final ReadableObjectPropertyKey<TabListMediator.ThumbnailProvider>
+            THUMBNAIL_PROVIDER = new ReadableObjectPropertyKey<>();
+
     public static final WritableObjectPropertyKey<String> TITLE = new WritableObjectPropertyKey<>();
 
     public static final WritableBooleanPropertyKey IS_SELECTED = new WritableBooleanPropertyKey();
 
     public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {TAB_ID, TAB_SELECTED_LISTENER,
-            TAB_CLOSED_LISTENER, FAVICON, THUMBNAIL_KEY_URI, TITLE, IS_SELECTED};
+            TAB_CLOSED_LISTENER, FAVICON, THUMBNAIL_PROVIDER, THUMBNAIL_KEY, TITLE, IS_SELECTED};
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
index 66aceff..e90e770 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarTablet.java
@@ -19,7 +19,6 @@
 import android.widget.ImageButton;
 
 import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.base.StrictModeContext;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.NavigationPopup;
@@ -661,9 +660,7 @@
     }
 
     private boolean isAccessibilityTabSwitcherPreferenceEnabled() {
-        try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
-            return ChromePreferenceManager.getInstance().readBoolean(
-                    ChromePreferenceManager.ACCESSIBILITY_TAB_SWITCHER, true);
-        }
+        return ChromePreferenceManager.getInstance().readBoolean(
+                ChromePreferenceManager.ACCESSIBILITY_TAB_SWITCHER, true);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
index 441c875..1359095 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
@@ -17,7 +17,6 @@
 
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
-import org.chromium.base.StrictModeContext;
 import org.chromium.base.SysUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
@@ -232,10 +231,8 @@
         if (sIsHomePageButtonForceEnabled == null) {
             ChromePreferenceManager prefManager = ChromePreferenceManager.getInstance();
 
-            try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
-                sIsHomePageButtonForceEnabled = prefManager.readBoolean(
-                        ChromePreferenceManager.HOME_PAGE_BUTTON_FORCE_ENABLED_KEY, false);
-            }
+            sIsHomePageButtonForceEnabled = prefManager.readBoolean(
+                    ChromePreferenceManager.HOME_PAGE_BUTTON_FORCE_ENABLED_KEY, false);
         }
         return sIsHomePageButtonForceEnabled;
     }
@@ -265,10 +262,8 @@
         if (sShouldInflateToolbarOnBackgroundThread == null) {
             ChromePreferenceManager prefManager = ChromePreferenceManager.getInstance();
 
-            try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
-                sShouldInflateToolbarOnBackgroundThread = prefManager.readBoolean(
-                        ChromePreferenceManager.INFLATE_TOOLBAR_ON_BACKGROUND_THREAD_KEY, false);
-            }
+            sShouldInflateToolbarOnBackgroundThread = prefManager.readBoolean(
+                    ChromePreferenceManager.INFLATE_TOOLBAR_ON_BACKGROUND_THREAD_KEY, false);
         }
         return sShouldInflateToolbarOnBackgroundThread;
     }
@@ -281,10 +276,8 @@
         if (sDownloadAutoResumptionEnabledInNative == null) {
             ChromePreferenceManager prefManager = ChromePreferenceManager.getInstance();
 
-            try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
-                sDownloadAutoResumptionEnabledInNative = prefManager.readBoolean(
-                        ChromePreferenceManager.DOWNLOAD_AUTO_RESUMPTION_IN_NATIVE_KEY, true);
-            }
+            sDownloadAutoResumptionEnabledInNative = prefManager.readBoolean(
+                    ChromePreferenceManager.DOWNLOAD_AUTO_RESUMPTION_IN_NATIVE_KEY, true);
         }
         return sDownloadAutoResumptionEnabledInNative;
     }
@@ -306,10 +299,8 @@
         if (sIsHomepageTileEnabled == null) {
             ChromePreferenceManager prefManager = ChromePreferenceManager.getInstance();
 
-            try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
-                sIsHomepageTileEnabled = prefManager.readBoolean(
-                        ChromePreferenceManager.HOMEPAGE_TILE_ENABLED_KEY, false);
-            }
+            sIsHomepageTileEnabled = prefManager.readBoolean(
+                    ChromePreferenceManager.HOMEPAGE_TILE_ENABLED_KEY, false);
         }
         return sIsHomepageTileEnabled;
     }
@@ -341,10 +332,8 @@
         if (sIsNewTabPageButtonEnabled == null) {
             ChromePreferenceManager prefManager = ChromePreferenceManager.getInstance();
 
-            try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
-                sIsNewTabPageButtonEnabled = prefManager.readBoolean(
-                        ChromePreferenceManager.NTP_BUTTON_ENABLED_KEY, false);
-            }
+            sIsNewTabPageButtonEnabled =
+                    prefManager.readBoolean(ChromePreferenceManager.NTP_BUTTON_ENABLED_KEY, false);
         }
         return sIsNewTabPageButtonEnabled;
     }
@@ -376,10 +365,8 @@
         if (sIsBottomToolbarEnabled == null) {
             ChromePreferenceManager prefManager = ChromePreferenceManager.getInstance();
 
-            try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
-                sIsBottomToolbarEnabled = prefManager.readBoolean(
-                        ChromePreferenceManager.BOTTOM_TOOLBAR_ENABLED_KEY, false);
-            }
+            sIsBottomToolbarEnabled = prefManager.readBoolean(
+                    ChromePreferenceManager.BOTTOM_TOOLBAR_ENABLED_KEY, false);
         }
         return sIsBottomToolbarEnabled
                 && !DeviceFormFactor.isNonMultiDisplayContextOnTablet(
@@ -404,10 +391,8 @@
         if (sIsNightModeAvailable == null) {
             ChromePreferenceManager prefManager = ChromePreferenceManager.getInstance();
 
-            try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
-                sIsNightModeAvailable = prefManager.readBoolean(
-                        ChromePreferenceManager.NIGHT_MODE_AVAILABLE_KEY, false);
-            }
+            sIsNightModeAvailable = prefManager.readBoolean(
+                    ChromePreferenceManager.NIGHT_MODE_AVAILABLE_KEY, false);
         }
         return sIsNightModeAvailable;
     }
@@ -451,11 +436,8 @@
         if (sIsSoleEnabled == null) {
             ChromePreferenceManager prefManager = ChromePreferenceManager.getInstance();
 
-            // Allow disk access for preferences while Sole is in experimentation.
-            try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
-                sIsSoleEnabled = prefManager.readBoolean(
-                        ChromePreferenceManager.SOLE_INTEGRATION_ENABLED_KEY, true);
-            }
+            sIsSoleEnabled = prefManager.readBoolean(
+                    ChromePreferenceManager.SOLE_INTEGRATION_ENABLED_KEY, true);
         }
         return sIsSoleEnabled;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java
index de03baa..a38cf90 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java
@@ -17,6 +17,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.NativeMethods;
 import org.chromium.blink_public.platform.WebDisplayMode;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.metrics.WebApkUma;
@@ -130,14 +131,14 @@
 
         if (!needsUpgrade) {
             if (!mStorage.didPreviousUpdateSucceed()) {
-                onFinishedUpdate(WebApkInstallResult.SUCCESS, false /* relaxUpdates */);
+                onFinishedUpdate(mStorage, WebApkInstallResult.SUCCESS, false /* relaxUpdates */);
             }
             return;
         }
 
         // Set WebAPK update as having failed in case that Chrome is killed prior to
         // {@link onBuiltWebApk} being called.
-        recordUpdate(WebApkInstallResult.FAILURE, false /* relaxUpdates*/);
+        recordUpdate(mStorage, WebApkInstallResult.FAILURE, false /* relaxUpdates*/);
 
         if (fetchedInfo != null) {
             buildUpdateRequestAndSchedule(fetchedInfo, primaryIconUrl, badgeIconUrl,
@@ -164,7 +165,7 @@
             String badgeIconUrl, boolean isManifestStale, @WebApkUpdateReason int updateReason) {
         Callback<Boolean> callback = (success) -> {
             if (!success) {
-                onFinishedUpdate(WebApkInstallResult.FAILURE, false /* relaxUpdates*/);
+                onFinishedUpdate(mStorage, WebApkInstallResult.FAILURE, false /* relaxUpdates*/);
                 return;
             }
             scheduleUpdate();
@@ -192,15 +193,17 @@
     }
 
     /** Sends update request to the WebAPK Server. Should be called when WebAPK is not running. */
-    public void updateWhileNotRunning(final Runnable callback) {
+    public static void updateWhileNotRunning(
+            final WebappDataStorage storage, final Runnable callback) {
         Log.i(TAG, "Update now");
         WebApkUpdateCallback callbackRunner = (result, relaxUpdates) -> {
-            onFinishedUpdate(result, relaxUpdates);
+            onFinishedUpdate(storage, result, relaxUpdates);
             callback.run();
         };
 
         WebApkUma.recordUpdateRequestSent(WebApkUma.UpdateRequestSent.WHILE_WEBAPK_CLOSED);
-        updateWebApkFromFile(mStorage.getPendingUpdateRequestPath(), callbackRunner);
+        WebApkUpdateManagerJni.get().updateWebApkFromFile(
+                storage.getPendingUpdateRequestPath(), callbackRunner);
     }
 
     /**
@@ -264,13 +267,14 @@
      * Updates {@link WebappDataStorage} with the time of the latest WebAPK update and whether the
      * WebAPK update succeeded. Also updates the last requested "shell APK version".
      */
-    private void recordUpdate(@WebApkInstallResult int result, boolean relaxUpdates) {
+    private static void recordUpdate(
+            WebappDataStorage storage, @WebApkInstallResult int result, boolean relaxUpdates) {
         // Update the request time and result together. It prevents getting a correct request time
         // but a result from the previous request.
-        mStorage.updateTimeOfLastWebApkUpdateRequestCompletion();
-        mStorage.updateDidLastWebApkUpdateRequestSucceed(result == WebApkInstallResult.SUCCESS);
-        mStorage.setRelaxedUpdates(relaxUpdates);
-        mStorage.updateLastRequestedShellApkVersion(
+        storage.updateTimeOfLastWebApkUpdateRequestCompletion();
+        storage.updateDidLastWebApkUpdateRequestSucceed(result == WebApkInstallResult.SUCCESS);
+        storage.setRelaxedUpdates(relaxUpdates);
+        storage.updateLastRequestedShellApkVersion(
                 WebApkVersion.REQUEST_UPDATE_FOR_SHELL_APK_VERSION);
     }
 
@@ -278,9 +282,10 @@
      * Callback for when WebAPK update finishes or succeeds. Unlike {@link #recordUpdate()}
      * cannot be called while update is in progress.
      */
-    private void onFinishedUpdate(@WebApkInstallResult int result, boolean relaxUpdates) {
-        recordUpdate(result, relaxUpdates);
-        mStorage.deletePendingUpdateRequestFile();
+    private static void onFinishedUpdate(
+            WebappDataStorage storage, @WebApkInstallResult int result, boolean relaxUpdates) {
+        recordUpdate(storage, result, relaxUpdates);
+        storage.deletePendingUpdateRequestFile();
     }
 
     /**
@@ -367,9 +372,9 @@
             i++;
         }
 
-        nativeStoreWebApkUpdateRequestToFile(updateRequestPath, info.manifestStartUrl(),
-                info.scopeUri().toString(), info.name(), info.shortName(), primaryIconUrl,
-                info.icon(), badgeIconUrl, info.badgeIcon(), iconUrls, iconHashes,
+        WebApkUpdateManagerJni.get().storeWebApkUpdateRequestToFile(updateRequestPath,
+                info.manifestStartUrl(), info.scopeUri().toString(), info.name(), info.shortName(),
+                primaryIconUrl, info.icon(), badgeIconUrl, info.badgeIcon(), iconUrls, iconHashes,
                 info.displayMode(), info.orientation(), info.themeColor(), info.backgroundColor(),
                 info.shareTarget().getAction(), info.shareTarget().getParamTitle(),
                 info.shareTarget().getParamText(), info.shareTarget().getParamUrl(),
@@ -377,18 +382,17 @@
                 updateReason, callback);
     }
 
-    protected void updateWebApkFromFile(String updateRequestPath, WebApkUpdateCallback callback) {
-        nativeUpdateWebApkFromFile(updateRequestPath, callback);
+    @NativeMethods
+    interface Natives {
+        public void storeWebApkUpdateRequestToFile(String updateRequestPath, String startUrl,
+                String scope, String name, String shortName, String primaryIconUrl,
+                Bitmap primaryIcon, String badgeIconUrl, Bitmap badgeIcon, String[] iconUrls,
+                String[] iconHashes, @WebDisplayMode int displayMode, int orientation,
+                long themeColor, long backgroundColor, String shareTargetAction,
+                String shareTargetParamTitle, String shareTargetParamText,
+                String shareTargetParamUrl, String manifestUrl, String webApkPackage,
+                int webApkVersion, boolean isManifestStale, @WebApkUpdateReason int updateReason,
+                Callback<Boolean> callback);
+        public void updateWebApkFromFile(String updateRequestPath, WebApkUpdateCallback callback);
     }
-
-    private static native void nativeStoreWebApkUpdateRequestToFile(String updateRequestPath,
-            String startUrl, String scope, String name, String shortName, String primaryIconUrl,
-            Bitmap primaryIcon, String badgeIconUrl, Bitmap badgeIcon, String[] iconUrls,
-            String[] iconHashes, @WebDisplayMode int displayMode, int orientation, long themeColor,
-            long backgroundColor, String shareTargetAction, String shareTargetParamTitle,
-            String shareTargetParamText, String shareTargetParamUrl, String manifestUrl,
-            String webApkPackage, int webApkVersion, boolean isManifestStale,
-            @WebApkUpdateReason int updateReason, Callback<Boolean> callback);
-    private static native void nativeUpdateWebApkFromFile(
-            String updateRequestPath, WebApkUpdateCallback callback);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateTask.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateTask.java
index 0878d05..b563110c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateTask.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateTask.java
@@ -55,8 +55,8 @@
             Context context, TaskParameters taskParameters, final TaskFinishedCallback callback) {
         assert taskParameters.getTaskId() == TaskIds.WEBAPK_UPDATE_JOB_ID;
 
-        WebApkUpdateManager updateManager = new WebApkUpdateManager(mStorageToUpdate);
-        updateManager.updateWhileNotRunning(() -> callback.taskFinished(mMoreToUpdate));
+        WebApkUpdateManager.updateWhileNotRunning(
+                mStorageToUpdate, () -> callback.taskFinished(mMoreToUpdate));
     }
 
     @Override
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 37ea711..30b8e30b 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -327,6 +327,9 @@
       <message name="IDS_SIGNIN_PREF_SUMMARY" desc="Summary for the entry in Settings to sign in to Chrome, explaining benefits of signing in.">
         Sync and personalize across devices
       </message>
+      <message name="IDS_SYNC_AND_SERVICES_SUMMARY_SYNC_ON" desc="Summary for 'Sync and Google services' preference row when sync is enabled.">
+        Sync is on
+      </message>
       <message name="IDS_SIGN_IN_TO_CHROME_DISABLED_SUMMARY" desc="A descriptive line of text that appears under the 'Sign in to Chrome' option, in Chrome Settings on Android. The text explains why 'Sign in to Chrome' is disabled. 'Administrator' refers to the IT administrator of the company/organization that owns the user’s device.">
           Disabled by the administrator of this device
       </message>
@@ -1487,9 +1490,6 @@
       <message name="IDS_ACCOUNT_MANAGEMENT_SYNC_SUMMARY" desc="Description for which account the data is being synced to">
         Syncing to <ph name="SYNC_ACCOUNT_USER_NAME">%1$s<ex>johndoe@gmail.com</ex></ph>
       </message>
-      <message name="IDS_ACCOUNT_MANAGEMENT_SYNC_OFF_SUMMARY" desc="Description for Chrome Sync status when Chrome Sync is disabled">
-        Sync off for <ph name="SYNC_ACCOUNT_USER_NAME">%1$s<ex>johndoe@gmail.com</ex></ph>
-      </message>
       <message name="IDS_ACCOUNT_MANAGEMENT_SIGN_OUT" desc="Button text for signing out of Chrome">
         Sign out of Chrome
       </message>
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_ACCOUNT_MANAGEMENT_SYNC_OFF_SUMMARY.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_ACCOUNT_MANAGEMENT_SYNC_OFF_SUMMARY.png.sha1
deleted file mode 100644
index a88dddd..0000000
--- a/chrome/android/java/strings/android_chrome_strings_grd/IDS_ACCOUNT_MANAGEMENT_SYNC_OFF_SUMMARY.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-fe54a15ea6f3a26881d3fe88aeb4bcea264ce8d3
\ No newline at end of file
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_SYNC_AND_SERVICES_SUMMARY_SYNC_ON.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_SYNC_AND_SERVICES_SUMMARY_SYNC_ON.png.sha1
new file mode 100644
index 0000000..294ab2e
--- /dev/null
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_SYNC_AND_SERVICES_SUMMARY_SYNC_ON.png.sha1
@@ -0,0 +1 @@
+dc46845173245d91390108ee2f7d4339fff16af6
\ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigationPopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigationPopupTest.java
index 7f60dd5..1deced9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigationPopupTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigationPopupTest.java
@@ -212,6 +212,11 @@
 
         @Override
         public void setEntryExtraData(int index, String key, String value) {}
+
+        @Override
+        public boolean isEntryMarkedToBeSkipped(int index) {
+            return false;
+        }
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ReachedCodeProfilerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ReachedCodeProfilerTest.java
index fa025940..17b8273 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ReachedCodeProfilerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ReachedCodeProfilerTest.java
@@ -12,7 +12,6 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.BaseSwitches;
-import org.chromium.base.StrictModeContext;
 import org.chromium.base.test.ReachedCodeProfiler;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
@@ -105,10 +104,8 @@
     }
 
     private boolean getReachedCodeProfilerSharedPreference() {
-        try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
-            return ChromePreferenceManager.getInstance().readBoolean(
-                    REACHED_CODE_PROFILER_ENABLED_KEY, false);
-        }
+        return ChromePreferenceManager.getInstance().readBoolean(
+                REACHED_CODE_PROFILER_ENABLED_KEY, false);
     }
 
     private void setReachedCodeProfilerSharedPreference(boolean value) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorObserverTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorObserverTestRule.java
index 3bbc073..ffb57b5e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorObserverTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorObserverTestRule.java
@@ -81,8 +81,8 @@
         };
 
         TabModelOrderController orderController = new TabModelOrderController(mSelector);
-        TabContentManager tabContentManager =
-                new TabContentManager(InstrumentationRegistry.getTargetContext(), null, false);
+        TabContentManager tabContentManager = new TabContentManager(
+                InstrumentationRegistry.getTargetContext(), null, null, false);
         TabPersistencePolicy persistencePolicy = new TabbedModeTabPersistencePolicy(0, false);
         TabPersistentStore tabPersistentStore =
                 new TabPersistentStore(persistencePolicy, mSelector, null, null);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextual_suggestions/GoogleSearchRestrictionTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextual_suggestions/GoogleSearchRestrictionTest.java
index 6db276c..6c820ac 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/contextual_suggestions/GoogleSearchRestrictionTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextual_suggestions/GoogleSearchRestrictionTest.java
@@ -374,5 +374,10 @@
 
         @Override
         public void setEntryExtraData(int index, String key, String value) {}
+
+        @Override
+        public boolean isEntryMarkedToBeSkipped(int index) {
+            return false;
+        }
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java
index e53ba919..fa5c2f0 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java
@@ -33,6 +33,7 @@
 import org.chromium.base.PathUtils;
 import org.chromium.base.task.test.CustomShadowAsyncTask;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.JniMocker;
 import org.chromium.blink_public.platform.WebDisplayMode;
 import org.chromium.chrome.browser.ShortcutHelper;
 import org.chromium.chrome.browser.tab.Tab;
@@ -60,6 +61,9 @@
     @Rule
     public MockWebappDataStorageClockRule mClockRule = new MockWebappDataStorageClockRule();
 
+    @Rule
+    public JniMocker mJniMocker = new JniMocker();
+
     private static final String WEBAPK_PACKAGE_NAME = "org.chromium.webapk.test_package";
     private static final String UNBOUND_WEBAPK_PACKAGE_NAME = "com.webapk.test_package";
 
@@ -99,9 +103,33 @@
         }
     }
 
+    private static class TestWebApkUpdateManagerJni implements WebApkUpdateManager.Natives {
+        private static WebApkUpdateManager.WebApkUpdateCallback sUpdateCallback;
+
+        public static WebApkUpdateManager.WebApkUpdateCallback getUpdateCallback() {
+            return sUpdateCallback;
+        }
+
+        @Override
+        public void storeWebApkUpdateRequestToFile(String updateRequestPath, String startUrl,
+                String scope, String name, String shortName, String primaryIconUrl,
+                Bitmap primaryIcon, String badgeIconUrl, Bitmap badgeIcon, String[] iconUrls,
+                String[] iconHashes, @WebDisplayMode int displayMode, int orientation,
+                long themeColor, long backgroundColor, String shareTargetAction,
+                String shareTargetParamTitle, String shareTargetParamText,
+                String shareTargetParamUrl, String manifestUrl, String webApkPackage,
+                int webApkVersion, boolean isManifestStale, @WebApkUpdateReason int updateReason,
+                Callback<Boolean> callback) {}
+
+        @Override
+        public void updateWebApkFromFile(
+                String updateRequestPath, WebApkUpdateManager.WebApkUpdateCallback callback) {
+            sUpdateCallback = callback;
+        }
+    }
+
     private static class TestWebApkUpdateManager extends WebApkUpdateManager {
         private Callback<Boolean> mStoreUpdateRequestCallback;
-        private WebApkUpdateManager.WebApkUpdateCallback mUpdateCallback;
         private TestWebApkUpdateDataFetcher mFetcher;
         private String mUpdateName;
         private boolean mDestroyedFetcher;
@@ -139,10 +167,6 @@
             return mStoreUpdateRequestCallback;
         }
 
-        public WebApkUpdateManager.WebApkUpdateCallback getUpdateCallback() {
-            return mUpdateCallback;
-        }
-
         @Override
         protected WebApkUpdateDataFetcher buildFetcher() {
             mFetcher = new TestWebApkUpdateDataFetcher();
@@ -159,12 +183,6 @@
         }
 
         @Override
-        protected void updateWebApkFromFile(
-                String updateRequestPath, WebApkUpdateCallback callback) {
-            mUpdateCallback = callback;
-        }
-
-        @Override
         protected void destroyFetcher() {
             mFetcher = null;
             mDestroyedFetcher = true;
@@ -325,8 +343,8 @@
      * @param result The result of the update task. Emulates the proto creation as always
      *               succeeding.
      */
-    private static void tryCompletingUpdate(
-            TestWebApkUpdateManager updateManager, @WebApkInstallResult int result) {
+    private static void tryCompletingUpdate(TestWebApkUpdateManager updateManager,
+            WebappDataStorage storage, @WebApkInstallResult int result) {
         // Emulate proto creation as always succeeding.
         Callback<Boolean> storeUpdateRequestCallback =
                 updateManager.getStoreUpdateRequestCallback();
@@ -334,8 +352,9 @@
 
         storeUpdateRequestCallback.onResult(true);
 
-        updateManager.updateWhileNotRunning(Mockito.mock(Runnable.class));
-        WebApkUpdateManager.WebApkUpdateCallback updateCallback = updateManager.getUpdateCallback();
+        WebApkUpdateManager.updateWhileNotRunning(storage, Mockito.mock(Runnable.class));
+        WebApkUpdateManager.WebApkUpdateCallback updateCallback =
+                TestWebApkUpdateManagerJni.getUpdateCallback();
         if (updateCallback == null) return;
 
         updateCallback.onResultFromNative(result, false /* relaxUpdates */);
@@ -382,6 +401,8 @@
         PathUtils.setPrivateDataDirectorySuffix("chrome");
         CommandLine.init(null);
 
+        mJniMocker.mock(WebApkUpdateManagerJni.TEST_HOOKS, new TestWebApkUpdateManagerJni());
+
         registerWebApk(
                 WEBAPK_PACKAGE_NAME, defaultManifestData(), REQUEST_UPDATE_FOR_SHELL_APK_VERSION);
 
@@ -521,7 +542,7 @@
         assertNotNull(updateRequestPath);
         assertTrue(new File(updateRequestPath).exists());
 
-        tryCompletingUpdate(updateManager, WebApkInstallResult.FAILURE);
+        tryCompletingUpdate(updateManager, storage, WebApkInstallResult.FAILURE);
 
         assertNull(storage.getPendingUpdateRequestPath());
         assertFalse(new File(updateRequestPath).exists());
@@ -878,8 +899,8 @@
     public void testShellApkOutOfDate() {
         registerWebApk(WEBAPK_PACKAGE_NAME, defaultManifestData(),
                 REQUEST_UPDATE_FOR_SHELL_APK_VERSION - 1);
-        TestWebApkUpdateManager updateManager =
-                new TestWebApkUpdateManager(getStorage(WEBAPK_PACKAGE_NAME));
+        WebappDataStorage storage = getStorage(WEBAPK_PACKAGE_NAME);
+        TestWebApkUpdateManager updateManager = new TestWebApkUpdateManager(storage);
 
         // There have not been any update requests for the current ShellAPK version. A WebAPK update
         // should be requested immediately.
@@ -887,7 +908,7 @@
         assertTrue(updateManager.updateCheckStarted());
         onGotManifestData(updateManager, defaultManifestData());
         assertTrue(updateManager.updateRequested());
-        tryCompletingUpdate(updateManager, WebApkInstallResult.FAILURE);
+        tryCompletingUpdate(updateManager, storage, WebApkInstallResult.FAILURE);
 
         mClockRule.advance(1);
         updateIfNeeded(updateManager);
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 55d9ddb..0214f55 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5664,6 +5664,9 @@
       <message name="IDS_PICTURE_IN_PICTURE_PLAY_PAUSE_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button toggles between play and pause controls.">
         Toggle video to play or pause
       </message>
+      <message name="IDS_PICTURE_IN_PICTURE_NEXT_TRACK_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button invokes next track action.">
+        Next track
+      </message>
       <message name="IDS_PICTURE_IN_PICTURE_CONFIRM_CLOSE_TITLE" desc="Text label of the title for the confirmation dialog. This dialog appears when the user tries to close a tab / window while in Picture-in-Picture mode.">
         Are you sure you want to close this tab?
       </message>
diff --git a/chrome/app/md_extensions_strings.grdp b/chrome/app/md_extensions_strings.grdp
index aa875dd..6ddc480 100644
--- a/chrome/app/md_extensions_strings.grdp
+++ b/chrome/app/md_extensions_strings.grdp
@@ -80,7 +80,7 @@
     Unknown
   </message>
   <message name="IDS_MD_EXTENSIONS_CLEAR_ACTIVITIES" desc="The label for the button that clears the activity log for the current extension.">
-    Clear activities
+    Clear
   </message>
   <message name="IDS_MD_EXTENSIONS_ERROR_CLEAR_ALL" desc="The label for the button that clears all the errors.">
     Clear all
@@ -133,6 +133,24 @@
   <message name="IDS_MD_EXTENSIONS_ACTIVITY_LOG_SEARCH_LABEL" desc="The placeholder label to display in the search bar for the activity log page.">
     Search by API call/URL
   </message>
+  <message name="IDS_MD_EXTENSIONS_ACTIVITY_LOG_HISTORY_TAB_HEADING" desc="The heading for the activity log history tab.">
+    History
+  </message>
+  <message name="IDS_MD_EXTENSIONS_ACTIVITY_LOG_STREAM_TAB_HEADING" desc="The heading for the activity log stream tab.">
+    Real-time
+  </message>
+  <message name="IDS_MD_EXTENSIONS_START_ACTIVITY_STREAM" desc="The label of the button used to start the activity stream.">
+    Start recording
+  </message>
+  <message name="IDS_MD_EXTENSIONS_STOP_ACTIVITY_STREAM" desc="The label of the button used to stop the activity stream.">
+    Stop recording
+  </message>
+  <message name="IDS_MD_EXTENSIONS_EMPTY_STREAM_STARTED" desc="The message shown to the user when there are no activities in the activity log stream and the activity log page is listening to the stream.">
+    Listening for extension activities...
+  </message>
+  <message name="IDS_MD_EXTENSIONS_EMPTY_STREAM_STOPPED" desc="The message shown to the user when there are no activities in the activity log stream and there are no listeners for the stream.">
+    Press "Start" to listen for extension activities
+  </message>
   <message name="IDS_MD_EXTENSIONS_ITEM_ID" desc="The text for the label next to the extension id.">
     &lt;span&gt;ID: &lt;/span&gt;<ph name="EXTENSION_ID">$1<ex>cfhdojbkjhnklbpkdaibdccddilifddb</ex></ph>
   </message>
diff --git a/chrome/app/vector_icons/google_pay_logo.icon b/chrome/app/vector_icons/google_pay_logo.icon
index 8830edf..03a38032 100644
--- a/chrome/app/vector_icons/google_pay_logo.icon
+++ b/chrome/app/vector_icons/google_pay_logo.icon
@@ -4,8 +4,7 @@
 
 CANVAS_DIMENSIONS, 40,
 
-// Pay part.
-PATH_COLOR_ARGB, 0xFF, 0x5F, 0x63, 0x68,
+// "Pay" text.  Color is set by Chrome code at runtime depending on dark mode.
 MOVE_TO, 18.92f, 7.82f,
 R_V_LINE_TO, 4.64f,
 H_LINE_TO, 17.44f,
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 21dbdd93..2ce0072 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -84,8 +84,10 @@
   sources = [
     "about_flags.cc",
     "about_flags.h",
-    "accessibility/accessibility_labels_prefs.cc",
-    "accessibility/accessibility_labels_prefs.h",
+    "accessibility/accessibility_labels_service.cc",
+    "accessibility/accessibility_labels_service.h",
+    "accessibility/accessibility_labels_service_factory.cc",
+    "accessibility/accessibility_labels_service_factory.h",
     "accessibility/accessibility_permission_context.cc",
     "accessibility/accessibility_permission_context.h",
     "accessibility/accessibility_state_utils.cc",
@@ -5401,8 +5403,6 @@
     "search_engines/template_url_service_factory_test_util.h",
     "search_engines/template_url_service_test_util.cc",
     "search_engines/template_url_service_test_util.h",
-    "signin/fake_account_fetcher_service_builder.cc",
-    "signin/fake_account_fetcher_service_builder.h",
     "signin/gaia_cookie_manager_service_test_util.cc",
     "signin/gaia_cookie_manager_service_test_util.h",
     "signin/identity_test_environment_profile_adaptor.cc",
diff --git a/chrome/browser/accessibility/accessibility_labels_prefs.cc b/chrome/browser/accessibility/accessibility_labels_prefs.cc
deleted file mode 100644
index 5cf704f..0000000
--- a/chrome/browser/accessibility/accessibility_labels_prefs.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/accessibility/accessibility_labels_prefs.h"
-
-#include "chrome/common/pref_names.h"
-#include "components/pref_registry/pref_registry_syncable.h"
-
-namespace accessibility_prefs {
-
-void RegisterAccessibilityLabelsProfilePrefs(
-    user_prefs::PrefRegistrySyncable* registry) {
-  registry->RegisterBooleanPref(prefs::kAccessibilityImageLabelsEnabled, false);
-}
-
-}  // namespace accessibility_prefs
diff --git a/chrome/browser/accessibility/accessibility_labels_prefs.h b/chrome/browser/accessibility/accessibility_labels_prefs.h
deleted file mode 100644
index fd7471f..0000000
--- a/chrome/browser/accessibility/accessibility_labels_prefs.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_LABELS_PREFS_H_
-#define CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_LABELS_PREFS_H_
-
-namespace user_prefs {
-class PrefRegistrySyncable;
-}
-
-namespace accessibility_prefs {
-
-// The accessibility labels preference should be registered on a user profile.
-void RegisterAccessibilityLabelsProfilePrefs(
-    user_prefs::PrefRegistrySyncable* registry);
-
-}  // namespace accessibility_prefs
-
-#endif  // CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_LABELS_PREFS_H_
diff --git a/chrome/browser/accessibility/accessibility_labels_service.cc b/chrome/browser/accessibility/accessibility_labels_service.cc
new file mode 100644
index 0000000..7648199
--- /dev/null
+++ b/chrome/browser/accessibility/accessibility_labels_service.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/accessibility/accessibility_labels_service.h"
+
+#include "base/command_line.h"
+#include "build/build_config.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
+#include "chrome/common/pref_names.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/browser/browser_accessibility_state.h"
+#include "ui/accessibility/accessibility_switches.h"
+
+AccessibilityLabelsService::~AccessibilityLabelsService() {}
+
+// static
+void AccessibilityLabelsService::RegisterProfilePrefs(
+    user_prefs::PrefRegistrySyncable* registry) {
+  registry->RegisterBooleanPref(prefs::kAccessibilityImageLabelsEnabled, false);
+}
+
+void AccessibilityLabelsService::Init() {
+  // Hidden behind a feature flag.
+  base::CommandLine& cmd = *base::CommandLine::ForCurrentProcess();
+  if (!cmd.HasSwitch(::switches::kEnableExperimentalAccessibilityLabels))
+    return;
+
+  pref_change_registrar_.Init(profile_->GetPrefs());
+  pref_change_registrar_.Add(
+      prefs::kAccessibilityImageLabelsEnabled,
+      base::BindRepeating(
+          &AccessibilityLabelsService::OnImageLabelsEnabledChanged,
+          weak_factory_.GetWeakPtr()));
+}
+
+AccessibilityLabelsService::AccessibilityLabelsService(Profile* profile)
+    : profile_(profile), weak_factory_(this) {}
+
+ui::AXMode AccessibilityLabelsService::GetAXMode() {
+  ui::AXMode ax_mode =
+      content::BrowserAccessibilityState::GetInstance()->GetAccessibilityMode();
+
+  // Hidden behind a feature flag.
+  base::CommandLine& cmd = *base::CommandLine::ForCurrentProcess();
+  if (cmd.HasSwitch(::switches::kEnableExperimentalAccessibilityLabels)) {
+    bool enabled = profile_->GetPrefs()->GetBoolean(
+        prefs::kAccessibilityImageLabelsEnabled);
+    ax_mode.set_mode(ui::AXMode::kLabelImages, enabled);
+  }
+
+  return ax_mode;
+}
+
+void AccessibilityLabelsService::OnImageLabelsEnabledChanged() {
+  // TODO(dmazzoni) Implement for Android, which doesn't support
+  // AllTabContentses(). crbug.com/905419
+#if !defined(OS_ANDROID)
+  bool enabled =
+      profile_->GetPrefs()->GetBoolean(prefs::kAccessibilityImageLabelsEnabled);
+
+  for (auto* web_contents : AllTabContentses()) {
+    if (web_contents->GetBrowserContext() != profile_)
+      continue;
+
+    ui::AXMode ax_mode = web_contents->GetAccessibilityMode();
+    ax_mode.set_mode(ui::AXMode::kLabelImages, enabled);
+    web_contents->SetAccessibilityMode(ax_mode);
+  }
+#endif
+}
diff --git a/chrome/browser/accessibility/accessibility_labels_service.h b/chrome/browser/accessibility/accessibility_labels_service.h
new file mode 100644
index 0000000..fe197d7
--- /dev/null
+++ b/chrome/browser/accessibility/accessibility_labels_service.h
@@ -0,0 +1,52 @@
+// 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_ACCESSIBILITY_ACCESSIBILITY_LABELS_SERVICE_H_
+#define CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_LABELS_SERVICE_H_
+
+#include "base/memory/weak_ptr.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "ui/accessibility/ax_mode.h"
+
+class Profile;
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+// Manages the feature that generates automatic image labels for accessibility.
+// Tracks the per-profile preference and updates the accessibility mode of
+// WebContents when it changes, provided image labeling is not disabled via
+// command-line switch.
+class AccessibilityLabelsService : public KeyedService {
+ public:
+  ~AccessibilityLabelsService() override;
+
+  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+
+  void Init();
+
+  ui::AXMode GetAXMode();
+
+ private:
+  friend class AccessibilityLabelsServiceFactory;
+
+  // Use |AccessibilityLabelsServiceFactory::GetForProfile(..)| to get
+  // an instance of this service.
+  explicit AccessibilityLabelsService(Profile* profile);
+
+  void OnImageLabelsEnabledChanged();
+
+  // Owns us via the KeyedService mechanism.
+  Profile* profile_;
+
+  PrefChangeRegistrar pref_change_registrar_;
+
+  base::WeakPtrFactory<AccessibilityLabelsService> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(AccessibilityLabelsService);
+};
+
+#endif  // CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_LABELS_SERVICE_H_
diff --git a/chrome/browser/accessibility/accessibility_labels_service_browsertest.cc b/chrome/browser/accessibility/accessibility_labels_service_browsertest.cc
new file mode 100644
index 0000000..6abf7cb0
--- /dev/null
+++ b/chrome/browser/accessibility/accessibility_labels_service_browsertest.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 "base/command_line.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/browser/browser_accessibility_state.h"
+#include "ui/accessibility/accessibility_switches.h"
+
+class AccessibilityLabelsBrowserTest : public InProcessBrowserTest {
+ public:
+  AccessibilityLabelsBrowserTest() {}
+
+  // InProcessBrowserTest overrides:
+  void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
+    InProcessBrowserTest::SetUpDefaultCommandLine(command_line);
+    command_line->AppendSwitch(
+        switches::kEnableExperimentalAccessibilityLabels);
+  }
+};
+
+// Changing the kAccessibilityImageLabelsEnabled pref should affect the
+// accessibility mode of a new WebContents for this profile.
+IN_PROC_BROWSER_TEST_F(AccessibilityLabelsBrowserTest, NewWebContents) {
+  ui::AXMode ax_mode =
+      content::BrowserAccessibilityState::GetInstance()->GetAccessibilityMode();
+  EXPECT_FALSE(ax_mode.has_mode(ui::AXMode::kLabelImages));
+
+  chrome::NewTab(browser());
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ax_mode = web_contents->GetAccessibilityMode();
+  EXPECT_FALSE(ax_mode.has_mode(ui::AXMode::kLabelImages));
+
+  browser()->profile()->GetPrefs()->SetBoolean(
+      prefs::kAccessibilityImageLabelsEnabled, true);
+
+  chrome::NewTab(browser());
+  web_contents = browser()->tab_strip_model()->GetActiveWebContents();
+  ax_mode = web_contents->GetAccessibilityMode();
+  EXPECT_TRUE(ax_mode.has_mode(ui::AXMode::kLabelImages));
+
+  browser()->profile()->GetPrefs()->SetBoolean(
+      prefs::kAccessibilityImageLabelsEnabled, false);
+
+  chrome::NewTab(browser());
+  web_contents = browser()->tab_strip_model()->GetActiveWebContents();
+  ax_mode = web_contents->GetAccessibilityMode();
+  EXPECT_FALSE(ax_mode.has_mode(ui::AXMode::kLabelImages));
+}
+
+// Changing the kAccessibilityImageLabelsEnabled pref should affect the
+// accessibility mode of existing WebContents in this profile.
+IN_PROC_BROWSER_TEST_F(AccessibilityLabelsBrowserTest, ExistingWebContents) {
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ui::AXMode ax_mode = web_contents->GetAccessibilityMode();
+  EXPECT_FALSE(ax_mode.has_mode(ui::AXMode::kLabelImages));
+
+  browser()->profile()->GetPrefs()->SetBoolean(
+      prefs::kAccessibilityImageLabelsEnabled, true);
+
+  ax_mode = web_contents->GetAccessibilityMode();
+  EXPECT_TRUE(ax_mode.has_mode(ui::AXMode::kLabelImages));
+
+  browser()->profile()->GetPrefs()->SetBoolean(
+      prefs::kAccessibilityImageLabelsEnabled, false);
+
+  ax_mode = web_contents->GetAccessibilityMode();
+  EXPECT_FALSE(ax_mode.has_mode(ui::AXMode::kLabelImages));
+}
diff --git a/chrome/browser/accessibility/accessibility_labels_service_factory.cc b/chrome/browser/accessibility/accessibility_labels_service_factory.cc
new file mode 100644
index 0000000..91d0e5d7
--- /dev/null
+++ b/chrome/browser/accessibility/accessibility_labels_service_factory.cc
@@ -0,0 +1,54 @@
+// 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/accessibility/accessibility_labels_service_factory.h"
+
+#include "chrome/browser/accessibility/accessibility_labels_service.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+
+// static
+AccessibilityLabelsService* AccessibilityLabelsServiceFactory::GetForProfile(
+    Profile* profile) {
+  return static_cast<AccessibilityLabelsService*>(
+      GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+AccessibilityLabelsService*
+AccessibilityLabelsServiceFactory::GetForProfileIfExists(Profile* profile) {
+  return static_cast<AccessibilityLabelsService*>(
+      GetInstance()->GetServiceForBrowserContext(profile, /*create=*/false));
+}
+
+// static
+AccessibilityLabelsServiceFactory*
+AccessibilityLabelsServiceFactory::GetInstance() {
+  return base::Singleton<AccessibilityLabelsServiceFactory>::get();
+}
+
+// static
+KeyedService* AccessibilityLabelsServiceFactory::BuildInstanceFor(
+    Profile* profile) {
+  return new AccessibilityLabelsService(profile);
+}
+
+AccessibilityLabelsServiceFactory::AccessibilityLabelsServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+          "AccessibilityLabelsService",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+AccessibilityLabelsServiceFactory::~AccessibilityLabelsServiceFactory() {}
+
+content::BrowserContext*
+AccessibilityLabelsServiceFactory::GetBrowserContextToUse(
+    content::BrowserContext* context) const {
+  return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
+
+KeyedService* AccessibilityLabelsServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* profile) const {
+  return BuildInstanceFor(static_cast<Profile*>(profile));
+}
diff --git a/chrome/browser/accessibility/accessibility_labels_service_factory.h b/chrome/browser/accessibility/accessibility_labels_service_factory.h
new file mode 100644
index 0000000..f8ac1521
--- /dev/null
+++ b/chrome/browser/accessibility/accessibility_labels_service_factory.h
@@ -0,0 +1,41 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_LABELS_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_LABELS_SERVICE_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class Profile;
+class AccessibilityLabelsService;
+
+// Factory to get or create an instance of AccessibilityLabelsService from
+// a Profile.
+class AccessibilityLabelsServiceFactory
+    : public BrowserContextKeyedServiceFactory {
+ public:
+  static AccessibilityLabelsService* GetForProfile(Profile* profile);
+
+  static AccessibilityLabelsService* GetForProfileIfExists(Profile* profile);
+
+  static AccessibilityLabelsServiceFactory* GetInstance();
+
+  // Used to create instances for testing.
+  static KeyedService* BuildInstanceFor(Profile* profile);
+
+ private:
+  friend struct base::DefaultSingletonTraits<AccessibilityLabelsServiceFactory>;
+
+  AccessibilityLabelsServiceFactory();
+  ~AccessibilityLabelsServiceFactory() override;
+
+  // BrowserContextKeyedServiceFactory:
+  content::BrowserContext* GetBrowserContextToUse(
+      content::BrowserContext* context) const override;
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* profile) const override;
+};
+
+#endif  // CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_LABELS_SERVICE_FACTORY_H_
diff --git a/chrome/browser/android/autofill_assistant/client_android.cc b/chrome/browser/android/autofill_assistant/client_android.cc
index 17a534e..f734780 100644
--- a/chrome/browser/android/autofill_assistant/client_android.cc
+++ b/chrome/browser/android/autofill_assistant/client_android.cc
@@ -123,7 +123,7 @@
 base::android::ScopedJavaLocalRef<jstring> ClientAndroid::GetPrimaryAccountName(
     JNIEnv* env,
     const JavaParamRef<jobject>& jcaller) {
-  AccountInfo account_info =
+  CoreAccountInfo account_info =
       IdentityManagerFactory::GetForProfile(
           Profile::FromBrowserContext(web_contents_->GetBrowserContext()))
           ->GetPrimaryAccountInfo();
diff --git a/chrome/browser/android/compositor/tab_content_manager.cc b/chrome/browser/android/compositor/tab_content_manager.cc
index bd01868..7e6d7c54 100644
--- a/chrome/browser/android/compositor/tab_content_manager.cc
+++ b/chrome/browser/android/compositor/tab_content_manager.cc
@@ -28,6 +28,7 @@
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "jni/TabContentManager_jni.h"
+#include "skia/ext/image_operations.h"
 #include "ui/android/resources/ui_resource_provider.h"
 #include "ui/android/view_android.h"
 #include "ui/gfx/android/java_bitmap.h"
@@ -338,9 +339,13 @@
     bool result,
     SkBitmap bitmap) {
   ScopedJavaLocalRef<jobject> j_bitmap;
-  if (!bitmap.isNull() && result)
-    j_bitmap = gfx::ConvertToJavaBitmap(&bitmap);
-
+  if (!bitmap.isNull() && result) {
+    SkIRect dest_subset = {0, 0, bitmap.width() / 2, bitmap.width() / 2};
+    SkBitmap result_bitmap = skia::ImageOperations::Resize(
+        bitmap, skia::ImageOperations::RESIZE_BETTER, bitmap.width() / 2,
+        bitmap.height() / 2, dest_subset);
+    j_bitmap = gfx::ConvertToJavaBitmap(&result_bitmap);
+  }
   RunObjectCallbackAndroid(j_callback, j_bitmap);
 }
 
diff --git a/chrome/browser/android/preferences/website_preference_bridge.cc b/chrome/browser/android/preferences/website_preference_bridge.cc
index 4e71e4d..9b6344b 100644
--- a/chrome/browser/android/preferences/website_preference_bridge.cc
+++ b/chrome/browser/android/preferences/website_preference_bridge.cc
@@ -591,7 +591,7 @@
       ConvertJavaStringToUTF8(env, jembedder.is_null() ? jorigin : jembedder));
   DCHECK(embedder.is_valid());
   std::unique_ptr<base::DictionaryValue> object = base::DictionaryValue::From(
-      base::JSONReader::Read(ConvertJavaStringToUTF8(env, jobject)));
+      base::JSONReader::ReadDeprecated(ConvertJavaStringToUTF8(env, jobject)));
   DCHECK(object);
   ChooserContextBase* context = GetChooserContext(
       static_cast<ContentSettingsType>(content_settings_type));
diff --git a/chrome/browser/apps/platform_apps/platform_app_navigation_redirector.cc b/chrome/browser/apps/platform_apps/platform_app_navigation_redirector.cc
index ac39a70..ab39cd8 100644
--- a/chrome/browser/apps/platform_apps/platform_app_navigation_redirector.cc
+++ b/chrome/browser/apps/platform_apps/platform_app_navigation_redirector.cc
@@ -115,7 +115,8 @@
                << "):" << handler->id;
       return std::make_unique<
           navigation_interception::InterceptNavigationThrottle>(
-          handle, base::Bind(&LaunchAppWithUrl, extension_ref, handler->id));
+          handle, base::Bind(&LaunchAppWithUrl, extension_ref, handler->id),
+          navigation_interception::SynchronyMode::kSync);
     }
   }
 
diff --git a/chrome/browser/autofill/autofill_save_card_infobar_delegate_mobile_unittest.cc b/chrome/browser/autofill/autofill_save_card_infobar_delegate_mobile_unittest.cc
index 07fcb16..d6100d7b 100644
--- a/chrome/browser/autofill/autofill_save_card_infobar_delegate_mobile_unittest.cc
+++ b/chrome/browser/autofill/autofill_save_card_infobar_delegate_mobile_unittest.cc
@@ -112,7 +112,7 @@
   std::unique_ptr<base::DictionaryValue> legal_message;
   if (!legal_message_string.empty()) {
     std::unique_ptr<base::Value> value(
-        base::JSONReader::Read(legal_message_string));
+        base::JSONReader::ReadDeprecated(legal_message_string));
     EXPECT_TRUE(value);
     base::DictionaryValue* dictionary;
     EXPECT_TRUE(value->GetAsDictionary(&dictionary));
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 6308143..e8dba9c 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -102,7 +102,9 @@
         <include name="IDR_ABOUT_NACL_JS" file="resources\about_nacl.js" type="BINDATA" />
       </if>
       <if expr="not is_android">
-        <include name="IDR_ABOUT_SYS_HTML" file="resources\about_sys\about_sys.html" flattenhtml="true" type="BINDATA" />
+        <include name="IDR_ABOUT_SYS_HTML" file="resources\about_sys\about_sys.html" compress="gzip" flattenhtml="true" type="BINDATA" />
+        <include name="IDR_ABOUT_SYS_CSS" file="resources\about_sys\about_sys.css" compress="gzip" type="BINDATA" />
+        <include name="IDR_ABOUT_SYS_JS" file="resources\about_sys\about_sys.js" compress="gzip" type="BINDATA" />
       </if>
       <include name="IDR_ACCESSIBILITY_HTML" file="resources\accessibility\accessibility.html" flattenhtml="true" allowexternalscript="true" compress="gzip" type="BINDATA" />
       <include name="IDR_ACCESSIBILITY_CSS" file="resources\accessibility\accessibility.css" compress="gzip" type="BINDATA" />
diff --git a/chrome/browser/browser_switcher/browser_switcher_navigation_throttle.cc b/chrome/browser/browser_switcher/browser_switcher_navigation_throttle.cc
index 8e161650..df8fd55 100644
--- a/chrome/browser/browser_switcher/browser_switcher_navigation_throttle.cc
+++ b/chrome/browser/browser_switcher/browser_switcher_navigation_throttle.cc
@@ -93,7 +93,8 @@
     return nullptr;
 
   return std::make_unique<navigation_interception::InterceptNavigationThrottle>(
-      navigation, base::BindRepeating(&MaybeLaunchAlternativeBrowser));
+      navigation, base::BindRepeating(&MaybeLaunchAlternativeBrowser),
+      navigation_interception::SynchronyMode::kSync);
 }
 
 }  // namespace browser_switcher
diff --git a/chrome/browser/chrome_browser_field_trials_mobile.cc b/chrome/browser/chrome_browser_field_trials_mobile.cc
index df3f583..e999f030 100644
--- a/chrome/browser/chrome_browser_field_trials_mobile.cc
+++ b/chrome/browser/chrome_browser_field_trials_mobile.cc
@@ -8,6 +8,7 @@
 
 #if defined(OS_ANDROID)
 #include "base/android/library_loader/library_loader_hooks.h"
+#include "base/android/reached_code_profiler.h"
 #include "base/base_switches.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
@@ -22,10 +23,11 @@
 
   // For tests on some platforms, g_browser_process is not initialized yet.
   if (g_browser_process) {
-    static constexpr char kOrderfileOptimizationTrial[] =
-        "AndroidOrderfileOptimization";
     static constexpr char kEnabledGroup[] = "Enabled";
     static constexpr char kDisabledGroup[] = "Disabled";
+
+    static constexpr char kOrderfileOptimizationTrial[] =
+        "AndroidOrderfileOptimization";
     if (base::android::IsUsingOrderfileOptimization()) {
       ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial(
           kOrderfileOptimizationTrial, kEnabledGroup);
@@ -33,6 +35,16 @@
       ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial(
           kOrderfileOptimizationTrial, kDisabledGroup);
     }
+
+    static constexpr char kReachedCodeProfilerTrial[] =
+        "ReachedCodeProfilerSynthetic";
+    if (base::android::IsReachedCodeProfilerEnabled()) {
+      ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial(
+          kReachedCodeProfilerTrial, kEnabledGroup);
+    } else {
+      ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial(
+          kReachedCodeProfilerTrial, kDisabledGroup);
+    }
   }
 
 #endif
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 11daea22..5df10b80 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -37,6 +37,8 @@
 #include "chrome/app/chrome_content_utility_overlay_manifest.h"
 #include "chrome/app/chrome_packaged_service_manifests.h"
 #include "chrome/app/chrome_renderer_manifest.h"
+#include "chrome/browser/accessibility/accessibility_labels_service.h"
+#include "chrome/browser/accessibility/accessibility_labels_service_factory.h"
 #include "chrome/browser/after_startup_task_utils.h"
 #include "chrome/browser/browser_about_handler.h"
 #include "chrome/browser/browser_process.h"
@@ -4114,7 +4116,7 @@
   if (!prerender_contents && handle->IsInMainFrame()) {
     throttles.push_back(
         navigation_interception::InterceptNavigationDelegate::CreateThrottleFor(
-            handle));
+            handle, navigation_interception::SynchronyMode::kAsync));
   }
   throttles.push_back(InterceptOMADownloadNavigationThrottle::Create(handle));
 #elif BUILDFLAG(ENABLE_EXTENSIONS)
@@ -5556,3 +5558,9 @@
   URLBlacklistState blacklist_state = service->GetURLBlacklistState(url);
   return blacklist_state == URLBlacklistState::URL_IN_BLACKLIST;
 }
+
+ui::AXMode ChromeContentBrowserClient::GetAXModeForBrowserContext(
+    content::BrowserContext* browser_context) {
+  Profile* profile = Profile::FromBrowserContext(browser_context);
+  return AccessibilityLabelsServiceFactory::GetForProfile(profile)->GetAXMode();
+}
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 1a863bab..4f7e87d 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -564,6 +564,9 @@
   bool IsRendererDebugURLBlacklisted(const GURL& url,
                                      content::BrowserContext* context) override;
 
+  ui::AXMode GetAXModeForBrowserContext(
+      content::BrowserContext* browser_context) override;
+
   // Determines the committed previews state for the passed in params.
   static content::PreviewsState DetermineCommittedPreviewsForURL(
       const GURL& url,
diff --git a/chrome/browser/chromeos/arc/extensions/arc_support_message_host.cc b/chrome/browser/chromeos/arc/extensions/arc_support_message_host.cc
index 5aa3837..64c16803 100644
--- a/chrome/browser/chromeos/arc/extensions/arc_support_message_host.cc
+++ b/chrome/browser/chromeos/arc/extensions/arc_support_message_host.cc
@@ -73,7 +73,7 @@
     return;
 
   std::unique_ptr<base::Value> message_value =
-      base::JSONReader::Read(message_string);
+      base::JSONReader::ReadDeprecated(message_string);
   base::DictionaryValue* message;
   if (!message_value || !message_value->GetAsDictionary(&message)) {
     NOTREACHED();
diff --git a/chrome/browser/chromeos/arc/extensions/arc_support_message_host_unittest.cc b/chrome/browser/chromeos/arc/extensions/arc_support_message_host_unittest.cc
index a31ba8b..a6fb824 100644
--- a/chrome/browser/chromeos/arc/extensions/arc_support_message_host_unittest.cc
+++ b/chrome/browser/chromeos/arc/extensions/arc_support_message_host_unittest.cc
@@ -103,7 +103,7 @@
 
   ASSERT_EQ(1u, client()->messages().size());
   std::unique_ptr<base::Value> recieved_value =
-      base::JSONReader::Read(client()->messages()[0]);
+      base::JSONReader::ReadDeprecated(client()->messages()[0]);
   EXPECT_EQ(value, *recieved_value);
 }
 
diff --git a/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc b/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc
index e163112..efec46a 100644
--- a/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc
+++ b/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc
@@ -142,8 +142,8 @@
 
 void FakeArcSupport::PostMessageFromNativeHost(
     const std::string& message_string) {
-  std::unique_ptr<base::DictionaryValue> message =
-      base::DictionaryValue::From(base::JSONReader::Read(message_string));
+  std::unique_ptr<base::DictionaryValue> message = base::DictionaryValue::From(
+      base::JSONReader::ReadDeprecated(message_string));
   DCHECK(message);
 
   std::string action;
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler_unittest.cc b/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler_unittest.cc
index 1468e24..05debf4 100644
--- a/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler_unittest.cc
+++ b/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler_unittest.cc
@@ -256,10 +256,10 @@
   EXPECT_CALL(*mock_script_executor_, ExecuteJavaScript(kScriptGetElements, _))
       .WillOnce(testing::Invoke(
           [](const std::string&, const JavaScriptResultCallback& callback) {
-            callback.Run(
-                base::JSONReader::Read("{\"dirNames\" :[\"dir1\", \"dir2\"],"
-                                       " \"fileNames\":[\"file1\",\"file2\"]}")
-                    .get());
+            callback.Run(base::JSONReader::ReadDeprecated(
+                             "{\"dirNames\" :[\"dir1\", \"dir2\"],"
+                             " \"fileNames\":[\"file1\",\"file2\"]}")
+                             .get());
           }));
 
   mojom::FileSelectorElementsPtr expectedElements =
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_browsertest.cc b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_browsertest.cc
index bba8271..127e32e 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_browsertest.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_browsertest.cc
@@ -191,7 +191,8 @@
   int count = 0;
   for (const FakeIntentHelperInstance::Broadcast& broadcast : broadcasts) {
     if (broadcast.action == kSetProxyBroadcastAction) {
-      EXPECT_TRUE(base::JSONReader::Read(broadcast.extras)->Equals(extras));
+      EXPECT_TRUE(
+          base::JSONReader::ReadDeprecated(broadcast.extras)->Equals(extras));
       count++;
     }
   }
diff --git a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc
index f68926c7..abe34ec8 100644
--- a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc
+++ b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc
@@ -95,4 +95,8 @@
   // Should be a no-op on ARC. This is managed on the Android side.
 }
 
+void ArcPictureInPictureWindowControllerImpl::NextTrack() {
+  // Should be a no-op on ARC. This is managed on the Android side.
+}
+
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h
index 0bc5b3f..00f6e12 100644
--- a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h
+++ b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h
@@ -51,6 +51,7 @@
                            bool reached_end_of_stream) override;
   void SetAlwaysHidePlayPauseButton(bool is_visible) override;
   void SkipAd() override;
+  void NextTrack() override;
 
  private:
   arc::ArcPipBridge* const arc_pip_bridge_;
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc
index ec9957e..9b6938c3 100644
--- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc
+++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc
@@ -228,7 +228,8 @@
     std::string app_policy_string;
     app_policy_value->GetAsString(&app_policy_string);
     std::unique_ptr<base::DictionaryValue> app_policy_dict =
-        base::DictionaryValue::From(base::JSONReader::Read(app_policy_string));
+        base::DictionaryValue::From(
+            base::JSONReader::ReadDeprecated(app_policy_string));
     if (app_policy_dict) {
       // Need a deep copy of all values here instead of doing a swap, because
       // JSONReader::Read constructs a dictionary whose StringValues are
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 04f638c..510ea1c 100644
--- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
+++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
@@ -197,7 +197,7 @@
       const std::string& compliance_report) {
     Mock::VerifyAndClearExpectations(&observer_);
     std::unique_ptr<base::Value> compliance_report_value =
-        base::JSONReader::Read(compliance_report);
+        base::JSONReader::ReadDeprecated(compliance_report);
     if (compliance_report_value && compliance_report_value->is_dict()) {
       EXPECT_CALL(observer_, OnComplianceReportReceived(
                                  ValueEquals(compliance_report_value.get())));
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_util.cc b/chrome/browser/chromeos/arc/policy/arc_policy_util.cc
index f7232e5..8362988 100644
--- a/chrome/browser/chromeos/arc/policy/arc_policy_util.cc
+++ b/chrome/browser/chromeos/arc/policy/arc_policy_util.cc
@@ -46,7 +46,8 @@
 
 std::set<std::string> GetRequestedPackagesFromArcPolicy(
     const std::string& arc_policy) {
-  std::unique_ptr<base::Value> dict = base::JSONReader::Read(arc_policy);
+  std::unique_ptr<base::Value> dict =
+      base::JSONReader::ReadDeprecated(arc_policy);
   if (!dict || !dict->is_dict())
     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 a56d3a4..da7bedb 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.cc
+++ b/chrome/browser/chromeos/arc/tracing/arc_tracing_graphics_model.cc
@@ -892,7 +892,7 @@
   Reset();
 
   const std::unique_ptr<base::DictionaryValue> root =
-      base::DictionaryValue::From(base::JSONReader::Read(json_data));
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(json_data));
   if (!root)
     return false;
 
diff --git a/chrome/browser/chromeos/arc/tracing/arc_tracing_model.cc b/chrome/browser/chromeos/arc/tracing/arc_tracing_model.cc
index 397e498..6e8f37f 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_tracing_model.cc
+++ b/chrome/browser/chromeos/arc/tracing/arc_tracing_model.cc
@@ -90,7 +90,7 @@
 ArcTracingModel::~ArcTracingModel() = default;
 
 bool ArcTracingModel::Build(const std::string& data) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(data);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(data);
   if (!value) {
     LOG(ERROR) << "Cannot parse trace data";
     return false;
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 df40717..c432b7e 100644
--- a/chrome/browser/chromeos/arc/tracing/arc_tracing_model_unittest.cc
+++ b/chrome/browser/chromeos/arc/tracing/arc_tracing_model_unittest.cc
@@ -189,7 +189,7 @@
 }
 
 TEST_F(ArcTracingModelTest, Event) {
-  const ArcTracingEvent event(base::JSONReader::Read(kTestEvent));
+  const ArcTracingEvent event(base::JSONReader::ReadDeprecated(kTestEvent));
 
   EXPECT_EQ(4640, event.GetPid());
   EXPECT_EQ(4641, event.GetTid());
@@ -206,19 +206,19 @@
 }
 
 TEST_F(ArcTracingModelTest, EventClassification) {
-  const ArcTracingEvent event(base::JSONReader::Read(kTestEvent));
+  const ArcTracingEvent event(base::JSONReader::ReadDeprecated(kTestEvent));
 
-  ArcTracingEvent event_before(base::JSONReader::Read(kTestEvent));
+  ArcTracingEvent event_before(base::JSONReader::ReadDeprecated(kTestEvent));
   event_before.SetTimestamp(event.GetTimestamp() - event.GetDuration());
   EXPECT_EQ(ArcTracingEvent::Position::kBefore,
             event.ClassifyPositionOf(event_before));
 
-  ArcTracingEvent event_after(base::JSONReader::Read(kTestEvent));
+  ArcTracingEvent event_after(base::JSONReader::ReadDeprecated(kTestEvent));
   event_after.SetTimestamp(event.GetTimestamp() + event.GetDuration());
   EXPECT_EQ(ArcTracingEvent::Position::kAfter,
             event.ClassifyPositionOf(event_after));
 
-  ArcTracingEvent event_inside(base::JSONReader::Read(kTestEvent));
+  ArcTracingEvent event_inside(base::JSONReader::ReadDeprecated(kTestEvent));
   event_inside.SetTimestamp(event.GetTimestamp() + 1);
   event_inside.SetDuration(event.GetDuration() - 2);
   EXPECT_EQ(ArcTracingEvent::Position::kInside,
@@ -226,7 +226,7 @@
   EXPECT_EQ(ArcTracingEvent::Position::kInside,
             event.ClassifyPositionOf(event));
 
-  ArcTracingEvent event_overlap(base::JSONReader::Read(kTestEvent));
+  ArcTracingEvent event_overlap(base::JSONReader::ReadDeprecated(kTestEvent));
   event_overlap.SetTimestamp(event.GetTimestamp() + 1);
   EXPECT_EQ(ArcTracingEvent::Position::kOverlap,
             event.ClassifyPositionOf(event_overlap));
@@ -241,32 +241,33 @@
 }
 
 TEST_F(ArcTracingModelTest, EventAppendChild) {
-  ArcTracingEvent event(base::JSONReader::Read(kTestEvent));
+  ArcTracingEvent event(base::JSONReader::ReadDeprecated(kTestEvent));
 
   // Impossible to append the even that is bigger than target.
   std::unique_ptr<ArcTracingEvent> event_overlap =
-      std::make_unique<ArcTracingEvent>(base::JSONReader::Read(kTestEvent));
+      std::make_unique<ArcTracingEvent>(
+          base::JSONReader::ReadDeprecated(kTestEvent));
   event_overlap->SetTimestamp(event.GetTimestamp() + 1);
   EXPECT_FALSE(event.AppendChild(std::move(event_overlap)));
 
-  std::unique_ptr<ArcTracingEvent> event1 =
-      std::make_unique<ArcTracingEvent>(base::JSONReader::Read(kTestEvent));
+  std::unique_ptr<ArcTracingEvent> event1 = std::make_unique<ArcTracingEvent>(
+      base::JSONReader::ReadDeprecated(kTestEvent));
   event1->SetTimestamp(event.GetTimestamp() + 4);
   event1->SetDuration(2);
   EXPECT_TRUE(event.AppendChild(std::move(event1)));
   EXPECT_EQ(1U, event.children().size());
 
   // Impossible to append the event that is before last child.
-  std::unique_ptr<ArcTracingEvent> event2 =
-      std::make_unique<ArcTracingEvent>(base::JSONReader::Read(kTestEvent));
+  std::unique_ptr<ArcTracingEvent> event2 = std::make_unique<ArcTracingEvent>(
+      base::JSONReader::ReadDeprecated(kTestEvent));
   event2->SetTimestamp(event.GetTimestamp());
   event2->SetDuration(2);
   EXPECT_FALSE(event.AppendChild(std::move(event2)));
   EXPECT_EQ(1U, event.children().size());
 
   // Append child to child
-  std::unique_ptr<ArcTracingEvent> event3 =
-      std::make_unique<ArcTracingEvent>(base::JSONReader::Read(kTestEvent));
+  std::unique_ptr<ArcTracingEvent> event3 = std::make_unique<ArcTracingEvent>(
+      base::JSONReader::ReadDeprecated(kTestEvent));
   event3->SetTimestamp(event.GetTimestamp() + 5);
   event3->SetDuration(1);
   EXPECT_TRUE(event.AppendChild(std::move(event3)));
@@ -274,8 +275,8 @@
   EXPECT_EQ(1U, event.children()[0].get()->children().size());
 
   // Append next immediate child.
-  std::unique_ptr<ArcTracingEvent> event4 =
-      std::make_unique<ArcTracingEvent>(base::JSONReader::Read(kTestEvent));
+  std::unique_ptr<ArcTracingEvent> event4 = std::make_unique<ArcTracingEvent>(
+      base::JSONReader::ReadDeprecated(kTestEvent));
   event4->SetTimestamp(event.GetTimestamp() + 6);
   event4->SetDuration(2);
   EXPECT_TRUE(event.AppendChild(std::move(event4)));
@@ -283,7 +284,7 @@
 }
 
 TEST_F(ArcTracingModelTest, EventMatcher) {
-  const ArcTracingEvent event(base::JSONReader::Read(kTestEvent));
+  const ArcTracingEvent event(base::JSONReader::ReadDeprecated(kTestEvent));
   // Nothing is specified. It matches any event.
   EXPECT_TRUE(ArcTracingEventMatcher().Match(event));
 
diff --git a/chrome/browser/chromeos/boot_times_recorder.cc b/chrome/browser/chromeos/boot_times_recorder.cc
index f8cc4809..993c33b 100644
--- a/chrome/browser/chromeos/boot_times_recorder.cc
+++ b/chrome/browser/chromeos/boot_times_recorder.cc
@@ -183,7 +183,7 @@
   if (source.empty())
     return Stats();
 
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(source);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(source);
   base::DictionaryValue* dictionary;
   if (!value || !value->GetAsDictionary(&dictionary)) {
     LOG(ERROR) << "BootTimesRecorder::Stats::DeserializeFromString(): not a "
diff --git a/chrome/browser/chromeos/customization/customization_document.cc b/chrome/browser/chromeos/customization/customization_document.cc
index 1c60d717..12c0a2d 100644
--- a/chrome/browser/chromeos/customization/customization_document.cc
+++ b/chrome/browser/chromeos/customization/customization_document.cc
@@ -244,8 +244,9 @@
     const std::string& manifest) {
   int error_code = 0;
   std::string error;
-  std::unique_ptr<base::Value> root = base::JSONReader::ReadAndReturnError(
-      manifest, base::JSON_ALLOW_TRAILING_COMMAS, &error_code, &error);
+  std::unique_ptr<base::Value> root =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          manifest, base::JSON_ALLOW_TRAILING_COMMAS, &error_code, &error);
   if (error_code != base::JSONReader::JSON_NO_ERROR)
     LOG(ERROR) << error;
   if (!root) {
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
index 96a1e2a..8e3e09c 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -1464,7 +1464,7 @@
 
     // If the message in JSON format has no command, ignore it
     // but note a reply is required: use std::string().
-    const auto json = base::JSONReader::Read(message.message);
+    const auto json = base::JSONReader::ReadDeprecated(message.message);
     const base::DictionaryValue* dictionary = nullptr;
     std::string command;
     if (!json || !json->GetAsDictionary(&dictionary) ||
@@ -1516,7 +1516,7 @@
       auto event = std::make_unique<extensions::Event>(
           extensions::events::FOR_TEST,
           extensions::api::test::OnMessage::kEventName,
-          base::ListValue::From(base::JSONReader::Read(
+          base::ListValue::From(base::JSONReader::ReadDeprecated(
               R"([{"data": "preloadZip", "lastMessage": false}])")),
           profile());
       extensions::EventRouter::Get(profile())->DispatchEventToExtension(
diff --git a/chrome/browser/chromeos/file_manager/url_util_unittest.cc b/chrome/browser/chromeos/file_manager/url_util_unittest.cc
index 3f80435..5a0463e 100644
--- a/chrome/browser/chromeos/file_manager/url_util_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/url_util_unittest.cc
@@ -25,7 +25,7 @@
   const std::string json = net::UnescapeURLComponent(
       query, net::UnescapeRule::SPACES | net::UnescapeRule::PATH_SEPARATORS |
                  net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS);
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(json);
   return value ? std::move(*value) : base::Value();
 }
 
diff --git a/chrome/browser/chromeos/file_system_provider/operations/get_actions_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/get_actions_unittest.cc
index 7e54232c..dd30b56 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/get_actions_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/get_actions_unittest.cc
@@ -79,8 +79,9 @@
 
   int json_error_code;
   std::string json_error_msg;
-  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-      json, base::JSON_PARSE_RFC, &json_error_code, &json_error_msg);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          json, base::JSON_PARSE_RFC, &json_error_code, &json_error_msg);
   ASSERT_TRUE(value.get()) << json_error_msg;
 
   base::ListValue* value_as_list;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc
index a4dea08..8f51b08 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc
@@ -47,8 +47,9 @@
 
   int json_error_code;
   std::string json_error_msg;
-  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-      json, base::JSON_PARSE_RFC, &json_error_code, &json_error_msg);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          json, base::JSON_PARSE_RFC, &json_error_code, &json_error_msg);
   ASSERT_TRUE(value.get()) << json_error_msg;
 
   base::ListValue* value_as_list;
diff --git a/chrome/browser/chromeos/file_system_provider/operations/read_directory_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/read_directory_unittest.cc
index 6e100f6..df72962 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/read_directory_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/read_directory_unittest.cc
@@ -90,8 +90,9 @@
 
   int json_error_code;
   std::string json_error_msg;
-  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-      json, base::JSON_PARSE_RFC, &json_error_code, &json_error_msg);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          json, base::JSON_PARSE_RFC, &json_error_code, &json_error_msg);
   ASSERT_TRUE(value.get()) << json_error_msg;
 
   base::ListValue* value_as_list;
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_extensions_external_loader.cc b/chrome/browser/chromeos/login/demo_mode/demo_extensions_external_loader.cc
index 0758dc35..17011169 100644
--- a/chrome/browser/chromeos/login/demo_mode/demo_extensions_external_loader.cc
+++ b/chrome/browser/chromeos/login/demo_mode/demo_extensions_external_loader.cc
@@ -47,7 +47,8 @@
     return base::nullopt;
   }
 
-  std::unique_ptr<base::Value> prefs_value = base::JSONReader::Read(prefs_str);
+  std::unique_ptr<base::Value> prefs_value =
+      base::JSONReader::ReadDeprecated(prefs_str);
   if (!prefs_value) {
     LOG(ERROR) << "Unable to parse demo extensions prefs.";
     return base::nullopt;
diff --git a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
index 9d67e11..d967ae5 100644
--- a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
+++ b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
@@ -387,7 +387,7 @@
   // which does not set any fields.
   void CheckPossibleConfiguration(const std::string& configuration) {
     std::unique_ptr<base::ListValue> options =
-        base::ListValue::From(base::JSONReader::Read(
+        base::ListValue::From(base::JSONReader::ReadDeprecated(
             configuration,
             base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS));
     base::DictionaryValue custom_option;
diff --git a/chrome/browser/chromeos/login/helper.cc b/chrome/browser/chromeos/login/helper.cc
index 0f55a0ee..2cc5531b 100644
--- a/chrome/browser/chromeos/login/helper.cc
+++ b/chrome/browser/chromeos/login/helper.cc
@@ -127,8 +127,9 @@
     const base::Closure& success_callback,
     const network_handler::ErrorCallback& error_callback) const {
   std::string error;
-  std::unique_ptr<base::Value> root = base::JSONReader::ReadAndReturnError(
-      onc_spec, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error);
+  std::unique_ptr<base::Value> root =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          onc_spec, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error);
 
   base::DictionaryValue* toplevel_onc = nullptr;
   if (!root || !root->GetAsDictionary(&toplevel_onc)) {
diff --git a/chrome/browser/chromeos/login/oobe_configuration.cc b/chrome/browser/chromeos/login/oobe_configuration.cc
index 912e8a6..b16f17bf 100644
--- a/chrome/browser/chromeos/login/oobe_configuration.cc
+++ b/chrome/browser/chromeos/login/oobe_configuration.cc
@@ -85,7 +85,7 @@
 
   int error_code, row, col;
   std::string error_message;
-  auto value = base::JSONReader::ReadAndReturnError(
+  auto value = base::JSONReader::ReadAndReturnErrorDeprecated(
       configuration, base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS,
       &error_code, &error_message, &row, &col);
   if (!value) {
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.cc b/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.cc
index 441d7a6..3d5c804c 100644
--- a/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.cc
+++ b/chrome/browser/chromeos/login/screens/recommend_apps/recommend_apps_fetcher.cc
@@ -530,8 +530,8 @@
   int error_code;
   std::string error_msg;
   std::unique_ptr<base::Value> json_value =
-      base::JSONReader::ReadAndReturnError(response, base::JSON_PARSE_RFC,
-                                           &error_code, &error_msg);
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          response, base::JSON_PARSE_RFC, &error_code, &error_msg);
 
   if (!json_value || (!json_value->is_list() && !json_value->is_dict())) {
     LOG(ERROR) << "Error parsing response JSON: " << error_msg;
diff --git a/chrome/browser/chromeos/login/signin/device_id_browsertest.cc b/chrome/browser/chromeos/login/signin/device_id_browsertest.cc
index 7b7e23d..2207f73 100644
--- a/chrome/browser/chromeos/login/signin/device_id_browsertest.cc
+++ b/chrome/browser/chromeos/login/signin/device_id_browsertest.cc
@@ -153,7 +153,8 @@
     if (!base::ReadFileToString(GetRefreshTokenToDeviceIdMapFilePath(),
                                 &file_contents))
       return;
-    std::unique_ptr<base::Value> value(base::JSONReader::Read(file_contents));
+    std::unique_ptr<base::Value> value(
+        base::JSONReader::ReadDeprecated(file_contents));
     base::DictionaryValue* dictionary;
     EXPECT_TRUE(value->GetAsDictionary(&dictionary));
     FakeGaia::RefreshTokenToDeviceIdMap map;
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_util_unittest.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_util_unittest.cc
index 867cf7d..2eba44f 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_util_unittest.cc
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_util_unittest.cc
@@ -68,7 +68,7 @@
   EXPECT_FALSE(IsPluginVmAllowedForProfile(testing_profile_.get()));
 
   testing_profile_->GetPrefs()->Set(plugin_vm::prefs::kPluginVmImage,
-                                    *base::JSONReader::Read(R"(
+                                    *base::JSONReader::ReadDeprecated(R"(
     {
         "url": "https://example.com/plugin_vm_image",
         "hash": "842841a4c75a55ad050d686f4ea5f77e83ae059877fe9b6946aa63d3d057ed32"
diff --git a/chrome/browser/chromeos/policy/component_active_directory_policy_service.cc b/chrome/browser/chromeos/policy/component_active_directory_policy_service.cc
index 206cfb88c..3966dc9 100644
--- a/chrome/browser/chromeos/policy/component_active_directory_policy_service.cc
+++ b/chrome/browser/chromeos/policy/component_active_directory_policy_service.cc
@@ -74,9 +74,10 @@
 std::unique_ptr<base::DictionaryValue> ParseJsonToDict(
     const std::string& json) {
   std::string json_reader_error_message;
-  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-      json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr /* error_code_out */,
-      &json_reader_error_message);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          json, base::JSON_ALLOW_TRAILING_COMMAS, nullptr /* error_code_out */,
+          &json_reader_error_message);
   if (!value) {
     LOG(ERROR) << "Could not parse policy value as JSON: "
                << json_reader_error_message;
diff --git a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos_unittest.cc b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos_unittest.cc
index 7bcf82e..deb6d08 100644
--- a/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/configuration_policy_handler_chromeos_unittest.cc
@@ -344,10 +344,11 @@
 
 TEST_F(LoginScreenPowerManagementPolicyHandlerTest, ValidPolicy) {
   PolicyMap policy_map;
-  policy_map.Set(key::kDeviceLoginScreenPowerManagement, POLICY_LEVEL_MANDATORY,
-                 POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
-                 base::JSONReader::Read(kLoginScreenPowerManagementPolicy),
-                 nullptr);
+  policy_map.Set(
+      key::kDeviceLoginScreenPowerManagement, POLICY_LEVEL_MANDATORY,
+      POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
+      base::JSONReader::ReadDeprecated(kLoginScreenPowerManagementPolicy),
+      nullptr);
   LoginScreenPowerManagementPolicyHandler handler(chrome_schema_);
   PolicyErrorMap errors;
   EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
index 96f82ce..67a3f564 100644
--- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -1857,7 +1857,8 @@
   ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents_,
                                                      get_locale_list,
                                                      &json));
-  std::unique_ptr<base::Value> value_ptr = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value_ptr =
+      base::JSONReader::ReadDeprecated(json);
   const base::ListValue* locales = NULL;
   ASSERT_TRUE(value_ptr);
   ASSERT_TRUE(value_ptr->GetAsList(&locales));
@@ -1915,7 +1916,7 @@
   ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents_,
                                                      get_locale_list,
                                                      &json));
-  value_ptr = base::JSONReader::Read(json);
+  value_ptr = base::JSONReader::ReadDeprecated(json);
   locales = NULL;
   ASSERT_TRUE(value_ptr);
   ASSERT_TRUE(value_ptr->GetAsList(&locales));
@@ -1998,7 +1999,7 @@
           account_id_1_.Serialize().c_str()),
       &json));
   LOG(ERROR) << json;
-  value_ptr = base::JSONReader::Read(json);
+  value_ptr = base::JSONReader::ReadDeprecated(json);
   const base::DictionaryValue* state = NULL;
   ASSERT_TRUE(value_ptr);
   ASSERT_TRUE(value_ptr->GetAsDictionary(&state));
@@ -2741,7 +2742,8 @@
       "  observer.observe(screenElement, options);"
       "}",
       &json));
-  std::unique_ptr<base::Value> value_ptr = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value_ptr =
+      base::JSONReader::ReadDeprecated(json);
   const base::DictionaryValue* status = NULL;
   ASSERT_TRUE(value_ptr);
   ASSERT_TRUE(value_ptr->GetAsDictionary(&status));
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
index 0484335..3ad4c033 100644
--- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
@@ -1188,8 +1188,9 @@
     const std::string& policy_name,
     std::string* error) {
   std::string json_error;
-  std::unique_ptr<base::Value> root = base::JSONReader::ReadAndReturnError(
-      json_string, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &json_error);
+  std::unique_ptr<base::Value> root =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          json_string, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &json_error);
   if (!root) {
     *error = "Invalid JSON string: " + json_error;
     return nullptr;
diff --git a/chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.cc b/chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.cc
index 45b70b4..71cc68e 100644
--- a/chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.cc
@@ -249,7 +249,8 @@
     std::unique_ptr<std::string> response_body) {
   ice_config_loader_.reset();
   if (response_body) {
-    std::unique_ptr<base::Value> value = base::JSONReader::Read(*response_body);
+    std::unique_ptr<base::Value> value =
+        base::JSONReader::ReadDeprecated(*response_body);
     if (!value || !value->is_dict()) {
       ice_success_callback_.Reset();
       std::move(error_callback_)
@@ -317,7 +318,8 @@
 }
 
 void CRDHostDelegate::PostMessageFromNativeHost(const std::string& message) {
-  std::unique_ptr<base::Value> message_value = base::JSONReader::Read(message);
+  std::unique_ptr<base::Value> message_value =
+      base::JSONReader::ReadDeprecated(message);
   if (!message_value->is_dict()) {
     OnProtocolBroken("Message is not a dictionary");
     return;
diff --git a/chrome/browser/chromeos/printing/external_printers.cc b/chrome/browser/chromeos/printing/external_printers.cc
index a2ba081b..6c80bec 100644
--- a/chrome/browser/chromeos/printing/external_printers.cc
+++ b/chrome/browser/chromeos/printing/external_printers.cc
@@ -39,9 +39,10 @@
 
   // This could be really slow.
   base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
-  std::unique_ptr<base::Value> json_blob = base::JSONReader::ReadAndReturnError(
-      *data, base::JSONParserOptions::JSON_PARSE_RFC, &error_code,
-      nullptr /* error_msg_out */, &error_line);
+  std::unique_ptr<base::Value> json_blob =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          *data, base::JSONParserOptions::JSON_PARSE_RFC, &error_code,
+          nullptr /* error_msg_out */, &error_line);
   // It's not valid JSON.  Give up.
   if (!json_blob || !json_blob->is_list()) {
     LOG(WARNING) << "Failed to parse printers policy (" << error_code
diff --git a/chrome/browser/chromeos/printing/synced_printers_manager.cc b/chrome/browser/chromeos/printing/synced_printers_manager.cc
index 3fffea575..ee03322 100644
--- a/chrome/browser/chromeos/printing/synced_printers_manager.cc
+++ b/chrome/browser/chromeos/printing/synced_printers_manager.cc
@@ -254,7 +254,7 @@
       }
 
       std::unique_ptr<base::DictionaryValue> printer_dictionary =
-          base::DictionaryValue::From(base::JSONReader::Read(
+          base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
               printer_json, base::JSON_ALLOW_TRAILING_COMMAS));
 
       if (!printer_dictionary) {
diff --git a/chrome/browser/component_updater/sth_set_component_installer.cc b/chrome/browser/component_updater/sth_set_component_installer.cc
index 86a2c4d..1b73c03 100644
--- a/chrome/browser/component_updater/sth_set_component_installer.cc
+++ b/chrome/browser/component_updater/sth_set_component_installer.cc
@@ -100,8 +100,8 @@
     int error_code = 0;
     std::string error_message;
     std::unique_ptr<base::Value> parsed_json =
-        base::JSONReader::ReadAndReturnError(json_sth, base::JSON_PARSE_RFC,
-                                             &error_code, &error_message);
+        base::JSONReader::ReadAndReturnErrorDeprecated(
+            json_sth, base::JSON_PARSE_RFC, &error_code, &error_message);
 
     if (!parsed_json || error_code != base::JSONReader::JSON_NO_ERROR) {
       DVLOG(1) << "STH loading failed: " << error_message << " for log: "
diff --git a/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc b/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc
index c08eae5..64714ab 100644
--- a/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc
+++ b/chrome/browser/component_updater/supervised_user_whitelist_installer_unittest.cc
@@ -383,8 +383,9 @@
 
   // The actual file contents don't have to be equal, but the parsed values
   // should be.
-  EXPECT_TRUE(base::JSONReader::Read(kWhitelistContents)
-                  ->Equals(base::JSONReader::Read(whitelist_contents).get()))
+  EXPECT_TRUE(
+      base::JSONReader::ReadDeprecated(kWhitelistContents)
+          ->Equals(base::JSONReader::ReadDeprecated(whitelist_contents).get()))
       << kWhitelistContents << " vs. " << whitelist_contents;
 
   EXPECT_EQ(JsonToString(pref_),
diff --git a/chrome/browser/component_updater/sw_reporter_installer_win_unittest.cc b/chrome/browser/component_updater/sw_reporter_installer_win_unittest.cc
index 208e99b3..8ec5409 100644
--- a/chrome/browser/component_updater/sw_reporter_installer_win_unittest.cc
+++ b/chrome/browser/component_updater/sw_reporter_installer_win_unittest.cc
@@ -284,9 +284,9 @@
       "    \"prompt\": false"
       "  }"
       "]}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   // The SwReporter should be launched once with the given arguments.
   EXPECT_EQ(default_version_, extracted_invocations_.version());
@@ -340,9 +340,9 @@
       "  }"
 
       "]}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   // The SwReporter should be launched four times with the given arguments.
   EXPECT_EQ(default_version_, extracted_invocations_.version());
@@ -380,9 +380,9 @@
       "    \"arguments\": [\"random argument\"]"
       "  }"
       "]}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   ExpectLaunchError();
 }
@@ -397,9 +397,9 @@
       "    \"arguments\": [\"random argument\"]"
       "  }"
       "]}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   ExpectInvocationFromManifest("", L"random argument");
 }
@@ -412,9 +412,9 @@
       "  {"
       "  }"
       "]}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   ExpectLaunchError();
 }
@@ -429,9 +429,9 @@
       "    \"arguments\": []"
       "  }"
       "]}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   ExpectInvocationFromManifest("", L"");
 }
@@ -446,9 +446,9 @@
       "    \"arguments\": [\"\"]"
       "  }"
       "]}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   ExpectInvocationFromManifest("", L"");
 }
@@ -462,9 +462,9 @@
       "    \"suffix\": \"TestSuffix\""
       "  }"
       "]}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   ExpectLaunchError();
 }
@@ -479,9 +479,9 @@
       "    \"arguments\": []"
       "  }"
       "]}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   ExpectInvocationFromManifest("TestSuffix", L"");
 }
@@ -496,9 +496,9 @@
       "    \"arguments\": [\"\"]"
       "  }"
       "]}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   ExpectInvocationFromManifest("TestSuffix", L"");
 }
@@ -507,9 +507,9 @@
   SwReporterInstallerPolicy policy(on_component_ready_callback_);
 
   static constexpr char kTestManifest[] = "{}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
   ExpectDefaultInvocation();
 }
 
@@ -517,9 +517,9 @@
   SwReporterInstallerPolicy policy(on_component_ready_callback_);
 
   static constexpr char kTestManifest[] = "{\"launch_params\": []}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
   ExpectDefaultInvocation();
 }
 
@@ -533,9 +533,9 @@
       "    \"suffix\": \"invalid whitespace characters\""
       "  }"
       "]}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   // The SwReporter should not be launched, and an error should be logged.
   EXPECT_TRUE(extracted_invocations_.container().empty());
@@ -558,7 +558,7 @@
       base::StringPrintf(kTestManifest, suffix_too_long.c_str());
   policy.ComponentReady(
       default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(manifest)));
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(manifest)));
 
   // The SwReporter should not be launched, and an error should be logged.
   EXPECT_TRUE(extracted_invocations_.container().empty());
@@ -577,9 +577,9 @@
       "    \"suffix\": \"TestSuffix\""
       "  }"
       "]}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   // The SwReporter should not be launched, and an error should be logged.
   EXPECT_TRUE(extracted_invocations_.container().empty());
@@ -599,9 +599,9 @@
       "    \"suffix\": \"TestSuffix\""
       "  }"
       "}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   // The SwReporter should not be launched, and an error should be logged.
   EXPECT_TRUE(extracted_invocations_.container().empty());
@@ -620,9 +620,9 @@
       "    \"suffix\": [\"TestSuffix\"]"
       "  }"
       "]}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   // The SwReporter should not be launched, and an error should be logged.
   EXPECT_TRUE(extracted_invocations_.container().empty());
@@ -642,9 +642,9 @@
       "    \"prompt\": 1"
       "  }"
       "]}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   // The SwReporter should not be launched, and an error should be logged.
   EXPECT_TRUE(extracted_invocations_.container().empty());
@@ -656,9 +656,9 @@
   SwReporterInstallerPolicy policy(on_component_ready_callback_);
 
   static constexpr char kTestManifest[] = "{\"launch_params\": 0}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   // The SwReporter should not be launched, and an error should be logged.
   EXPECT_TRUE(extracted_invocations_.container().empty());
@@ -670,9 +670,9 @@
   SwReporterInstallerPolicy policy(on_component_ready_callback_);
 
   static constexpr char kTestManifest[] = "{\"launch_params\": {}}";
-  policy.ComponentReady(
-      default_version_, default_path_,
-      base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+  policy.ComponentReady(default_version_, default_path_,
+                        base::DictionaryValue::From(
+                            base::JSONReader::ReadDeprecated(kTestManifest)));
 
   // The SwReporter should not be launched, and an error should be logged.
   EXPECT_TRUE(extracted_invocations_.container().empty());
diff --git a/chrome/browser/content_settings/host_content_settings_map_unittest.cc b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
index 95c2688..dd220389 100644
--- a/chrome/browser/content_settings/host_content_settings_map_unittest.cc
+++ b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
@@ -1147,13 +1147,13 @@
 TEST_F(HostContentSettingsMapTest, CanonicalizeExceptionsUnicodeAndPunycode) {
   TestingProfile profile;
 
-  std::unique_ptr<base::Value> value =
-      base::JSONReader::Read("{\"[*.]\\xC4\\x87ira.com,*\":{\"setting\":1}}");
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
+      "{\"[*.]\\xC4\\x87ira.com,*\":{\"setting\":1}}");
   profile.GetPrefs()->Set(GetPrefName(CONTENT_SETTINGS_TYPE_COOKIES), *value);
 
   // Set punycode equivalent, with different setting.
-  std::unique_ptr<base::Value> puny_value =
-      base::JSONReader::Read("{\"[*.]xn--ira-ppa.com,*\":{\"setting\":2}}");
+  std::unique_ptr<base::Value> puny_value = base::JSONReader::ReadDeprecated(
+      "{\"[*.]xn--ira-ppa.com,*\":{\"setting\":2}}");
   profile.GetPrefs()->Set(GetPrefName(CONTENT_SETTINGS_TYPE_COOKIES),
                           *puny_value);
 
@@ -1460,8 +1460,8 @@
   profile.SetGuestSession(true);
 
   // Set a pref manually in the guest profile.
-  std::unique_ptr<base::Value> value =
-      base::JSONReader::Read("{\"[*.]\\xC4\\x87ira.com,*\":{\"setting\":1}}");
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
+      "{\"[*.]\\xC4\\x87ira.com,*\":{\"setting\":1}}");
   profile.GetPrefs()->Set(GetPrefName(CONTENT_SETTINGS_TYPE_COOKIES), *value);
 
   // Test that during construction all the prefs get cleared.
@@ -1884,7 +1884,7 @@
   }
   TestingProfile profile;
   // Set a website-specific Flash preference and a pattern exception.
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       "{\"https://urlwithflashchanged.com:443,*\":{\"setting\":1}, "
       "\"[*.]patternurl.com:443,*\":{\"setting\":1}}");
   profile.GetPrefs()->Set(GetPrefName(CONTENT_SETTINGS_TYPE_PLUGINS), *value);
@@ -1915,10 +1915,10 @@
   TestingProfile profile;
   // Set a website-specific Flash preference and another preference indicating
   // that the Flash setting has changed for a different website.
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
       "{\"https://unmigratedurl.com:443,*\":{\"setting\":1}}");
   profile.GetPrefs()->Set(GetPrefName(CONTENT_SETTINGS_TYPE_PLUGINS), *value);
-  value = base::JSONReader::Read(
+  value = base::JSONReader::ReadDeprecated(
       "{\"https://"
       "example.com:443,*\":{\"setting\":{\"flashPreviouslyChanged\":true}}}");
   profile.GetPrefs()->Set(GetPrefName(CONTENT_SETTINGS_TYPE_PLUGINS_DATA),
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber_unittest.cc b/chrome/browser/data_use_measurement/chrome_data_use_ascriber_unittest.cc
index 59d33283..68a46c1 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber_unittest.cc
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber_unittest.cc
@@ -84,9 +84,9 @@
         request.get(),
         is_main_frame ? content::RESOURCE_TYPE_MAIN_FRAME
                       : content::RESOURCE_TYPE_SCRIPT,
-        /*resource_context*/nullptr, render_process_id,
+        /*resource_context*/ nullptr, render_process_id,
         /*render_view_id=*/-1, render_frame_id, is_main_frame,
-        /*allow_download=*/false,
+        content::ResourceInterceptPolicy::kAllowNone,
         /*is_async=*/true, content::PREVIEWS_OFF,
         /*navigation_ui_data*/ nullptr);
     return request;
diff --git a/chrome/browser/devtools/chrome_devtools_session.cc b/chrome/browser/devtools/chrome_devtools_session.cc
index 457f578..80388aa 100644
--- a/chrome/browser/devtools/chrome_devtools_session.cc
+++ b/chrome/browser/devtools/chrome_devtools_session.cc
@@ -48,7 +48,8 @@
     int call_id,
     std::unique_ptr<protocol::Serializable> message) {
   pending_commands_.erase(call_id);
-  client_->DispatchProtocolMessage(agent_host_, message->serialize());
+  bool binary = client_->UsesBinaryProtocol();
+  client_->DispatchProtocolMessage(agent_host_, message->serialize(binary));
 }
 
 void ChromeDevToolsSession::HandleCommand(
@@ -63,7 +64,8 @@
   int call_id;
   std::string unused;
   std::unique_ptr<protocol::DictionaryValue> value =
-      protocol::DictionaryValue::cast(protocol::StringUtil::parseJSON(message));
+      protocol::DictionaryValue::cast(protocol::StringUtil::parseMessage(
+          message, client_->UsesBinaryProtocol()));
   if (!dispatcher_->parseCommand(value.get(), &call_id, &unused))
     return;
   pending_commands_[call_id] = std::move(callback);
@@ -80,7 +82,8 @@
 
 void ChromeDevToolsSession::sendProtocolNotification(
     std::unique_ptr<protocol::Serializable> message) {
-  client_->DispatchProtocolMessage(agent_host_, message->serialize());
+  bool binary = client_->UsesBinaryProtocol();
+  client_->DispatchProtocolMessage(agent_host_, message->serialize(binary));
 }
 
 void ChromeDevToolsSession::flushProtocolNotifications() {}
diff --git a/chrome/browser/devtools/device/devtools_device_discovery.cc b/chrome/browser/devtools/device/devtools_device_discovery.cc
index a9b2b11..adc8c75 100644
--- a/chrome/browser/devtools/device/devtools_device_discovery.cc
+++ b/chrome/browser/devtools/device/devtools_device_discovery.cc
@@ -459,7 +459,8 @@
   if (result < 0)
     return;
   // Parse version, append to package name if available,
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(response);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(response);
   base::DictionaryValue* dict;
   if (value && value->GetAsDictionary(&dict)) {
     std::string browser_name;
@@ -490,7 +491,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (result < 0)
     return;
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(response);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(response);
   base::ListValue* list_value;
   if (value && value->GetAsList(&list_value)) {
     for (const auto& page_value : *list_value) {
diff --git a/chrome/browser/devtools/device/port_forwarding_controller.cc b/chrome/browser/devtools/device/port_forwarding_controller.cc
index 6950f17..e12f2221 100644
--- a/chrome/browser/devtools/device/port_forwarding_controller.cc
+++ b/chrome/browser/devtools/device/port_forwarding_controller.cc
@@ -69,7 +69,7 @@
 static bool ParseNotification(const std::string& json,
                               std::string* method,
                               std::unique_ptr<base::DictionaryValue>* params) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(json);
   if (!value || !value->is_dict())
     return false;
 
@@ -90,7 +90,7 @@
 static bool ParseResponse(const std::string& json,
                           int* command_id,
                           int* error_code) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(json);
   if (!value || !value->is_dict())
     return false;
 
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index 8bc69c90..2f3c39ba 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -571,7 +571,8 @@
   base::ListValue* params = &empty_params;
 
   base::DictionaryValue* dict = NULL;
-  std::unique_ptr<base::Value> parsed_message = base::JSONReader::Read(message);
+  std::unique_ptr<base::Value> parsed_message =
+      base::JSONReader::ReadDeprecated(message);
   if (!parsed_message ||
       !parsed_message->GetAsDictionary(&dict) ||
       !dict->GetString(kFrontendHostMethod, &method) ||
@@ -806,7 +807,7 @@
     return;
   std::vector<std::string> excluded_folders;
   std::unique_ptr<base::Value> parsed_excluded_folders =
-      base::JSONReader::Read(excluded_folders_message);
+      base::JSONReader::ReadDeprecated(excluded_folders_message);
   if (parsed_excluded_folders && parsed_excluded_folders->is_list()) {
     const std::vector<base::Value>& folder_paths =
         parsed_excluded_folders->GetList();
@@ -891,7 +892,7 @@
     const std::string& network_discovery_config) {
   base::DictionaryValue* port_forwarding_dict = nullptr;
   std::unique_ptr<base::Value> parsed_port_forwarding =
-      base::JSONReader::Read(port_forwarding_config);
+      base::JSONReader::ReadDeprecated(port_forwarding_config);
   if (!parsed_port_forwarding ||
       !parsed_port_forwarding->GetAsDictionary(&port_forwarding_dict)) {
     return;
@@ -899,7 +900,7 @@
 
   base::ListValue* network_list = nullptr;
   std::unique_ptr<base::Value> parsed_network =
-      base::JSONReader::Read(network_discovery_config);
+      base::JSONReader::ReadDeprecated(network_discovery_config);
   if (!parsed_network || !parsed_network->GetAsList(&network_list))
     return;
 
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index d81cc18..659d6c3 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -116,7 +116,7 @@
 
 void SetPreferencesFromJson(Profile* profile, const std::string& json) {
   base::DictionaryValue* dict = nullptr;
-  std::unique_ptr<base::Value> parsed = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> parsed = base::JSONReader::ReadDeprecated(json);
   if (!parsed || !parsed->GetAsDictionary(&dict))
     return;
   DictionaryPrefUpdate update(profile->GetPrefs(), prefs::kDevToolsPreferences);
@@ -266,7 +266,8 @@
 
 void DevToolsEventForwarder::SetWhitelistedShortcuts(
     const std::string& message) {
-  std::unique_ptr<base::Value> parsed_message = base::JSONReader::Read(message);
+  std::unique_ptr<base::Value> parsed_message =
+      base::JSONReader::ReadDeprecated(message);
   base::ListValue* shortcut_list;
   if (!parsed_message || !parsed_message->GetAsList(&shortcut_list))
       return;
@@ -1449,7 +1450,8 @@
 }
 
 void DevToolsWindow::ShowCertificateViewer(const std::string& cert_chain) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(cert_chain);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(cert_chain);
   if (!value || value->type() != base::Value::Type::LIST) {
     NOTREACHED();
     return;
diff --git a/chrome/browser/domain_reliability/browsertest.cc b/chrome/browser/domain_reliability/browsertest.cc
index 176e50f..521498fe 100644
--- a/chrome/browser/domain_reliability/browsertest.cc
+++ b/chrome/browser/domain_reliability/browsertest.cc
@@ -156,7 +156,7 @@
   EXPECT_EQ(1, request_count);
   EXPECT_NE("", last_request_content);
 
-  auto body = base::JSONReader::Read(last_request_content);
+  auto body = base::JSONReader::ReadDeprecated(last_request_content);
   ASSERT_TRUE(body);
 
   const base::DictionaryValue* dict;
diff --git a/chrome/browser/download/download_service_factory.h b/chrome/browser/download/download_service_factory.h
index 2c93700..ef49d79 100644
--- a/chrome/browser/download/download_service_factory.h
+++ b/chrome/browser/download/download_service_factory.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_SERVICE_FACTORY_H_
 
 #include "base/macros.h"
-#include "chrome/browser/download/download_service_factory.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
 namespace base {
diff --git a/chrome/browser/extensions/activity_log/counting_policy.cc b/chrome/browser/extensions/activity_log/counting_policy.cc
index 0ead49c..17e5412 100644
--- a/chrome/browser/extensions/activity_log/counting_policy.cc
+++ b/chrome/browser/extensions/activity_log/counting_policy.cc
@@ -497,7 +497,7 @@
 
     if (query.ColumnType(4) != sql::COLUMN_TYPE_NULL) {
       std::unique_ptr<base::Value> parsed_value =
-          base::JSONReader::Read(query.ColumnString(4));
+          base::JSONReader::ReadDeprecated(query.ColumnString(4));
       if (parsed_value && parsed_value->is_list()) {
         action->set_args(base::WrapUnique(
             static_cast<base::ListValue*>(parsed_value.release())));
@@ -510,7 +510,7 @@
 
     if (query.ColumnType(8) != sql::COLUMN_TYPE_NULL) {
       std::unique_ptr<base::Value> parsed_value =
-          base::JSONReader::Read(query.ColumnString(8));
+          base::JSONReader::ReadDeprecated(query.ColumnString(8));
       if (parsed_value && parsed_value->is_dict()) {
         action->set_other(base::WrapUnique(
             static_cast<base::DictionaryValue*>(parsed_value.release())));
diff --git a/chrome/browser/extensions/activity_log/fullstream_ui_policy.cc b/chrome/browser/extensions/activity_log/fullstream_ui_policy.cc
index eaa4d2b..4b833483 100644
--- a/chrome/browser/extensions/activity_log/fullstream_ui_policy.cc
+++ b/chrome/browser/extensions/activity_log/fullstream_ui_policy.cc
@@ -194,7 +194,7 @@
 
     if (query.ColumnType(4) != sql::COLUMN_TYPE_NULL) {
       std::unique_ptr<base::Value> parsed_value =
-          base::JSONReader::Read(query.ColumnString(4));
+          base::JSONReader::ReadDeprecated(query.ColumnString(4));
       if (parsed_value && parsed_value->is_list()) {
         action->set_args(base::WrapUnique(
             static_cast<base::ListValue*>(parsed_value.release())));
@@ -207,7 +207,7 @@
 
     if (query.ColumnType(8) != sql::COLUMN_TYPE_NULL) {
       std::unique_ptr<base::Value> parsed_value =
-          base::JSONReader::Read(query.ColumnString(8));
+          base::JSONReader::ReadDeprecated(query.ColumnString(8));
       if (parsed_value && parsed_value->is_dict()) {
         action->set_other(base::WrapUnique(
             static_cast<base::DictionaryValue*>(parsed_value.release())));
diff --git a/chrome/browser/extensions/api/debugger/debugger_api.cc b/chrome/browser/extensions/api/debugger/debugger_api.cc
index 257b977..e6c793b 100644
--- a/chrome/browser/extensions/api/debugger/debugger_api.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_api.cc
@@ -320,8 +320,8 @@
   if (!EventRouter::Get(profile_))
     return;
 
-  std::unique_ptr<base::Value> result =
-      base::JSONReader::Read(message, base::JSON_REPLACE_INVALID_CHARACTERS);
+  std::unique_ptr<base::Value> result = base::JSONReader::ReadDeprecated(
+      message, base::JSON_REPLACE_INVALID_CHARACTERS);
   if (!result || !result->is_dict()) {
     LOG(ERROR) << "Tried to send invalid message to extension: " << message;
     return;
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
index 245bb2e..c8f2b9b7d 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
@@ -542,9 +542,11 @@
       "  \"priority\": 300                                               \n"
       "}                                                                 ";
 
-  std::unique_ptr<base::Value> value1 = base::JSONReader::Read(kRule1);
+  std::unique_ptr<base::Value> value1 =
+      base::JSONReader::ReadDeprecated(kRule1);
   ASSERT_TRUE(value1.get());
-  std::unique_ptr<base::Value> value2 = base::JSONReader::Read(kRule2);
+  std::unique_ptr<base::Value> value2 =
+      base::JSONReader::ReadDeprecated(kRule2);
   ASSERT_TRUE(value2.get());
 
   std::vector<const api::events::Rule*> rules;
@@ -712,7 +714,7 @@
       "  \"priority\": 200                                                \n"
       "}                                                                  ";
 
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(kRule);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(kRule);
   ASSERT_TRUE(value);
 
   api::events::Rule rule;
@@ -745,7 +747,8 @@
       "  \"instanceType\": \"declarativeWebRequest.RedirectRequest\",\n"
       "  \"redirectUrl\": \"http://bar.com\"                         \n"
       "}                                                             ";
-  std::unique_ptr<base::Value> action_value = base::JSONReader::Read(kAction);
+  std::unique_ptr<base::Value> action_value =
+      base::JSONReader::ReadDeprecated(kAction);
   ASSERT_TRUE(action_value);
 
   WebRequestActionSet::Values actions;
@@ -801,7 +804,7 @@
       "  \"priority\": 200                                               \n"
       "}                                                                 ";
 
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(kRule);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(kRule);
   ASSERT_TRUE(value.get());
 
   std::vector<const api::events::Rule*> rules;
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
index 0d12889..8519b71 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -141,7 +141,7 @@
         : profile_(profile),
           event_name_(event_name),
           json_args_(json_args),
-          args_(base::JSONReader::Read(json_args).release()),
+          args_(base::JSONReader::ReadDeprecated(json_args).release()),
           caught_(caught) {}
 
     const base::Time& caught() { return caught_; }
diff --git a/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper_unittest.cc b/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper_unittest.cc
index 06904bb..9be986f 100644
--- a/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper_unittest.cc
+++ b/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper_unittest.cc
@@ -93,7 +93,7 @@
 
   // Extension list will be a empty list by default.
   expected_extension_list = "[]";
-  report = base::DictionaryValue::From(base::JSONReader::Read(
+  report = base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
       R"({"browserReport": {"chromeUserProfileReport":[{}]}})"));
   ASSERT_TRUE(report);
   request = GenerateChromeDesktopReportRequest(*report, &profile_);
@@ -104,7 +104,7 @@
 
   // Extension list will be copied from the |report|.
   expected_extension_list = R"([{"id":"1\\\""}])";
-  report = base::DictionaryValue::From(base::JSONReader::Read(
+  report = base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
       R"({"browserReport":
            {"chromeUserProfileReport":
              [
@@ -126,7 +126,7 @@
   std::string expected_plugin_list;
 
   expected_plugin_list = R"([{"id":"1\\\""}])";
-  report = base::DictionaryValue::From(base::JSONReader::Read(
+  report = base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
       R"({"browserReport":
            {"chromeUserProfileReport":
              [
@@ -147,7 +147,7 @@
   std::string expected_signed_in_user;
 
   expected_signed_in_user = R"({"email":"a\\@example.com"})";
-  report = base::DictionaryValue::From(base::JSONReader::Read(
+  report = base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
       R"({"browserReport":
            {"chromeUserProfileReport":
              [
@@ -175,8 +175,8 @@
 
   // Profile ID will be merged into the first item of
   // |chrome_user_profile_reports|
-  std::unique_ptr<base::DictionaryValue> report =
-      base::DictionaryValue::From(base::JSONReader::Read(R"({"browserReport":
+  std::unique_ptr<base::DictionaryValue> report = base::DictionaryValue::From(
+      base::JSONReader::ReadDeprecated(R"({"browserReport":
                                   {"chromeUserProfileReport":[
                                     {"extensionData": [{"id":"1"}]}
                                   ]}
@@ -191,13 +191,13 @@
 TEST_F(ChromeDesktopReportRequestGeneratorTest, InvalidInput) {
   // |request| will not be generated if the type of input is invalid.
   std::unique_ptr<base::DictionaryValue> report;
-  report = base::DictionaryValue::From(base::JSONReader::Read(
+  report = base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
       R"({"browserReport":
          {"chromeUserProfileReport":[{"extensionData":{}}]}})"));
   ASSERT_TRUE(report);
   EXPECT_FALSE(GenerateChromeDesktopReportRequest(*report, &profile_));
 
-  report = base::DictionaryValue::From(base::JSONReader::Read(
+  report = base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
       R"({"browserReport":
          {"chromeUserProfileReport":[{"chromeSignInUser":""}]}})"));
   ASSERT_TRUE(report);
@@ -209,8 +209,8 @@
                                   true);
 
   std::unique_ptr<base::DictionaryValue> report;
-  report =
-      base::DictionaryValue::From(base::JSONReader::Read(R"({"browserReport":
+  report = base::DictionaryValue::From(
+      base::JSONReader::ReadDeprecated(R"({"browserReport":
                                   {"chromeUserProfileReport":[{
                                     "safeBrowsingWarnings":"invalid"
                                     }]
@@ -219,7 +219,7 @@
   ASSERT_TRUE(report);
   EXPECT_FALSE(GenerateChromeDesktopReportRequest(*report, &profile_));
 
-  report = base::DictionaryValue::From(base::JSONReader::Read(
+  report = base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
       R"({"browserReport":
            {"chromeUserProfileReport":[{
              "safeBrowsingWarningsClickThrough": "invalid"}]
@@ -228,7 +228,7 @@
   ASSERT_TRUE(report);
   EXPECT_FALSE(GenerateChromeDesktopReportRequest(*report, &profile_));
 
-  report = base::DictionaryValue::From(base::JSONReader::Read(
+  report = base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
       R"({"browserReport":
            {"chromeUserProfileReport":[{
               "safeBrowsingWarnings":3,
@@ -268,8 +268,8 @@
   prefs->SetBoolean(enterprise_reporting::kReportExtensionsAndPluginsData,
                     false);
 
-  std::unique_ptr<base::DictionaryValue> report =
-      base::DictionaryValue::From(base::JSONReader::Read(R"({"browserReport":
+  std::unique_ptr<base::DictionaryValue> report = base::DictionaryValue::From(
+      base::JSONReader::ReadDeprecated(R"({"browserReport":
                                   {"chromeUserProfileReport":[
                                     {"extensionData": [{"id":"1"}],
                                      "plugins": [{"id":"2"}]
@@ -289,8 +289,8 @@
   PrefService* prefs = profile_.GetPrefs();
   prefs->SetBoolean(enterprise_reporting::kReportSafeBrowsingData, false);
 
-  std::unique_ptr<base::DictionaryValue> report =
-      base::DictionaryValue::From(base::JSONReader::Read(R"({"browserReport":
+  std::unique_ptr<base::DictionaryValue> report = base::DictionaryValue::From(
+      base::JSONReader::ReadDeprecated(R"({"browserReport":
                                   {"chromeUserProfileReport":[
                                     {"safeBrowsingWarnings" : 1,
                                      "safeBrowsingWarningsClickThrough": 2
diff --git a/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc b/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc
index 52c2d49b..9a5e8ef 100644
--- a/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc
+++ b/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc
@@ -53,7 +53,7 @@
 
   void OnMessage(const std::string& request_string) override {
     std::unique_ptr<base::Value> request_value =
-        base::JSONReader::Read(request_string);
+        base::JSONReader::ReadDeprecated(request_string);
     std::unique_ptr<base::DictionaryValue> request(
         static_cast<base::DictionaryValue*>(request_value.release()));
     if (request_string.find("stopHostTest") != std::string::npos) {
diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc b/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc
index 8d89690..4e27254 100644
--- a/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc
+++ b/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc
@@ -122,7 +122,7 @@
 
     // Parse the message.
     std::unique_ptr<base::DictionaryValue> dict_value =
-        base::DictionaryValue::From(base::JSONReader::Read(message));
+        base::DictionaryValue::From(base::JSONReader::ReadDeprecated(message));
     if (dict_value) {
       last_message_parsed_ = std::move(dict_value);
     } else {
diff --git a/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc b/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
index 4fb41c7..56b019ab 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
@@ -44,7 +44,7 @@
     const std::string& permission_str,
     std::string* error) {
   std::unique_ptr<base::Value> permission_json =
-      base::JSONReader::Read(permission_arg);
+      base::JSONReader::ReadDeprecated(permission_arg);
   if (!permission_json.get()) {
     *error = ErrorUtils::FormatErrorMessage(kInvalidParameter, permission_str);
     return nullptr;
diff --git a/chrome/browser/extensions/api/storage/setting_sync_data.cc b/chrome/browser/extensions/api/storage/setting_sync_data.cc
index a704db76..3aac4a07 100644
--- a/chrome/browser/extensions/api/storage/setting_sync_data.cc
+++ b/chrome/browser/extensions/api/storage/setting_sync_data.cc
@@ -52,7 +52,7 @@
 
   extension_id_ = extension_specifics.extension_id();
   key_ = extension_specifics.key();
-  value_ = base::JSONReader::Read(extension_specifics.value());
+  value_ = base::JSONReader::ReadDeprecated(extension_specifics.value());
 
   if (!value_) {
     LOG(WARNING) << "Specifics for " << extension_id_ << "/" << key_
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
index 4677243..2f9a2e9 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
@@ -169,7 +169,8 @@
       request.get(), content::RESOURCE_TYPE_MAIN_FRAME, /*context*/ nullptr,
       -1 /* render_process_id */, -1 /* render_view_id */,
       -1 /* render_frame_id */, true /* is_main_frame */,
-      false /* allow_download */, false /* is_async */, content::PREVIEWS_OFF,
+      content::ResourceInterceptPolicy::kAllowNone, false /* is_async */,
+      content::PREVIEWS_OFF,
       ChromeNavigationUIData::CreateForMainFrameNavigation(
           nullptr /* web_contents */, WindowOpenDisposition::CURRENT_TAB));
   return request;
diff --git a/chrome/browser/extensions/chrome_app_api_browsertest.cc b/chrome/browser/extensions/chrome_app_api_browsertest.cc
index de3b87f..573d306c 100644
--- a/chrome/browser/extensions/chrome_app_api_browsertest.cc
+++ b/chrome/browser/extensions/chrome_app_api_browsertest.cc
@@ -145,7 +145,7 @@
           &result));
   std::unique_ptr<base::DictionaryValue> app_details(
       static_cast<base::DictionaryValue*>(
-          base::JSONReader::Read(result).release()));
+          base::JSONReader::ReadDeprecated(result).release()));
   // extension->manifest() does not contain the id.
   app_details->Remove("id", NULL);
   EXPECT_TRUE(app_details.get());
diff --git a/chrome/browser/extensions/extension_function_test_utils.cc b/chrome/browser/extensions/extension_function_test_utils.cc
index 3f22cb5..edf3ff8 100644
--- a/chrome/browser/extensions/extension_function_test_utils.cc
+++ b/chrome/browser/extensions/extension_function_test_utils.cc
@@ -51,7 +51,7 @@
 namespace extension_function_test_utils {
 
 base::ListValue* ParseList(const std::string& data) {
-  std::unique_ptr<base::Value> result = base::JSONReader::Read(data);
+  std::unique_ptr<base::Value> result = base::JSONReader::ReadDeprecated(data);
   if (!result) {
     ADD_FAILURE() << "Failed to parse: " << data;
     return nullptr;
diff --git a/chrome/browser/extensions/extension_management_unittest.cc b/chrome/browser/extensions/extension_management_unittest.cc
index d32be29..a80ed20d 100644
--- a/chrome/browser/extensions/extension_management_unittest.cc
+++ b/chrome/browser/extensions/extension_management_unittest.cc
@@ -167,9 +167,11 @@
 
   void SetExampleDictPref(const base::StringPiece example_dict_preference) {
     std::string error_msg;
-    std::unique_ptr<base::Value> parsed = base::JSONReader::ReadAndReturnError(
-        example_dict_preference,
-        base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS, NULL, &error_msg);
+    std::unique_ptr<base::Value> parsed =
+        base::JSONReader::ReadAndReturnErrorDeprecated(
+            example_dict_preference,
+            base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS, NULL,
+            &error_msg);
     ASSERT_TRUE(parsed && parsed->is_dict()) << error_msg;
     SetPref(true, pref_names::kExtensionManagement, std::move(parsed));
   }
diff --git a/chrome/browser/extensions/extension_protocols_unittest.cc b/chrome/browser/extensions/extension_protocols_unittest.cc
index 982221f..b860393 100644
--- a/chrome/browser/extensions/extension_protocols_unittest.cc
+++ b/chrome/browser/extensions/extension_protocols_unittest.cc
@@ -332,12 +332,12 @@
 
     content::ResourceRequestInfo::AllocateForTesting(
         request.get(), resource_type,
-        /* resource_context */nullptr,
+        /* resource_context */ nullptr,
         /*render_process_id=*/-1,
         /*render_view_id=*/-1,
         /*render_frame_id=*/-1,
         /*is_main_frame=*/resource_type == content::RESOURCE_TYPE_MAIN_FRAME,
-        /*allow_download=*/true,
+        content::ResourceInterceptPolicy::kAllowAll,
         /*is_async=*/false, content::PREVIEWS_OFF,
         /*navigation_ui_data*/ nullptr);
     request->Start();
diff --git a/chrome/browser/extensions/install_signer.cc b/chrome/browser/extensions/install_signer.cc
index b4f6108e..2e165d23 100644
--- a/chrome/browser/extensions/install_signer.cc
+++ b/chrome/browser/extensions/install_signer.cc
@@ -443,7 +443,8 @@
   // could not be verified to be in the webstore.
 
   base::DictionaryValue* dictionary = NULL;
-  std::unique_ptr<base::Value> parsed = base::JSONReader::Read(*response_body);
+  std::unique_ptr<base::Value> parsed =
+      base::JSONReader::ReadDeprecated(*response_body);
   bool json_success = parsed.get() && parsed->GetAsDictionary(&dictionary);
   UMA_HISTOGRAM_BOOLEAN("ExtensionInstallSigner.ParseJsonSuccess",
                         json_success);
diff --git a/chrome/browser/extensions/policy_handlers_unittest.cc b/chrome/browser/extensions/policy_handlers_unittest.cc
index edbe164..4dbb80f 100644
--- a/chrome/browser/extensions/policy_handlers_unittest.cc
+++ b/chrome/browser/extensions/policy_handlers_unittest.cc
@@ -111,7 +111,7 @@
     std::string policy = base::StringPrintf(policy_template, url.c_str());
     std::string error;
     std::unique_ptr<base::Value> policy_value =
-        base::JSONReader::ReadAndReturnError(
+        base::JSONReader::ReadAndReturnErrorDeprecated(
             policy, base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS,
             nullptr, &error);
     if (!policy_value)
@@ -352,7 +352,7 @@
 TEST(ExtensionSettingsPolicyHandlerTest, CheckPolicySettings) {
   std::string error;
   std::unique_ptr<base::Value> policy_value =
-      base::JSONReader::ReadAndReturnError(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
           kTestManagementPolicy1,
           base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS, NULL, &error);
   ASSERT_TRUE(policy_value.get()) << error;
@@ -379,7 +379,7 @@
 
   std::string error;
   std::unique_ptr<base::Value> policy_value =
-      base::JSONReader::ReadAndReturnError(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
           kTestManagementPolicy2,
           base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS, NULL, &error);
   ASSERT_TRUE(policy_value.get()) << error;
@@ -411,7 +411,7 @@
 
   std::string error;
   std::unique_ptr<base::Value> policy_value =
-      base::JSONReader::ReadAndReturnError(
+      base::JSONReader::ReadAndReturnErrorDeprecated(
           kTestManagementPolicy2,
           base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error);
   ASSERT_TRUE(policy_value.get()) << error;
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc
index acdb50c..5ad2fe2 100644
--- a/chrome/browser/extensions/service_worker_apitest.cc
+++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -486,7 +486,7 @@
   // Build "test.onMessage" event for dispatch.
   auto event = std::make_unique<Event>(
       events::FOR_TEST, extensions::api::test::OnMessage::kEventName,
-      base::ListValue::From(base::JSONReader::Read(
+      base::ListValue::From(base::JSONReader::ReadDeprecated(
           R"([{"data": "hello", "lastMessage": true}])")),
       profile());
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 5173e27..96c6d98 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1294,8 +1294,8 @@
   },
   {
     "name": "enable-homepage-tile",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
+    "owners": [ "dimich", "twellington" ],
+    "expiry_milestone": 78
   },
   {
     "name": "enable-horizontal-tab-switcher",
diff --git a/chrome/browser/media/router/providers/cast/cast_internal_message_util_unittest.cc b/chrome/browser/media/router/providers/cast/cast_internal_message_util_unittest.cc
index b0c5739..5b7c6c5 100644
--- a/chrome/browser/media/router/providers/cast/cast_internal_message_util_unittest.cc
+++ b/chrome/browser/media/router/providers/cast/cast_internal_message_util_unittest.cc
@@ -34,7 +34,7 @@
         "transportId":"transportId"
       }]
   })";
-  return base::JSONReader::Read(receiver_status_str);
+  return base::JSONReader::ReadDeprecated(receiver_status_str);
 }
 
 void ExpectNoCastSession(const MediaSinkInternal& sink,
diff --git a/chrome/browser/media/router/providers/dial/dial_internal_message_util_unittest.cc b/chrome/browser/media/router/providers/dial/dial_internal_message_util_unittest.cc
index ba16c66..85110e6 100644
--- a/chrome/browser/media/router/providers/dial/dial_internal_message_util_unittest.cc
+++ b/chrome/browser/media/router/providers/dial/dial_internal_message_util_unittest.cc
@@ -30,10 +30,11 @@
 
   void ExpectMessagesEqual(const std::string& expected_message,
                            const std::string& message) {
-    auto expected_message_value = base::JSONReader::Read(expected_message);
+    auto expected_message_value =
+        base::JSONReader::ReadDeprecated(expected_message);
     ASSERT_TRUE(expected_message_value);
 
-    auto message_value = base::JSONReader::Read(message);
+    auto message_value = base::JSONReader::ReadDeprecated(message);
     ASSERT_TRUE(message_value);
 
     EXPECT_EQ(*expected_message_value, *message_value);
diff --git a/chrome/browser/media/router/test/test_helper.cc b/chrome/browser/media/router/test/test_helper.cc
index f1dc6c9..63cf872 100644
--- a/chrome/browser/media/router/test/test_helper.cc
+++ b/chrome/browser/media/router/test/test_helper.cc
@@ -177,7 +177,7 @@
 
 std::unique_ptr<DialInternalMessage> ParseDialInternalMessage(
     const std::string& message) {
-  auto message_value = base::JSONReader::Read(message);
+  auto message_value = base::JSONReader::ReadDeprecated(message);
   std::string error_unused;
   return message_value ? DialInternalMessage::From(std::move(*message_value),
                                                    &error_unused)
diff --git a/chrome/browser/media/webrtc/test_stats_dictionary_unittest.cc b/chrome/browser/media/webrtc/test_stats_dictionary_unittest.cc
index 85acdaf..51bfa16 100644
--- a/chrome/browser/media/webrtc/test_stats_dictionary_unittest.cc
+++ b/chrome/browser/media/webrtc/test_stats_dictionary_unittest.cc
@@ -48,7 +48,7 @@
  public:
   TestStatsDictionaryTest() {
     std::unique_ptr<base::Value> value =
-        base::JSONReader::Read(kTestStatsReportJson);
+        base::JSONReader::ReadDeprecated(kTestStatsReportJson);
     CHECK(value);
     base::DictionaryValue* dictionary;
     CHECK(value->GetAsDictionary(&dictionary));
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest_base.cc b/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
index 3b1db29..fc1bb53 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
+++ b/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
@@ -140,7 +140,8 @@
 
 std::vector<std::string> JsonArrayToVectorOfStrings(
     const std::string& json_array) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json_array);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(json_array);
   EXPECT_TRUE(value);
   EXPECT_TRUE(value->is_list());
   std::unique_ptr<base::ListValue> list =
@@ -560,8 +561,8 @@
 WebRtcTestBase::GetStatsReportDictionary(content::WebContents* tab) const {
   std::string result = ExecuteJavascript("getStatsReportDictionary()", tab);
   EXPECT_TRUE(base::StartsWith(result, "ok-", base::CompareCase::SENSITIVE));
-  std::unique_ptr<base::Value> parsed_json = base::JSONReader::Read(
-      result.substr(3));
+  std::unique_ptr<base::Value> parsed_json =
+      base::JSONReader::ReadDeprecated(result.substr(3));
   base::DictionaryValue* dictionary;
   CHECK(parsed_json);
   CHECK(parsed_json->GetAsDictionary(&dictionary));
diff --git a/chrome/browser/media/webrtc/webrtc_getmediadevices_browsertest.cc b/chrome/browser/media/webrtc/webrtc_getmediadevices_browsertest.cc
index 4a7eff8..f596c90 100644
--- a/chrome/browser/media/webrtc/webrtc_getmediadevices_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_getmediadevices_browsertest.cc
@@ -85,9 +85,10 @@
 
     int error_code;
     std::string error_message;
-    std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-        devices_as_json, base::JSON_ALLOW_TRAILING_COMMAS, &error_code,
-        &error_message);
+    std::unique_ptr<base::Value> value =
+        base::JSONReader::ReadAndReturnErrorDeprecated(
+            devices_as_json, base::JSON_ALLOW_TRAILING_COMMAS, &error_code,
+            &error_message);
 
     ASSERT_TRUE(value.get() != NULL) << error_message;
     EXPECT_EQ(value->type(), base::Value::Type::LIST);
diff --git a/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc b/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc
index 406a704..dbd565f8 100644
--- a/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc
@@ -74,7 +74,7 @@
         webrtc_internals_tab);
 
     std::unique_ptr<base::Value> parsed_json =
-        base::JSONReader::Read(all_stats_json);
+        base::JSONReader::ReadDeprecated(all_stats_json);
     base::DictionaryValue* result;
     if (parsed_json.get() && parsed_json->GetAsDictionary(&result)) {
       ignore_result(parsed_json.release());
diff --git a/chrome/browser/net/dns_probe_runner.cc b/chrome/browser/net/dns_probe_runner.cc
index 2582fd5..90f483b 100644
--- a/chrome/browser/net/dns_probe_runner.cc
+++ b/chrome/browser/net/dns_probe_runner.cc
@@ -17,6 +17,7 @@
 #include "net/dns/dns_client.h"
 #include "net/dns/dns_response.h"
 #include "net/dns/dns_transaction.h"
+#include "net/dns/dns_util.h"
 #include "net/dns/public/dns_protocol.h"
 #include "net/log/net_log_with_source.h"
 
@@ -109,7 +110,7 @@
       kKnownGoodHostname, net::dns_protocol::kTypeA,
       base::Bind(&DnsProbeRunner::OnTransactionComplete,
                  weak_factory_.GetWeakPtr()),
-      NetLogWithSource());
+      NetLogWithSource(), net::SecureDnsMode::AUTOMATIC);
 
   transaction_->Start();
 }
diff --git a/chrome/browser/net/log_net_log_browsertest.cc b/chrome/browser/net/log_net_log_browsertest.cc
index fb257e4..88350ec 100644
--- a/chrome/browser/net/log_net_log_browsertest.cc
+++ b/chrome/browser/net/log_net_log_browsertest.cc
@@ -37,7 +37,7 @@
         << "Could not read: " << net_log_path_;
 
     // Parse it as JSON.
-    auto parsed = base::JSONReader::Read(file_contents);
+    auto parsed = base::JSONReader::ReadDeprecated(file_contents);
     ASSERT_TRUE(parsed);
 
     // Ensure the root value is a dictionary.
diff --git a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
index 7a723c5..1729b0a4 100644
--- a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
+++ b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
@@ -1146,8 +1146,7 @@
       /*render_process_id=*/1,
       /*render_view_id=*/-1,
       /*render_frame_id=*/1,
-      /*is_main_frame=*/true,
-      /*allow_download=*/true,
+      /*is_main_frame=*/true, content::ResourceInterceptPolicy::kAllowAll,
       /*is_async=*/true,
       test_base_->allow_preview() ? content::OFFLINE_PAGE_ON
                                   : content::PREVIEWS_OFF,
diff --git a/chrome/browser/picture_in_picture/DEPS b/chrome/browser/picture_in_picture/DEPS
index 6d49d19..169b1b5 100644
--- a/chrome/browser/picture_in_picture/DEPS
+++ b/chrome/browser/picture_in_picture/DEPS
@@ -2,6 +2,7 @@
   "picture_in_picture_window_controller_browsertest\.cc": [
     "+ash/accelerators/accelerator_controller.h",
     "+ash/shell.h",
+    "+chrome/browser/ui/views/overlay/next_track_image_button.h",
     "+chrome/browser/ui/views/overlay/overlay_window_views.h",
     "+chrome/browser/ui/views/overlay/playback_image_button.h",
     "+chrome/browser/ui/views/overlay/skip_ad_label_button.h",
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
index dc73d30..1e504057 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -44,6 +44,7 @@
 #include "ui/gfx/codec/png_codec.h"
 
 #if !defined(OS_ANDROID)
+#include "chrome/browser/ui/views/overlay/next_track_image_button.h"
 #include "chrome/browser/ui/views/overlay/overlay_window_views.h"
 #include "chrome/browser/ui/views/overlay/playback_image_button.h"
 #include "chrome/browser/ui/views/overlay/skip_ad_label_button.h"
@@ -88,6 +89,7 @@
   MOCK_METHOD1(CustomControlPressed, void(const std::string&));
   MOCK_METHOD1(SetAlwaysHidePlayPauseButton, void(bool));
   MOCK_METHOD0(SkipAd, void());
+  MOCK_METHOD0(NextTrack, void());
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockPictureInPictureWindowController);
@@ -1990,7 +1992,6 @@
 
   // Set Media Session action "pause" handler and check that Play/Pause button
   // is now displayed when mouse is hovering over the window.
-  base::RunLoop().RunUntilIdle();
   ASSERT_TRUE(content::ExecuteScript(active_web_contents,
                                      "setMediaSessionActionHandler('pause');"));
   base::RunLoop().RunUntilIdle();
@@ -2026,6 +2027,51 @@
 }
 #endif
 
+// Tests that a Next Track button is displayed in the Picture-in-Picture window
+// when Media Session Action "nexttrack" is handled by the website.
+IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest,
+                       NextTrackButtonVisibility) {
+  LoadTabAndEnterPictureInPicture(browser());
+  OverlayWindowViews* overlay_window = static_cast<OverlayWindowViews*>(
+      window_controller()->GetWindowForTesting());
+  ASSERT_TRUE(overlay_window);
+
+  // Next Track button is not displayed initially when mouse is hovering over
+  // the window.
+  MoveMouseOver(overlay_window);
+  EXPECT_FALSE(
+      overlay_window->next_track_controls_view_for_testing()->IsDrawn());
+
+  content::WebContents* active_web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  // Next Track button is not displayed if video is not playing even if mouse is
+  // hovering over the window and media session action handler has been set.
+  ASSERT_TRUE(content::ExecuteScript(
+      active_web_contents, "setMediaSessionActionHandler('nexttrack');"));
+  base::RunLoop().RunUntilIdle();
+  MoveMouseOver(overlay_window);
+  EXPECT_FALSE(
+      overlay_window->next_track_controls_view_for_testing()->IsDrawn());
+
+  // Play video and check that Next Track button is now displayed when
+  // video plays and mouse is hovering over the window.
+  ASSERT_TRUE(content::ExecuteScript(active_web_contents, "video.play();"));
+  base::RunLoop().RunUntilIdle();
+  MoveMouseOver(overlay_window);
+  EXPECT_TRUE(
+      overlay_window->next_track_controls_view_for_testing()->IsDrawn());
+
+  // Unset action handler and check that Next Track button is not displayed when
+  // video plays and mouse is hovering over the window.
+  ASSERT_TRUE(content::ExecuteScript(
+      active_web_contents, "unsetMediaSessionActionHandler('nexttrack');"));
+  base::RunLoop().RunUntilIdle();
+  MoveMouseOver(overlay_window);
+  EXPECT_FALSE(
+      overlay_window->next_track_controls_view_for_testing()->IsDrawn());
+}
+
 // Tests that clicking the Skip Ad button in the Picture-in-Picture window
 // calls the Media Session Action "skipad" handler function.
 IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest,
@@ -2079,6 +2125,27 @@
                 .WaitAndGetTitle());
 }
 
+// Tests that clicking the Next Track button in the Picture-in-Picture window
+// calls the Media Session Action "nexttrack" handler function.
+IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureWindowControllerBrowserTest,
+                       NextTrackHandlerCalled) {
+  LoadTabAndEnterPictureInPicture(browser());
+  content::WebContents* active_web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_TRUE(content::ExecuteScript(active_web_contents, "video.play();"));
+  ASSERT_TRUE(content::ExecuteScript(
+      active_web_contents, "setMediaSessionActionHandler('nexttrack');"));
+  base::RunLoop().RunUntilIdle();
+
+  // Simulates user clicking "Next Track" and check the handler function is
+  // called.
+  window_controller()->NextTrack();
+  base::string16 expected_title = base::ASCIIToUTF16("nexttrack");
+  EXPECT_EQ(expected_title,
+            content::TitleWatcher(active_web_contents, expected_title)
+                .WaitAndGetTitle());
+}
+
 // Show/hide page and check that Auto Picture-in-Picture is not triggered. This
 // test is most likely going to be flaky the day the tested thing fails.
 // Do NOT disable test. Ping /chrome/browser/picture_in_picture/OWNERS instead.
diff --git a/chrome/browser/plugins/flash_download_interception.cc b/chrome/browser/plugins/flash_download_interception.cc
index abf8cc2..c4335027 100644
--- a/chrome/browser/plugins/flash_download_interception.cc
+++ b/chrome/browser/plugins/flash_download_interception.cc
@@ -178,5 +178,6 @@
   }
 
   return std::make_unique<navigation_interception::InterceptNavigationThrottle>(
-      handle, base::Bind(&InterceptNavigation, source_url));
+      handle, base::Bind(&InterceptNavigation, source_url),
+      navigation_interception::SynchronyMode::kSync);
 }
diff --git a/chrome/browser/plugins/plugin_finder.cc b/chrome/browser/plugins/plugin_finder.cc
index 7c0dcca..427c192 100644
--- a/chrome/browser/plugins/plugin_finder.cc
+++ b/chrome/browser/plugins/plugin_finder.cc
@@ -171,8 +171,9 @@
           IDR_PLUGIN_DB_JSON));
   std::string error_str;
   int error_code = base::JSONReader::JSON_NO_ERROR;
-  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-      json_resource, base::JSON_PARSE_RFC, &error_code, &error_str);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          json_resource, base::JSON_PARSE_RFC, &error_code, &error_str);
   if (!value) {
     DLOG(ERROR) << error_str;
     switch (error_code) {
diff --git a/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc
index 499d850a..15184fb 100644
--- a/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc
+++ b/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc
@@ -64,10 +64,20 @@
 const char kEnrollmentToken[] = "enrollment_token";
 const char kInvalidEnrollmentToken[] = "invalid_enrollment_token";
 const char kMachineName[] = "foo";
-const char kClientID[] = "fake-client-id";
-const char kDMToken[] = "fake-dm-token";
+const char kClientID[] = "fake_client_id";
+const char kDMToken[] = "fake_dm_token";
+const char kInvalidDMToken[] = "invalid_dm_token";
 const char kEnrollmentResultMetrics[] =
     "Enterprise.MachineLevelUserCloudPolicyEnrollment.Result";
+const char kTestPolicyConfig[] = R"(
+{
+  "google/chrome/machine-level-user" : {
+    "mandatory": {
+      "ShowHomeButton": true
+    }
+  }
+}
+)";
 
 class MachineLevelUserCloudPolicyControllerObserver
     : public MachineLevelUserCloudPolicyController::Observer {
@@ -141,6 +151,8 @@
 
   void SetClientId(std::string client_id) { client_id_ = client_id; }
 
+  void SetDMToken(std::string dm_token) { dm_token_ = dm_token; }
+
   std::string InitClientId() override {
     NOTREACHED();
     return std::string();
@@ -191,6 +203,61 @@
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserExtraSetUp);
 };
 
+// Two observers that quit run_loop when policy is fetched and stored or in case
+// there is any error.
+class PolicyFetchStoreObserver : public CloudPolicyStore::Observer {
+ public:
+  PolicyFetchStoreObserver(CloudPolicyStore* store,
+                           base::OnceClosure quit_closure)
+      : store_(store), quit_closure_(std::move(quit_closure)) {
+    store_->AddObserver(this);
+  }
+  ~PolicyFetchStoreObserver() override { store_->RemoveObserver(this); }
+
+  void OnStoreLoaded(CloudPolicyStore* store) override {
+    std::move(quit_closure_).Run();
+  }
+  void OnStoreError(CloudPolicyStore* store) override {
+    std::move(quit_closure_).Run();
+  }
+
+ private:
+  CloudPolicyStore* store_;
+  base::OnceClosure quit_closure_;
+  DISALLOW_COPY_AND_ASSIGN(PolicyFetchStoreObserver);
+};
+
+class PolicyFetchClientObserver : public CloudPolicyClient::Observer {
+ public:
+  PolicyFetchClientObserver(CloudPolicyClient* client,
+                            base::OnceClosure quit_closure)
+      : client_(client), quit_closure_(std::move(quit_closure)) {
+    client_->AddObserver(this);
+  }
+  ~PolicyFetchClientObserver() override { client_->RemoveObserver(this); }
+
+  void OnPolicyFetched(CloudPolicyClient* client) override {
+    // The policy is fetched, wait for the policy is validated and stored.
+    store_observer_ = std::make_unique<PolicyFetchStoreObserver>(
+        g_browser_process->browser_policy_connector()
+            ->machine_level_user_cloud_policy_manager()
+            ->store(),
+        std::move(quit_closure_));
+  }
+
+  void OnRegistrationStateChanged(CloudPolicyClient* client) override {}
+
+  void OnClientError(CloudPolicyClient* client) override {
+    std::move(quit_closure_).Run();
+  }
+
+ private:
+  CloudPolicyClient* client_;
+  base::OnceClosure quit_closure_;
+  std::unique_ptr<PolicyFetchStoreObserver> store_observer_;
+  DISALLOW_COPY_AND_ASSIGN(PolicyFetchClientObserver);
+};
+
 }  // namespace
 
 MATCHER_P(MatchProto, expected, "matches protobuf") {
@@ -512,4 +579,89 @@
                                             ::testing::Bool(),
                                             ::testing::Bool()));
 
+class MachineLevelUserCloudPolicyPolicyFetchTest
+    : public InProcessBrowserTest,
+      public ::testing::WithParamInterface<std::string> {
+ public:
+  MachineLevelUserCloudPolicyPolicyFetchTest() {
+    BrowserDMTokenStorage::SetForTesting(&storage_);
+    storage_.SetEnrollmentToken(kEnrollmentToken);
+    storage_.SetClientId(kClientID);
+    if (!dm_token().empty())
+      storage_.SetDMToken(dm_token());
+  }
+
+  void SetUpInProcessBrowserTestFixture() override {
+    SetUpTestServer();
+    ASSERT_TRUE(test_server_->Start());
+
+    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+    command_line->AppendSwitchASCII(switches::kDeviceManagementUrl,
+                                    test_server_->GetServiceURL().spec());
+  }
+
+#if !defined(GOOGLE_CHROME_BUILD)
+  void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
+    InProcessBrowserTest::SetUpDefaultCommandLine(command_line);
+    command_line->AppendSwitch(::switches::kEnableMachineLevelUserCloudPolicy);
+  }
+#endif
+
+  void SetUpTestServer() {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    base::FilePath config_path = temp_dir_.GetPath().AppendASCII("config.json");
+    base::WriteFile(config_path, kTestPolicyConfig, strlen(kTestPolicyConfig));
+    test_server_ = std::make_unique<LocalPolicyTestServer>(config_path);
+    test_server_->RegisterClient(kDMToken, kClientID);
+  }
+
+  const std::string dm_token() const { return GetParam(); }
+
+ private:
+  std::unique_ptr<LocalPolicyTestServer> test_server_;
+  FakeBrowserDMTokenStorage storage_;
+  base::ScopedTempDir temp_dir_;
+
+  DISALLOW_COPY_AND_ASSIGN(MachineLevelUserCloudPolicyPolicyFetchTest);
+};
+
+IN_PROC_BROWSER_TEST_P(MachineLevelUserCloudPolicyPolicyFetchTest, Test) {
+  MachineLevelUserCloudPolicyManager* manager =
+      g_browser_process->browser_policy_connector()
+          ->machine_level_user_cloud_policy_manager();
+  ASSERT_TRUE(manager);
+  // If the policy hasn't been updated, wait for it.
+  if (manager->core()->client()->last_policy_timestamp().is_null()) {
+    base::RunLoop run_loop;
+    PolicyFetchClientObserver observer(manager->core()->client(),
+                                       run_loop.QuitClosure());
+    g_browser_process->browser_policy_connector()
+        ->device_management_service()
+        ->ScheduleInitialization(0);
+    run_loop.Run();
+  }
+  EXPECT_TRUE(
+      manager->IsInitializationComplete(PolicyDomain::POLICY_DOMAIN_CHROME));
+
+  const PolicyMap& policy_map = manager->store()->policy_map();
+  if (dm_token() != kInvalidDMToken) {
+    EXPECT_EQ(1u, policy_map.size());
+    EXPECT_EQ(base::Value(true), *(policy_map.Get("ShowHomeButton")->value));
+  } else {
+    EXPECT_EQ(0u, policy_map.size());
+  }
+}
+
+// The tests here cover three cases:
+//  1) Start Chrome with a valid DM token but no policy cache. Chrome will
+//  load the policy from the DM server.
+//  2) Start Chrome with an invalid DM token. Chrome will hit the DM server and
+//  get an error. There should be no more cloud policy applied.
+//  3) Start Chrome without DM token. Chrome will register itself and fetch
+//  policy after it.
+INSTANTIATE_TEST_SUITE_P(,
+                         MachineLevelUserCloudPolicyPolicyFetchTest,
+                         ::testing::Values(kDMToken, kInvalidDMToken, ""));
+
 }  // namespace policy
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 6f3bfca..3ba5cfa 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -661,6 +661,9 @@
   { key::kEcryptfsMigrationStrategy,
     arc::prefs::kEcryptfsMigrationStrategy,
     base::Value::Type::INTEGER },
+  { key::kSchedulerConfiguration,
+    prefs::kSchedulerConfiguration,
+    base::Value::Type::STRING },
   { key::kNativePrintersBulkAccessMode,
     prefs::kRecommendedNativePrintersAccessMode,
     base::Value::Type::INTEGER },
diff --git a/chrome/browser/policy/managed_bookmarks_policy_handler_unittest.cc b/chrome/browser/policy/managed_bookmarks_policy_handler_unittest.cc
index d5b96da56..3bca775 100644
--- a/chrome/browser/policy/managed_bookmarks_policy_handler_unittest.cc
+++ b/chrome/browser/policy/managed_bookmarks_policy_handler_unittest.cc
@@ -38,46 +38,47 @@
   EXPECT_FALSE(store_->GetValue(bookmarks::prefs::kManagedBookmarks, NULL));
 
   PolicyMap policy;
-  policy.Set(key::kManagedBookmarks, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-             POLICY_SOURCE_CLOUD,
-             base::JSONReader::Read("["
-                                    // The following gets filtered out from the
-                                    // JSON string when parsed.
-                                    "  {"
-                                    "    \"toplevel_name\": \"abc 123\""
-                                    "  },"
-                                    "  {"
-                                    "    \"name\": \"Google\","
-                                    "    \"url\": \"google.com\""
-                                    "  },"
-                                    "  {"
-                                    "    \"name\": \"Empty Folder\","
-                                    "    \"children\": []"
-                                    "  },"
-                                    "  {"
-                                    "    \"name\": \"Big Folder\","
-                                    "    \"children\": ["
-                                    "      {"
-                                    "        \"name\": \"Youtube\","
-                                    "        \"url\": \"youtube.com\""
-                                    "      },"
-                                    "      {"
-                                    "        \"name\": \"Chromium\","
-                                    "        \"url\": \"chromium.org\""
-                                    "      },"
-                                    "      {"
-                                    "        \"name\": \"More Stuff\","
-                                    "        \"children\": ["
-                                    "          {"
-                                    "            \"name\": \"Bugs\","
-                                    "            \"url\": \"crbug.com\""
-                                    "          }"
-                                    "        ]"
-                                    "      }"
-                                    "    ]"
-                                    "  }"
-                                    "]"),
-             nullptr);
+  policy.Set(
+      key::kManagedBookmarks, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+      POLICY_SOURCE_CLOUD,
+      base::JSONReader::ReadDeprecated("["
+                                       // The following gets filtered out from
+                                       // the JSON string when parsed.
+                                       "  {"
+                                       "    \"toplevel_name\": \"abc 123\""
+                                       "  },"
+                                       "  {"
+                                       "    \"name\": \"Google\","
+                                       "    \"url\": \"google.com\""
+                                       "  },"
+                                       "  {"
+                                       "    \"name\": \"Empty Folder\","
+                                       "    \"children\": []"
+                                       "  },"
+                                       "  {"
+                                       "    \"name\": \"Big Folder\","
+                                       "    \"children\": ["
+                                       "      {"
+                                       "        \"name\": \"Youtube\","
+                                       "        \"url\": \"youtube.com\""
+                                       "      },"
+                                       "      {"
+                                       "        \"name\": \"Chromium\","
+                                       "        \"url\": \"chromium.org\""
+                                       "      },"
+                                       "      {"
+                                       "        \"name\": \"More Stuff\","
+                                       "        \"children\": ["
+                                       "          {"
+                                       "            \"name\": \"Bugs\","
+                                       "            \"url\": \"crbug.com\""
+                                       "          }"
+                                       "        ]"
+                                       "      }"
+                                       "    ]"
+                                       "  }"
+                                       "]"),
+      nullptr);
   UpdateProviderPolicy(policy);
   const base::Value* pref_value = NULL;
   EXPECT_TRUE(
@@ -146,12 +147,12 @@
   PolicyMap policy;
   policy.Set(key::kManagedBookmarks, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
              POLICY_SOURCE_CLOUD,
-             base::JSONReader::Read("["
-                                    "  {"
-                                    "    \"name\": \"Google\","
-                                    "    \"url\": \"google.com\""
-                                    "  }"
-                                    "]"),
+             base::JSONReader::ReadDeprecated("["
+                                              "  {"
+                                              "    \"name\": \"Google\","
+                                              "    \"url\": \"google.com\""
+                                              "  }"
+                                              "]"),
              nullptr);
   UpdateProviderPolicy(policy);
   const base::Value* pref_value = NULL;
@@ -199,16 +200,17 @@
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 TEST_F(ManagedBookmarksPolicyHandlerTest, UnknownKeys) {
   PolicyMap policy;
-  policy.Set(key::kManagedBookmarks, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-             POLICY_SOURCE_CLOUD,
-             base::JSONReader::Read("["
-                                    "  {"
-                                    "    \"name\": \"Google\","
-                                    "    \"unknown\": \"should be ignored\","
-                                    "    \"url\": \"google.com\""
-                                    "  }"
-                                    "]"),
-             nullptr);
+  policy.Set(
+      key::kManagedBookmarks, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+      POLICY_SOURCE_CLOUD,
+      base::JSONReader::ReadDeprecated("["
+                                       "  {"
+                                       "    \"name\": \"Google\","
+                                       "    \"unknown\": \"should be ignored\","
+                                       "    \"url\": \"google.com\""
+                                       "  }"
+                                       "]"),
+      nullptr);
   UpdateProviderPolicy(policy);
   const base::Value* pref_value = NULL;
   EXPECT_TRUE(
@@ -231,24 +233,24 @@
   PolicyMap policy;
   policy.Set(key::kManagedBookmarks, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
              POLICY_SOURCE_CLOUD,
-             base::JSONReader::Read("["
-                                    "  {"
-                                    "    \"name\": \"Empty\","
-                                    "    \"url\": \"\""
-                                    "  },"
-                                    "  {"
-                                    "    \"name\": \"Invalid type\","
-                                    "    \"url\": 4"
-                                    "  },"
-                                    "  {"
-                                    "    \"name\": \"Invalid URL\","
-                                    "    \"url\": \"?\""
-                                    "  },"
-                                    "  {"
-                                    "    \"name\": \"Google\","
-                                    "    \"url\": \"google.com\""
-                                    "  }"
-                                    "]"),
+             base::JSONReader::ReadDeprecated("["
+                                              "  {"
+                                              "    \"name\": \"Empty\","
+                                              "    \"url\": \"\""
+                                              "  },"
+                                              "  {"
+                                              "    \"name\": \"Invalid type\","
+                                              "    \"url\": 4"
+                                              "  },"
+                                              "  {"
+                                              "    \"name\": \"Invalid URL\","
+                                              "    \"url\": \"?\""
+                                              "  },"
+                                              "  {"
+                                              "    \"name\": \"Google\","
+                                              "    \"url\": \"google.com\""
+                                              "  }"
+                                              "]"),
              nullptr);
   UpdateProviderPolicy(policy);
   const base::Value* pref_value = NULL;
diff --git a/chrome/browser/policy/policy_prefs_browsertest.cc b/chrome/browser/policy/policy_prefs_browsertest.cc
index db06811..a945c70 100644
--- a/chrome/browser/policy/policy_prefs_browsertest.cc
+++ b/chrome/browser/policy/policy_prefs_browsertest.cc
@@ -247,8 +247,9 @@
     int error_code = -1;
     std::string error_string;
     base::DictionaryValue* dict = NULL;
-    std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-        json, base::JSON_PARSE_RFC, &error_code, &error_string);
+    std::unique_ptr<base::Value> value =
+        base::JSONReader::ReadAndReturnErrorDeprecated(
+            json, base::JSON_PARSE_RFC, &error_code, &error_string);
     if (!value.get() || !value->GetAsDictionary(&dict)) {
       ADD_FAILURE() << "Error parsing policy_test_cases.json: " << error_string;
       return;
diff --git a/chrome/browser/policy/test/local_policy_test_server.cc b/chrome/browser/policy/test/local_policy_test_server.cc
index cbb7d63..711b916 100644
--- a/chrome/browser/policy/test/local_policy_test_server.cc
+++ b/chrome/browser/policy/test/local_policy_test_server.cc
@@ -69,7 +69,10 @@
 
 LocalPolicyTestServer::LocalPolicyTestServer(const base::FilePath& config_file)
     : net::LocalTestServer(net::BaseTestServer::TYPE_HTTP, base::FilePath()),
-      config_file_(config_file) {}
+      config_file_(config_file) {
+  base::ScopedAllowBlockingForTesting allow_blocking;
+  CHECK(server_data_dir_.CreateUniqueTempDir());
+}
 
 LocalPolicyTestServer::LocalPolicyTestServer(const std::string& test_name)
     : net::LocalTestServer(net::BaseTestServer::TYPE_HTTP, base::FilePath()) {
@@ -137,6 +140,8 @@
   types->AppendString(dm_protocol::kChromePublicAccountPolicyType);
   types->AppendString(dm_protocol::kChromeExtensionPolicyType);
   types->AppendString(dm_protocol::kChromeSigninExtensionPolicyType);
+  types->AppendString(dm_protocol::kChromeMachineLevelUserCloudPolicyType);
+  types->AppendString(dm_protocol::kChromeMachineLevelExtensionCloudPolicyType);
 
   client_dict->Set(kClientStateKeyAllowedPolicyTypes, std::move(types));
   clients_.Set(dm_token, std::move(client_dict));
diff --git a/chrome/browser/policy/test/policy_testserver.py b/chrome/browser/policy/test/policy_testserver.py
index ce5a6c1..b3c8128 100644
--- a/chrome/browser/policy/test/policy_testserver.py
+++ b/chrome/browser/policy/test/policy_testserver.py
@@ -601,12 +601,14 @@
               'google/chromeos/device',
               'google/chromeos/publicaccount',
               'google/chromeos/user',
-              'google/chrome/user')):
+              'google/chrome/user',
+              'google/chrome/machine-level-user')):
         fetch_response = response.policy_response.response.add()
         self.ProcessCloudPolicy(request, token_info, fetch_response, username)
       elif (request.policy_type in
              ('google/chrome/extension',
-              'google/chromeos/signinextension')):
+              'google/chromeos/signinextension',
+              'google/chrome/machine-level-extension')):
         self.ProcessCloudPolicyForExtensions(
             request, response.policy_response, token_info, username)
       else:
@@ -806,9 +808,12 @@
     if enrollment_token == INVALID_ENROLLMENT_TOKEN:
       return (401, 'Invalid enrollment token')
 
+    dm_token = 'fake_device_management_token'
     response = dm.DeviceManagementResponse()
     response.register_response.device_management_token = (
-        'fake_device_management_token')
+        dm_token)
+    self.server.RegisterBrowser(dm_token, device_id, msg.machine_name)
+
     return (200, response)
 
   def ProcessChromeDesktopReportUploadRequest(self, chrome_desktop_report):
@@ -1028,7 +1033,8 @@
       if msg.policy_type in ('google/android/user',
                              'google/chromeos/publicaccount',
                              'google/chromeos/user',
-                             'google/chrome/user'):
+                             'google/chrome/user',
+                             'google/chrome/machine-level-user'):
         settings = cp.CloudPolicySettings()
         payload = self.server.ReadPolicyFromDataDir(policy_key, settings)
         if payload is None:
@@ -1041,7 +1047,8 @@
           self.GatherDevicePolicySettings(settings, policy.get(policy_key, {}))
           payload = settings.SerializeToString()
       elif msg.policy_type in ('google/chrome/extension',
-                               'google/chromeos/signinextension'):
+                               'google/chromeos/signinextension',
+                               'google/chrome/machine-level-extension'):
         settings = ep.ExternalPolicyData()
         payload = self.server.ReadPolicyFromDataDir(policy_key, settings)
         if payload is None:
@@ -1415,6 +1422,16 @@
     self.WriteClientState()
     return self._registered_tokens[dmtoken]
 
+  def RegisterBrowser(self, dm_token, device_id, machine_name):
+    self._registered_tokens[dm_token] = {
+      'device_id': device_id,
+      'device_token': dm_token,
+      'allowed_policy_types': ['google/chrome/machine-level-user',
+                               'google/chrome/machine-level-extension'],
+      'machine_name': machine_name
+    }
+    self.WriteClientState()
+
   def UpdateStateKeys(self, dmtoken, state_keys):
     """Updates the state keys for a given client.
 
diff --git a/chrome/browser/policy/webusb_allow_devices_for_urls_policy_handler_unittest.cc b/chrome/browser/policy/webusb_allow_devices_for_urls_policy_handler_unittest.cc
index 5356066c..6f694ff9 100644
--- a/chrome/browser/policy/webusb_allow_devices_for_urls_policy_handler_unittest.cc
+++ b/chrome/browser/policy/webusb_allow_devices_for_urls_policy_handler_unittest.cc
@@ -211,7 +211,7 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kValidPolicy), nullptr);
+      base::JSONReader::ReadDeprecated(kValidPolicy), nullptr);
   ASSERT_TRUE(errors.empty());
   EXPECT_TRUE(handler()->CheckPolicySettings(policy, &errors));
   EXPECT_TRUE(errors.empty());
@@ -225,7 +225,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyInvalidTopLevelEntry), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyInvalidTopLevelEntry),
+      nullptr);
 
   ASSERT_TRUE(errors.empty());
   EXPECT_FALSE(handler()->CheckPolicySettings(policy, &errors));
@@ -245,7 +246,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyMissingDevicesProperty), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyMissingDevicesProperty),
+      nullptr);
 
   ASSERT_TRUE(errors.empty());
   EXPECT_FALSE(handler()->CheckPolicySettings(policy, &errors));
@@ -265,7 +267,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyMissingUrlsProperty), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyMissingUrlsProperty),
+      nullptr);
 
   ASSERT_TRUE(errors.empty());
   EXPECT_FALSE(handler()->CheckPolicySettings(policy, &errors));
@@ -285,7 +288,7 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyUnknownProperty), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyUnknownProperty), nullptr);
 
   ASSERT_TRUE(errors.empty());
   EXPECT_FALSE(handler()->CheckPolicySettings(policy, &errors));
@@ -305,7 +308,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyMismatchedVendorIdType), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyMismatchedVendorIdType),
+      nullptr);
 
   ASSERT_TRUE(errors.empty());
   EXPECT_FALSE(handler()->CheckPolicySettings(policy, &errors));
@@ -325,7 +329,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyMismatchedProductIdType), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyMismatchedProductIdType),
+      nullptr);
 
   ASSERT_TRUE(errors.empty());
   EXPECT_FALSE(handler()->CheckPolicySettings(policy, &errors));
@@ -345,7 +350,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyProductIdWithoutVendorId), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyProductIdWithoutVendorId),
+      nullptr);
 
   ASSERT_TRUE(errors.empty());
   EXPECT_FALSE(handler()->CheckPolicySettings(policy, &errors));
@@ -365,7 +371,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyInvalidRequestingUrl), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyInvalidRequestingUrl),
+      nullptr);
 
   ASSERT_TRUE(errors.empty());
   EXPECT_FALSE(handler()->CheckPolicySettings(policy, &errors));
@@ -385,7 +392,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyInvalidEmbeddingUrl), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyInvalidEmbeddingUrl),
+      nullptr);
 
   ASSERT_TRUE(errors.empty());
   EXPECT_FALSE(handler()->CheckPolicySettings(policy, &errors));
@@ -405,7 +413,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyInvalidUrlsEntry), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyInvalidUrlsEntry),
+      nullptr);
 
   ASSERT_TRUE(errors.empty());
   EXPECT_FALSE(handler()->CheckPolicySettings(policy, &errors));
@@ -425,7 +434,7 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(InvalidPolicyNoUrls), nullptr);
+      base::JSONReader::ReadDeprecated(InvalidPolicyNoUrls), nullptr);
 
   ASSERT_TRUE(errors.empty());
   EXPECT_FALSE(handler()->CheckPolicySettings(policy, &errors));
@@ -445,7 +454,7 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kValidPolicy), nullptr);
+      base::JSONReader::ReadDeprecated(kValidPolicy), nullptr);
   UpdateProviderPolicy(policy);
 
   const base::Value* pref_value = nullptr;
@@ -524,7 +533,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyInvalidTopLevelEntry), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyInvalidTopLevelEntry),
+      nullptr);
   UpdateProviderPolicy(policy);
 
   const base::Value* pref_value = nullptr;
@@ -542,7 +552,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyMissingDevicesProperty), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyMissingDevicesProperty),
+      nullptr);
   UpdateProviderPolicy(policy);
   const base::Value* pref_value = nullptr;
   EXPECT_FALSE(
@@ -559,7 +570,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyMissingUrlsProperty), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyMissingUrlsProperty),
+      nullptr);
   UpdateProviderPolicy(policy);
   const base::Value* pref_value = nullptr;
   EXPECT_FALSE(
@@ -576,7 +588,7 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyUnknownProperty), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyUnknownProperty), nullptr);
   UpdateProviderPolicy(policy);
   const base::Value* pref_value = nullptr;
   EXPECT_FALSE(
@@ -593,7 +605,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyMismatchedVendorIdType), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyMismatchedVendorIdType),
+      nullptr);
   UpdateProviderPolicy(policy);
   const base::Value* pref_value = nullptr;
   EXPECT_FALSE(
@@ -610,7 +623,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyMismatchedProductIdType), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyMismatchedProductIdType),
+      nullptr);
   UpdateProviderPolicy(policy);
   const base::Value* pref_value = nullptr;
   EXPECT_FALSE(
@@ -627,7 +641,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyProductIdWithoutVendorId), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyProductIdWithoutVendorId),
+      nullptr);
   UpdateProviderPolicy(policy);
   const base::Value* pref_value = nullptr;
   EXPECT_FALSE(
@@ -644,7 +659,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyInvalidRequestingUrl), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyInvalidRequestingUrl),
+      nullptr);
   UpdateProviderPolicy(policy);
   const base::Value* pref_value = nullptr;
   EXPECT_FALSE(
@@ -661,7 +677,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyInvalidEmbeddingUrl), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyInvalidEmbeddingUrl),
+      nullptr);
   UpdateProviderPolicy(policy);
   const base::Value* pref_value = nullptr;
   EXPECT_FALSE(
@@ -678,7 +695,8 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(kInvalidPolicyInvalidUrlsEntry), nullptr);
+      base::JSONReader::ReadDeprecated(kInvalidPolicyInvalidUrlsEntry),
+      nullptr);
   UpdateProviderPolicy(policy);
   const base::Value* pref_value = nullptr;
   EXPECT_FALSE(
@@ -694,7 +712,7 @@
   policy.Set(
       key::kWebUsbAllowDevicesForUrls, PolicyLevel::POLICY_LEVEL_MANDATORY,
       PolicyScope::POLICY_SCOPE_MACHINE, PolicySource::POLICY_SOURCE_CLOUD,
-      base::JSONReader::Read(InvalidPolicyNoUrls), nullptr);
+      base::JSONReader::ReadDeprecated(InvalidPolicyNoUrls), nullptr);
   UpdateProviderPolicy(policy);
   const base::Value* pref_value = nullptr;
   EXPECT_FALSE(
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index fad6a6b..c6f5e5a 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -10,7 +10,7 @@
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "chrome/browser/about_flags.h"
-#include "chrome/browser/accessibility/accessibility_labels_prefs.h"
+#include "chrome/browser/accessibility/accessibility_labels_service.h"
 #include "chrome/browser/accessibility/accessibility_ui.h"
 #include "chrome/browser/accessibility/invert_bubble_prefs.h"
 #include "chrome/browser/browser_process_impl.h"
@@ -574,7 +574,7 @@
   TRACE_EVENT0("browser", "chrome::RegisterProfilePrefs");
   SCOPED_UMA_HISTOGRAM_TIMER("Settings.RegisterProfilePrefsTime");
   // User prefs. Please keep this list alphabetized.
-  accessibility_prefs::RegisterAccessibilityLabelsProfilePrefs(registry);
+  AccessibilityLabelsService::RegisterProfilePrefs(registry);
   AccessibilityUIMessageHandler::RegisterProfilePrefs(registry);
   autofill::prefs::RegisterProfilePrefs(registry);
   browsing_data::prefs::RegisterBrowserUserPrefs(registry);
diff --git a/chrome/browser/prefs/tracked/pref_hash_browsertest.cc b/chrome/browser/prefs/tracked/pref_hash_browsertest.cc
index f436769..eb1fcc7 100644
--- a/chrome/browser/prefs/tracked/pref_hash_browsertest.cc
+++ b/chrome/browser/prefs/tracked/pref_hash_browsertest.cc
@@ -1236,9 +1236,9 @@
 
     // Try to override default search in all three of available preferences.
     auto attack1 = base::DictionaryValue::From(
-        base::JSONReader::Read(default_search_provider_data));
+        base::JSONReader::ReadDeprecated(default_search_provider_data));
     auto attack2 = base::DictionaryValue::From(
-        base::JSONReader::Read(search_provider_overrides));
+        base::JSONReader::ReadDeprecated(search_provider_overrides));
     unprotected_preferences->MergeDictionary(attack1.get());
     unprotected_preferences->MergeDictionary(attack2.get());
     if (protected_preferences) {
diff --git a/chrome/browser/printing/cloud_print/cloud_print_printer_list_unittest.cc b/chrome/browser/printing/cloud_print/cloud_print_printer_list_unittest.cc
index db9b696..31bb1e1 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_printer_list_unittest.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_printer_list_unittest.cc
@@ -55,7 +55,7 @@
   EXPECT_CALL(delegate, OnDeviceListReady(_)).WillOnce(SaveArg<0>(&devices));
 
   std::unique_ptr<base::Value> value =
-      base::JSONReader::Read(kSampleSuccessResponseOAuth);
+      base::JSONReader::ReadDeprecated(kSampleSuccessResponseOAuth);
   const base::DictionaryValue* dictionary = NULL;
   ASSERT_TRUE(value->GetAsDictionary(&dictionary));
   device_list.OnGCDApiFlowComplete(*dictionary);
diff --git a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
index 7190c49f..97ad8b1 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
@@ -244,7 +244,7 @@
     PrintersCallback callback,
     const std::string& printers_json) {
   std::unique_ptr<base::Value> list_value =
-      base::ListValue::From(base::JSONReader::Read(printers_json));
+      base::ListValue::From(base::JSONReader::ReadDeprecated(printers_json));
   std::vector<std::string> printers;
   if (list_value) {
     for (const auto& element : list_value->GetList()) {
diff --git a/chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc b/chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc
index 9c082cac..b5c4ff0 100644
--- a/chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc
+++ b/chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc
@@ -168,7 +168,8 @@
   }
 
   base::JSONReader reader;
-  std::unique_ptr<const base::Value> value(reader.Read(*response_body));
+  std::unique_ptr<const base::Value> value(
+      reader.ReadDeprecated(*response_body));
   const base::DictionaryValue* dictionary_value = NULL;
 
   if (!value || !value->GetAsDictionary(&dictionary_value)) {
diff --git a/chrome/browser/printing/cloud_print/privet_confirm_api_flow_unittest.cc b/chrome/browser/printing/cloud_print/privet_confirm_api_flow_unittest.cc
index 4e84482..09190ca 100644
--- a/chrome/browser/printing/cloud_print/privet_confirm_api_flow_unittest.cc
+++ b/chrome/browser/printing/cloud_print/privet_confirm_api_flow_unittest.cc
@@ -50,14 +50,14 @@
   EXPECT_CALL(delegate, Callback(GCDApiFlow::SUCCESS)).Times(1);
 
   std::unique_ptr<base::Value> value =
-      base::JSONReader::Read(kSampleConfirmResponse);
+      base::JSONReader::ReadDeprecated(kSampleConfirmResponse);
   const base::DictionaryValue* dictionary = NULL;
   ASSERT_TRUE(value->GetAsDictionary(&dictionary));
   confirmation.OnGCDApiFlowComplete(*dictionary);
 
   EXPECT_CALL(delegate, Callback(GCDApiFlow::ERROR_FROM_SERVER)).Times(1);
 
-  value = base::JSONReader::Read(kFailedConfirmResponse);
+  value = base::JSONReader::ReadDeprecated(kFailedConfirmResponse);
   ASSERT_TRUE(value->GetAsDictionary(&dictionary));
   confirmation.OnGCDApiFlowComplete(*dictionary);
 }
diff --git a/chrome/browser/printing/cloud_print/privet_http_unittest.cc b/chrome/browser/printing/cloud_print/privet_http_unittest.cc
index 6dfa08e..e32cd78 100644
--- a/chrome/browser/printing/cloud_print/privet_http_unittest.cc
+++ b/chrome/browser/printing/cloud_print/privet_http_unittest.cc
@@ -266,7 +266,7 @@
 // string.
 std::string NormalizeJson(const std::string& json) {
   std::string result = json;
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(result);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(result);
   DCHECK(value) << result;
   base::JSONWriter::Write(*value, &result);
   return result;
diff --git a/chrome/browser/profiles/profile_browsertest.cc b/chrome/browser/profiles/profile_browsertest.cc
index dcdf687..137a2370 100644
--- a/chrome/browser/profiles/profile_browsertest.cc
+++ b/chrome/browser/profiles/profile_browsertest.cc
@@ -562,7 +562,7 @@
   if (!base::ReadFileToString(prefs_path, &prefs))
     return std::string();
 
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(prefs);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(prefs);
   if (!value)
     return std::string();
 
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 5a4a96c..9ab37ce 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -30,6 +30,8 @@
 #include "base/trace_event/trace_event.h"
 #include "base/value_conversions.h"
 #include "build/build_config.h"
+#include "chrome/browser/accessibility/accessibility_labels_service.h"
+#include "chrome/browser/accessibility/accessibility_labels_service_factory.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/bookmarks/startup_task_runner_service_factory.h"
 #include "chrome/browser/browser_process.h"
@@ -1363,6 +1365,8 @@
 #if defined(OS_WIN) && BUILDFLAG(ENABLE_DICE_SUPPORT)
   signin_util::SigninWithCredentialProviderIfPossible(profile);
 #endif
+
+  AccessibilityLabelsServiceFactory::GetForProfile(profile)->Init();
 }
 
 void ProfileManager::DoFinalInitLogging(Profile* profile) {
diff --git a/chrome/browser/resources/about_sys/about_sys.css b/chrome/browser/resources/about_sys/about_sys.css
index eabfa210..8b626b540 100644
--- a/chrome/browser/resources/about_sys/about_sys.css
+++ b/chrome/browser/resources/about_sys/about_sys.css
@@ -169,3 +169,17 @@
 .number-expanded .stat-value {
   display: auto;
 }
+
+.spinner {
+  -webkit-animation: rotate 2s linear infinite;
+  border: 4px solid rgb(239, 243, 255);
+  border-radius: 50%;
+  border-top: 4px solid rgb(82, 150, 222);
+  height: 20px;
+  width: 20px;
+}
+
+@-webkit-keyframes rotate {
+  0% { transform: rotate(0deg); }
+  100% { transform: rotate(360deg); }
+}
diff --git a/chrome/browser/resources/about_sys/about_sys.html b/chrome/browser/resources/about_sys/about_sys.html
index 796eb29..412a568 100644
--- a/chrome/browser/resources/about_sys/about_sys.html
+++ b/chrome/browser/resources/about_sys/about_sys.html
@@ -4,11 +4,13 @@
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
     <title>$i18n{title}</title>
     <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
-    <link rel="stylesheet" href="about_sys.css">
+    <link rel="stylesheet" href="chrome://system/about_sys.css">
     <script src="chrome://resources/js/util.js"></script>
     <script src="chrome://resources/js/i18n_template_no_process.js"></script>
     <script src="chrome://resources/js/jstemplate_compiled.js"></script>
-    <script src="about_sys.js"></script>
+    <script src="chrome://resources/js/load_time_data.js"></script>
+    <script src="chrome://system/about_sys.js"></script>
+    <script src="chrome://system/strings.js"></script>
   </head>
   <body>
     <div id="header">
@@ -17,26 +19,13 @@
     </div>
     <div id="content">
       <h2 id="tableTitle">$i18n{tableTitle}</h2>
-      <div id="anchor" jscontent="anchor"></div>
       <button id="expandAll" class="global-button">$i18n{expandAllBtn}</button>
       <button id="collapseAll" class="global-button">
         $i18n{collapseAllBtn}
       </button>
       <p id="status"></p>
+      <div class="spinner" id="loadingIndicator"></div>
       <table class="list" id="details">
-        <tr jsselect="details">
-          <td class="name">
-            <div class="stat-name" jscontent="statName"></div>
-          </td>
-          <td class="button-cell">
-            <button jsvalues="id:statName + '-value-btn'"
-              class="expand-status"></button>
-          </td>
-          <td class="number">
-            <div class="stat-value" jscontent="statValue"
-              jsvalues="id:statName + '-value'"></div>
-          </td>
-        </tr>
       </table>
     </div>
   </body>
diff --git a/chrome/browser/resources/about_sys/about_sys.js b/chrome/browser/resources/about_sys/about_sys.js
index 0246954..097abdb 100644
--- a/chrome/browser/resources/about_sys/about_sys.js
+++ b/chrome/browser/resources/about_sys/about_sys.js
@@ -77,26 +77,6 @@
 }
 
 /**
- * Collapse only those log items with multi-line values.
- */
-function collapseMultiLineStrings() {
-  const valueDivs = document.getElementsByClassName('stat-value');
-  const nameDivs = document.getElementsByClassName('stat-name');
-  for (let i = 0; i < valueDivs.length; i++) {
-    const button = getButtonForValueDiv(valueDivs[i]);
-    button.onclick = changeCollapsedStatus;
-    if (valueDivs[i].scrollHeight > (nameDivs[i].scrollHeight * 2)) {
-      button.className = '';
-      button.textContent = loadTimeData.getString('expandBtn');
-      valueDivs[i].parentNode.className = 'number-collapsed';
-    } else {
-      button.className = 'button-hidden';
-      valueDivs[i].parentNode.className = 'number';
-    }
-  }
-}
-
-/**
  * Read in a log asynchronously, calling parseSystemLog if successful.
  * @param {File} file The file to read.
  */
@@ -120,6 +100,84 @@
 }
 
 /**
+ * For a particular log entry, create the DOM node representing it in the
+ * log entry table.
+ * @param{log} A dictionary with the keys statName and statValue
+ * @return{Element} The DOM node for the given log entry.
+ */
+function createNodeForLogEntry(log) {
+  const row = document.createElement('tr');
+
+  const nameCell = document.createElement('td');
+  nameCell.className = 'name';
+  const nameDiv = document.createElement('div');
+  nameDiv.className = 'stat-name';
+  nameDiv.textContent = log.statName;
+  nameCell.appendChild(nameDiv);
+  row.appendChild(nameCell);
+
+  const buttonCell = document.createElement('td');
+  buttonCell.className = 'button-cell';
+  const button = document.createElement('button');
+  button.id = log.statName + '-value-btn';
+  button.className = 'expand-status';
+  button.onclick = changeCollapsedStatus;
+  buttonCell.appendChild(button);
+  row.appendChild(buttonCell);
+
+  const valueCell = document.createElement('td');
+  const valueDiv = document.createElement('div');
+  valueDiv.className = 'stat-value';
+  valueDiv.id = log.statName + '-value';
+  valueDiv.textContent = log.statValue;
+  valueCell.appendChild(valueDiv);
+  row.appendChild(valueCell);
+
+  if (log.statValue.length > 200) {
+    button.className = '';
+    button.textContent = loadTimeData.getString('expandBtn');
+    valueCell.className = 'number-collapsed';
+  } else {
+    button.className = 'button-hidden';
+    valueCell.className = 'number';
+  }
+
+  return row;
+}
+
+/**
+ * Given a list of log entries, replace the contents of the log entry table
+ * with those entries. The log entries are passed as a list of dictionaries
+ * containing the keys statName and statValue.
+ * @param {systemInfo} The log entries to insert into the DOM.
+ */
+function updateLogEntries(systemInfo) {
+  const fragment = document.createDocumentFragment();
+  systemInfo.forEach(logEntry => {
+    const node = createNodeForLogEntry(logEntry);
+    fragment.appendChild(node);
+  });
+  const table = $('details');
+
+  // Delete any existing log entries in the table
+  table.innerHtml = '';
+  table.appendChild(fragment);
+}
+
+/**
+ * Callback called by system_info_ui.cc when it has finished fetching
+ * system info. The log entries are passed as a list of dictionaries containing
+ * the keys statName and statValue.
+ * @param {systemInfo} The fetched log entries.
+ */
+function returnSystemInfo(systemInfo) {
+  updateLogEntries(systemInfo);
+  const spinner = $('loadingIndicator');
+  spinner.style.display = 'none';
+  spinner.style.webkitAnimationPlayState = 'paused';
+}
+
+/**
  * Convert text-based log into list of name-value pairs.
  * @param {string} text The raw text of a log.
  * @return {boolean} True if the log was parsed successfully.
@@ -173,15 +231,15 @@
     details.push({'statName': name, 'statValue': value});
   }
 
-  const templateData = {'details': details};
-  jstProcess(new JsEvalContext(templateData), $('t'));
 
-  collapseMultiLineStrings();
+
+  updateLogEntries(details);
+
   return true;
 }
 
 document.addEventListener('DOMContentLoaded', function() {
-  jstProcess(loadTimeData.createJsEvalContext(), $('t'));
+  chrome.send('requestSystemInfo');
 
   $('collapseAll').onclick = collapseAll;
   $('expandAll').onclick = expandAll;
@@ -189,6 +247,4 @@
   const tp = $('t');
   tp.addEventListener('dragover', handleDragOver, false);
   tp.addEventListener('drop', handleDrop, false);
-
-  collapseMultiLineStrings();
 });
diff --git a/chrome/browser/resources/browser_switcher/app.js b/chrome/browser/resources/browser_switcher/app.js
index e735c47..c237302 100644
--- a/chrome/browser/resources/browser_switcher/app.js
+++ b/chrome/browser/resources/browser_switcher/app.js
@@ -24,6 +24,17 @@
 
   /** @override */
   attached: function() {
+    const proxy = browser_switcher.BrowserSwitcherProxyImpl.getInstance();
+
+    // If '?done=...' is specified in the URL, this tab was-reopened, or the
+    // entire browser was closed by LBS and re-opened. In that case, go to NTP
+    // instead.
+    const done = (new URLSearchParams(window.location.search)).has('done');
+    if (done) {
+      proxy.gotoNewTabPage();
+      return;
+    }
+
     // Sanity check the URL to make sure nothing really funky is going on.
     const anchor = document.createElement('a');
     anchor.href = this.url_;
@@ -31,7 +42,10 @@
       return;
     }
 
-    const proxy = browser_switcher.BrowserSwitcherProxyImpl.getInstance();
+    // Mark this page with '?done=...' so that restoring the tab doesn't
+    // immediately re-trigger LBS.
+    history.pushState({}, '', '/?done=true');
+
     proxy.launchAlternativeBrowserAndCloseTab(this.url_);
   },
 });
diff --git a/chrome/browser/resources/browser_switcher/browser_switcher_proxy.js b/chrome/browser/resources/browser_switcher/browser_switcher_proxy.js
index f78f4a5..4c38e59 100644
--- a/chrome/browser/resources/browser_switcher/browser_switcher_proxy.js
+++ b/chrome/browser/resources/browser_switcher/browser_switcher_proxy.js
@@ -11,6 +11,8 @@
      *     never resolve, because the tab closes if this succeeds.
      */
     launchAlternativeBrowserAndCloseTab(url) {}
+
+    gotoNewTabPage() {}
   }
 
   /** @implements {settings.BrowserSwitcherProxy} */
@@ -19,6 +21,11 @@
     launchAlternativeBrowserAndCloseTab(url) {
       return cr.sendWithPromise('launchAlternativeBrowserAndCloseTab', url);
     }
+
+    /** @override */
+    gotoNewTabPage() {
+      chrome.send('gotoNewTabPage');
+    }
   }
 
   cr.addSingletonGetter(BrowserSwitcherProxyImpl);
diff --git a/chrome/browser/resources/chromeos/arc_support/main.html b/chrome/browser/resources/chromeos/arc_support/main.html
index a3ebb05..a4278b3 100644
--- a/chrome/browser/resources/chromeos/arc_support/main.html
+++ b/chrome/browser/resources/chromeos/arc_support/main.html
@@ -11,45 +11,47 @@
   <link rel="import" href="chrome://resources/cr_elements/cr_checkbox/cr_checkbox.html">
   <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
   <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
-  <style is="custom-style" include="iron-flex iron-flex-alignment">
-    paper-button {
-      border-radius: 4px;
-      border-style: solid;
-      border-width: 2px;
-      height: 32px; /* = 28px + 2 * 2px border */
-      margin: 0;
-      padding: 0;
-    }
-    paper-button.blue {
-      border-color: transparent;
-    }
-    paper-button.white {
-      border-color: rgba(0, 0, 0, 0.1);
-    }
-    paper-button[focused] {
-      border-color: rgba(66, 133, 244, 0.4); /* #4284f4 */
-    }
-    paper-button .container {
-      align-items: center;
-      align-self: stretch;
-      border-radius: 2px;
-      display: flex;
-      font: Roboto, sans-serif;
-      font-size: 12px;
-      font-weight: 500;
-      justify-content: center;
-      padding: 0 16px;
-      text-transform: none;
-    }
-    paper-button.white .container {
-      background-color: white;
-      color: rgba(0, 0, 0, 0.54);
-    }
-    paper-button.blue .container {
-      background-color: rgb(66, 133, 244); /* #4285f4 */
-      color: white;
-    }
-  </style>
+  <custom-style>
+    <style is="custom-style" include="iron-flex iron-flex-alignment">
+      paper-button {
+        border-radius: 4px;
+        border-style: solid;
+        border-width: 2px;
+        height: 32px; /* = 28px + 2 * 2px border */
+        margin: 0;
+        padding: 0;
+      }
+      paper-button.blue {
+        border-color: transparent;
+      }
+      paper-button.white {
+        border-color: rgba(0, 0, 0, 0.1);
+      }
+      paper-button[focused] {
+        border-color: rgba(66, 133, 244, 0.4); /* #4284f4 */
+      }
+      paper-button .container {
+        align-items: center;
+        align-self: stretch;
+        border-radius: 2px;
+        display: flex;
+        font: Roboto, sans-serif;
+        font-size: 12px;
+        font-weight: 500;
+        justify-content: center;
+        padding: 0 16px;
+        text-transform: none;
+      }
+      paper-button.white .container {
+        background-color: white;
+        color: rgba(0, 0, 0, 0.54);
+      }
+      paper-button.blue .container {
+        background-color: rgb(66, 133, 244); /* #4285f4 */
+        color: white;
+      }
+    </style>
+  </custom-style>
   <link rel="stylesheet" href="main.css">
   <link rel="stylesheet" href="progressbar.css">
   <script src="chrome://resources/js/load_time_data.js"></script>
diff --git a/chrome/browser/resources/history/shared_vars.html b/chrome/browser/resources/history/shared_vars.html
index b4cc65bd..73ce890 100644
--- a/chrome/browser/resources/history/shared_vars.html
+++ b/chrome/browser/resources/history/shared_vars.html
@@ -34,6 +34,7 @@
 
   html[dark] {
     --history-item-time-color: var(--cr-secondary-text-color);
+    --interactive-color: var(--google-blue-refresh-300);
     --separator-color: var(--cr-separator-color);
     --sidebar-footer-text-color: rgba(255, 255, 255, 0.6);
     --sidebar-unselected-color: var(--cr-secondary-text-color);
diff --git a/chrome/browser/resources/md_extensions/BUILD.gn b/chrome/browser/resources/md_extensions/BUILD.gn
index 702dcde..911d329 100644
--- a/chrome/browser/resources/md_extensions/BUILD.gn
+++ b/chrome/browser/resources/md_extensions/BUILD.gn
@@ -258,6 +258,7 @@
     "activity_log:activity_log",
     "activity_log:activity_log_history",
     "activity_log:activity_log_item",
+    "activity_log:activity_log_stream",
     "//ui/webui/resources/cr_elements/cr_drawer:cr_drawer",
     "//ui/webui/resources/cr_elements/cr_view_manager:cr_view_manager",
     "//ui/webui/resources/js:assert",
@@ -329,6 +330,7 @@
     ":toolbar",
     "activity_log:activity_log",
     "activity_log:activity_log_history",
+    "activity_log:activity_log_stream",
     "//ui/webui/resources/js:assert",
     "//ui/webui/resources/js:cr",
     "//ui/webui/resources/js:load_time_data",
diff --git a/chrome/browser/resources/md_extensions/activity_log/BUILD.gn b/chrome/browser/resources/md_extensions/activity_log/BUILD.gn
index 152e0f4..acfc245f7 100644
--- a/chrome/browser/resources/md_extensions/activity_log/BUILD.gn
+++ b/chrome/browser/resources/md_extensions/activity_log/BUILD.gn
@@ -9,6 +9,7 @@
     ":activity_log",
     ":activity_log_history",
     ":activity_log_item",
+    ":activity_log_stream",
   ]
 }
 
@@ -27,9 +28,17 @@
   externs_list = [ "$externs_path/activity_log_private.js" ]
 }
 
+js_library("activity_log_stream") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+  ]
+  externs_list = [ "$externs_path/activity_log_private.js" ]
+}
+
 js_library("activity_log") {
   deps = [
     ":activity_log_history",
+    ":activity_log_stream",
     "..:navigation_helper",
     "//ui/webui/resources/cr_elements:cr_container_shadow_behavior",
     "//ui/webui/resources/cr_elements/cr_search_field:cr_search_field",
diff --git a/chrome/browser/resources/md_extensions/activity_log/activity_log.html b/chrome/browser/resources/md_extensions/activity_log/activity_log.html
index 39cf5c0..cec40928 100644
--- a/chrome/browser/resources/md_extensions/activity_log/activity_log.html
+++ b/chrome/browser/resources/md_extensions/activity_log/activity_log.html
@@ -3,17 +3,21 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_container_shadow_behavior.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_search_field/cr_search_field.html">
 <link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
+<link rel="import" href="chrome://resources/cr_elements/paper_tabs_style_css.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-tabs/paper-tabs.html">
 <link rel="import" href="activity_log_history.html">
+<link rel="import" href="activity_log_stream.html">
 <link rel="import" href="../navigation_helper.html">
 <link rel="import" href="../shared_style.html">
 
 <dom-module id="extensions-activity-log">
   <template>
-    <style include="iron-flex cr-shared-style shared-style paper-button-style">
+    <style include="shared-style paper-button-style paper-tabs-style">
       #activity-log-heading {
         flex-grow: 1;
         margin-inline-start: 16px;
@@ -26,6 +30,11 @@
       cr-search-field  {
         padding-inline-end: 8px;
       }
+
+      paper-tabs {
+        font-size: inherit;
+        height: 40px;
+      }
     </style>
     <div class="page-container" id="container">
       <div class="page-content">
@@ -43,11 +52,31 @@
             $i18n{clearActivities}
           </paper-button>
         </div>
-        <template is="dom-if" if="[[showHistory_]]" restamp>
-          <activity-log-history extension-id="[[extensionId]]"
-              delegate="[[delegate]]" last-search="[[lastSearch_]]">
-          </activity-log-history>
-        </template>
+        <paper-tabs noink selected="{{selectedSubpage_}}">
+          <paper-tab id="history-tab">
+            $i18n{activityLogHistoryTabHeading}
+          </paper-tab>
+          <paper-tab id="real-time-tab">
+            $i18n{activityLogStreamTabHeading}
+          </paper-tab>
+        </paper-tabs>
+        <iron-pages selected="[[selectedSubpage_]]">
+          <div>
+            <template is="dom-if"
+                if="[[isHistoryTabSelected_(selectedSubpage_)]]" restamp>
+              <activity-log-history extension-id="[[extensionId]]"
+                  delegate="[[delegate]]" last-search="[[lastSearch_]]">
+              </activity-log-history>
+            </template>
+          </div>
+          <div>
+            <template is="dom-if"
+                if="[[isStreamTabSelected_(selectedSubpage_)]]" restamp>
+              <activity-log-stream>
+              </activity-log-stream>
+            </template>
+          </div>
+        </iron-pages>
       </div>
     </div>
   </template>
diff --git a/chrome/browser/resources/md_extensions/activity_log/activity_log.js b/chrome/browser/resources/md_extensions/activity_log/activity_log.js
index 1269cd4a..4e0256b1 100644
--- a/chrome/browser/resources/md_extensions/activity_log/activity_log.js
+++ b/chrome/browser/resources/md_extensions/activity_log/activity_log.js
@@ -2,6 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+/**
+ * Subpages/views for the activity log. HISTORY shows extension activities
+ * fetched from the activity log database with some fields such as args
+ * omitted. STREAM displays extension activities in a more verbose format in
+ * real time. NONE is used when user is away from the page.
+ * @enum {number}
+ */
+const ActivityLogSubpage = {
+  NONE: -1,
+  HISTORY: 0,
+  STREAM: 1
+};
+
 cr.define('extensions', function() {
   'use strict';
 
@@ -25,10 +38,10 @@
         value: '',
       },
 
-      /** @private */
-      showHistory_: {
-        type: Boolean,
-        value: true,
+      /** @private {!ActivityLogSubpage} */
+      selectedSubpage_: {
+        type: Number,
+        value: ActivityLogSubpage.NONE,
       },
     },
 
@@ -38,27 +51,46 @@
     },
 
     /**
-     * Focuses the back button when page is loaded.
+     * Focuses the back button when page is loaded and set the activie view to
+     * be HISTORY when we navigate to the page.
      * @private
      */
     onViewEnterStart_: function() {
-      this.showHistory_ = true;
+      this.selectedSubpage_ = ActivityLogSubpage.HISTORY;
       Polymer.RenderStatus.afterNextRender(
           this, () => cr.ui.focusWithoutInk(this.$.closeButton));
     },
 
     /**
-     * Set |showHistory_| to false to remove activity-log-history from the DOM.
+     * Set |selectedSubpage_| to NONE to remove the active view from the DOM.
      * @private
      */
     onViewExitFinish_: function() {
-      this.showHistory_ = false;
+      this.selectedSubpage_ = ActivityLogSubpage.NONE;
+    },
+
+    /**
+     * @private
+     * @return {boolean}
+     */
+    isHistoryTabSelected_: function() {
+      return this.selectedSubpage_ === ActivityLogSubpage.HISTORY;
+    },
+
+    /**
+     * @private
+     * @return {boolean}
+     */
+    isStreamTabSelected_: function() {
+      return this.selectedSubpage_ === ActivityLogSubpage.STREAM;
     },
 
     /** @private */
     onClearButtonTap_: function() {
-      const activityLogHistory = this.$$('activity-log-history');
-      activityLogHistory.clearActivities();
+      if (this.selectedSubpage_ === ActivityLogSubpage.HISTORY) {
+        const activityLogHistory = this.$$('activity-log-history');
+        activityLogHistory.clearActivities();
+      }
     },
 
     /** @private */
diff --git a/chrome/browser/resources/md_extensions/activity_log/activity_log_history.html b/chrome/browser/resources/md_extensions/activity_log/activity_log_history.html
index 6422d50..27604880 100644
--- a/chrome/browser/resources/md_extensions/activity_log/activity_log_history.html
+++ b/chrome/browser/resources/md_extensions/activity_log/activity_log_history.html
@@ -3,25 +3,19 @@
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/html/promise_resolver.html">
 <link rel="import" href="activity_log_item.html">
+<link rel="import" href="../shared_style.html">
 
 <dom-module id="activity-log-history">
   <template>
-    <style>
-      #loading-activities,
-      #no-activities {
-        color: var(--md-loading-message-color);
-        font-size: 123%;  /* Should be 16px when 100% is 13px. */
-        font-weight: 500;
-        margin-top: 80px;
-        text-align: center;
-      }
-    </style>
-    <div id="loading-activities" hidden$="[[!shouldShowLoadingMessage_(
-        pageState_)]]">
+    <style include="shared-style"></style>
+    <div id="loading-activities" class="activity-message"
+        hidden$="[[!shouldShowLoadingMessage_(
+            pageState_)]]">
       <span>$i18n{loadingActivities}</span>
     </div>
-    <div id="no-activities" hidden$="[[!shouldShowEmptyActivityLogMessage_(
-        pageState_, activityData_)]]">
+    <div id="no-activities" class="activity-message"
+        hidden$="[[!shouldShowEmptyActivityLogMessage_(
+            pageState_, activityData_)]]">
       <span>$i18n{noActivities}</span>
     </div>
     <div id="activity-list"
diff --git a/chrome/browser/resources/md_extensions/activity_log/activity_log_stream.html b/chrome/browser/resources/md_extensions/activity_log/activity_log_stream.html
new file mode 100644
index 0000000..f83fe156
--- /dev/null
+++ b/chrome/browser/resources/md_extensions/activity_log/activity_log_stream.html
@@ -0,0 +1,34 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
+<link rel="import" href="../shared_style.html">
+
+<dom-module id="activity-log-stream">
+  <template>
+    <style include="shared-style paper-button-style">
+      #activity-log-stream-header {
+        justify-content: flex-end;
+      }
+    </style>
+    <div id="activity-log-stream-header" class="page-header">
+      <paper-button id="toggle-stream-button" on-click="onToggleButtonTap_">
+        <span hidden$="[[isStreamOn_]]">
+          $i18n{startActivityStream}
+        </span>
+        <span hidden$="[[!isStreamOn_]]">
+          $i18n{stopActivityStream}
+        </span>
+      </paper-button>
+    </div>
+    <div id="empty-stream-message" class="activity-message">
+      <span hidden$="[[isStreamOn_]]">
+        $i18n{emptyStreamStopped}
+      </span>
+      <span hidden$="[[!isStreamOn_]]">
+        $i18n{emptyStreamStarted}
+      </span>
+    </div>
+  </template>
+  <script src="activity_log_stream.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/md_extensions/activity_log/activity_log_stream.js b/chrome/browser/resources/md_extensions/activity_log/activity_log_stream.js
new file mode 100644
index 0000000..c034683b
--- /dev/null
+++ b/chrome/browser/resources/md_extensions/activity_log/activity_log_stream.js
@@ -0,0 +1,46 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('extensions', function() {
+  'use strict';
+
+  const ActivityLogStream = Polymer({
+    is: 'activity-log-stream',
+
+    properties: {
+      /** @private */
+      isStreamOn_: {
+        type: Boolean,
+        value: false,
+      },
+    },
+
+    /** @override */
+    attached: function() {
+      this.isStreamOn_ = true;
+    },
+
+    /** @override */
+    detached: function() {
+      this.isStreamOn_ = false;
+    },
+
+    /** @return {boolean} */
+    isStreamOnForTest() {
+      // TODO(kelvinjiang): remove this method when the event listener has been
+      // hooked up to this component (in the CL after this one). At that time,
+      // onExtensionActivity.hasListeners() will be used instead.
+      return this.isStreamOn_;
+    },
+
+    /** @private */
+    onToggleButtonTap_: function() {
+      this.isStreamOn_ = !this.isStreamOn_;
+    },
+  });
+
+  return {
+    ActivityLogStream: ActivityLogStream,
+  };
+});
diff --git a/chrome/browser/resources/md_extensions/extensions_resources.grd b/chrome/browser/resources/md_extensions/extensions_resources.grd
index d073d49..54e241a 100644
--- a/chrome/browser/resources/md_extensions/extensions_resources.grd
+++ b/chrome/browser/resources/md_extensions/extensions_resources.grd
@@ -47,6 +47,12 @@
       <structure name="IDR_MD_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_ITEM_JS"
                  file="activity_log/activity_log_item.js"
                  type="chrome_html" />
+      <structure name="IDR_MD_EXTENSIONS_ACTIVITY_LOG_STREAM_HTML"
+                 file="activity_log/activity_log_stream.html"
+                 type="chrome_html" />
+      <structure name="IDR_MD_EXTENSIONS_ACTIVITY_LOG_STREAM_JS"
+                 file="activity_log/activity_log_stream.js"
+                 type="chrome_html" />
       <structure name="IDR_MD_EXTENSIONS_DETAIL_VIEW_HTML"
                  file="detail_view.html"
                  type="chrome_html" />
diff --git a/chrome/browser/resources/md_extensions/shared_style.html b/chrome/browser/resources/md_extensions/shared_style.html
index b6f3208..8b80b9d 100644
--- a/chrome/browser/resources/md_extensions/shared_style.html
+++ b/chrome/browser/resources/md_extensions/shared_style.html
@@ -9,6 +9,14 @@
         text-decoration: none;
       }
 
+      .activity-message {
+        color: var(--md-loading-message-color);
+        font-size: 123%;  /* Should be 16px when 100% is 13px. */
+        font-weight: 500;
+        margin-top: 80px;
+        text-align: center;
+      }
+
       .page-container {
         height: 100%;
         overflow: overlay;
diff --git a/chrome/browser/resources/signin/signin_email_confirmation/signin_email_confirmation.html b/chrome/browser/resources/signin/signin_email_confirmation/signin_email_confirmation.html
index 2b15ab2..d3865fd 100644
--- a/chrome/browser/resources/signin/signin_email_confirmation/signin_email_confirmation.html
+++ b/chrome/browser/resources/signin/signin_email_confirmation/signin_email_confirmation.html
@@ -60,7 +60,7 @@
         }
 </if>
       </style>
-    <custom-style>
+    </custom-style>
   </head>
   <body>
     <div class="container">
diff --git a/chrome/browser/resources/signin/signin_error/signin_error.html b/chrome/browser/resources/signin/signin_error/signin_error.html
index b540038..5e2c8b5a 100644
--- a/chrome/browser/resources/signin/signin_error/signin_error.html
+++ b/chrome/browser/resources/signin/signin_error/signin_error.html
@@ -70,7 +70,7 @@
         }
 </if>
       </style>
-    <custom-style>
+    </custom-style>
   </head>
   <body>
     <div class="container">
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.html b/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.html
index 0f97022..0b8da5b 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.html
+++ b/chrome/browser/resources/welcome/onboarding_welcome/set_as_default/nux_set_as_default.html
@@ -34,6 +34,7 @@
         content: -webkit-image-set(
           url(../images/set_as_default_illustration_1x.png) 1x,
           url(../images/set_as_default_illustration_2x.png) 2x);
+        margin: auto;
         width: 454px;
       }
 
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/shared/chooser_shared_css.html b/chrome/browser/resources/welcome/onboarding_welcome/shared/chooser_shared_css.html
index 07e9272..23499fb 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/shared/chooser_shared_css.html
+++ b/chrome/browser/resources/welcome/onboarding_welcome/shared/chooser_shared_css.html
@@ -23,16 +23,16 @@
         display: inline-flex;
         flex-direction: column;
         font-family: inherit;
-        height: 84px;
+        height: 5.25rem;
         justify-content: center;
         outline: 0;
         position: relative;
         vertical-align: bottom;
-        width: 104px;
+        width: 6.5rem;
       }
 
       .option:not(:first-of-type) {
-        margin-inline-start: 24px;
+        margin-inline-start: 1.5rem;
       }
 
       .option.keyboard-focused:focus {
@@ -51,18 +51,18 @@
         background-position: center;
         background-repeat: no-repeat;
         background-size: contain;
-        height: 32px;
+        height: 2rem;
         margin: auto;
-        width: 32px;
+        width: 2rem;
       }
 
       .option .option-icon-shadow {
         background-color: var(--google-grey-refresh-100);
         border-radius: 50%;
         display: flex;
-        height: 48px;
-        margin-bottom: 4px;
-        width: 48px;
+        height: 3rem;
+        margin-bottom: 0.25rem;
+        width: 3rem;
       }
 
       .option iron-icon {
@@ -70,12 +70,12 @@
         background: lightgrey;
         border-radius: 50%;
         display: none;
-        height: 12px;
+        height: 0.75rem;
         margin: 0;
         position: absolute;
-        right: 6px;
-        top: 6px;
-        width: 12px;
+        right: 0.375rem;
+        top: 0.375rem;
+        width: 0.75rem;
       }
 
       .option.keyboard-focused:focus iron-icon[icon='cr:check'],
@@ -97,14 +97,18 @@
       .button-bar {
         display: flex;
         justify-content: space-between;
-        margin-top: 64px;
+        margin-top: 4rem;
+      }
+
+      :host-context([dir=rtl]) iron-icon {
+        transform: rotate(180deg);
       }
 
       iron-icon[icon='cr:chevron-right'] {
-        height: 20px;
-        margin-left: 6px;
-        margin-right: -10px;
-        width: 20px;
+        height: 1.25rem;
+        margin-inline-end: -0.625rem;
+        margin-inline-start: 0.375rem;
+        width: 1.25rem;
       }
     </style>
   </template>
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
index c14a1ed..b7c3d11 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -163,12 +163,16 @@
         ->SetTestingFactory(
             browser_context(),
             base::BindRepeating(&BuildSafeBrowsingPrivateEventRouter));
+
+    identity_test_env_profile_adaptor_ =
+        std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile());
   }
 
   void TearDown() override {
     base::RunLoop().RunUntilIdle();
     service_.reset();
     request_ = nullptr;
+    identity_test_env_profile_adaptor_.reset();
     content_setting_map_->ShutdownOnUIThread();
     ChromeRenderViewHostTestHarness::TearDown();
   }
@@ -190,9 +194,6 @@
 
   content::BrowserContext* CreateBrowserContext() override {
     TestingProfile::Builder builder;
-    builder.AddTestingFactory(
-        ChromeSigninClientFactory::GetInstance(),
-        base::BindRepeating(&signin::BuildTestSigninClient));
     std::unique_ptr<TestingProfile> profile =
         IdentityTestEnvironmentProfileAdaptor::
             CreateProfileForIdentityTestEnvironment(builder);
@@ -236,21 +237,15 @@
   }
 
   CoreAccountInfo SetPrimaryAccount(const std::string& email) {
-    IdentityTestEnvironmentProfileAdaptor identity_test_env_profile_adaptor(
-        profile());
-    return identity_test_env_profile_adaptor.identity_test_env()
-        ->SetPrimaryAccount(email);
+    return identity_test_env()->SetPrimaryAccount(email);
   }
 
   void SetUpSyncAccount(const std::string& hosted_domain,
                         const CoreAccountInfo& account_info) {
-    IdentityTestEnvironmentProfileAdaptor identity_test_env_profile_adaptor(
-        profile());
-    identity_test_env_profile_adaptor.identity_test_env()
-        ->SimulateSuccessfulFetchOfAccountInfo(
-            account_info.account_id, account_info.email, account_info.gaia,
-            hosted_domain, "full_name", "given_name", "locale",
-            "http://picture.example.com/picture.jpg");
+    identity_test_env()->SimulateSuccessfulFetchOfAccountInfo(
+        account_info.account_id, account_info.email, account_info.gaia,
+        hosted_domain, "full_name", "given_name", "locale",
+        "http://picture.example.com/picture.jpg");
   }
 
   void PrepareRequest(
@@ -272,12 +267,18 @@
     return request_ ? request_->throttles_.size() : 0u;
   }
 
+  identity::IdentityTestEnvironment* identity_test_env() {
+    return identity_test_env_profile_adaptor_->identity_test_env();
+  }
+
  protected:
   sync_preferences::TestingPrefServiceSyncable test_pref_service_;
   scoped_refptr<HostContentSettingsMap> content_setting_map_;
   std::unique_ptr<MockChromePasswordProtectionService> service_;
   scoped_refptr<PasswordProtectionRequest> request_;
   std::unique_ptr<LoginReputationClientResponse> verdict_;
+  std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
+      identity_test_env_profile_adaptor_;
   // Owned by KeyedServiceFactory.
   syncer::FakeUserEventService* fake_user_event_service_;
   extensions::TestEventRouter* test_event_router_;
diff --git a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector_unittest.cc
index 50f4d55..5a337a04 100644
--- a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector_unittest.cc
@@ -103,8 +103,7 @@
         /*render_process_id=*/0,
         /*render_view_id=*/0,
         /*render_frame_id=*/MSG_ROUTING_NONE,
-        /*is_main_frame=*/true,
-        /*allow_download=*/true,
+        /*is_main_frame=*/true, content::ResourceInterceptPolicy::kAllowAll,
         /*is_async=*/false, content::PREVIEWS_OFF,
         /*navigation_ui_data*/ nullptr);
 
diff --git a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.cc b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.cc
index af62eaf..4ac23184 100644
--- a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.cc
+++ b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.cc
@@ -197,7 +197,8 @@
 
   // Is the input parseable JSON?
   std::unique_ptr<base::DictionaryValue> domains_dict =
-      base::DictionaryValue::From(base::JSONReader::Read(domain_hashes_json));
+      base::DictionaryValue::From(
+          base::JSONReader::ReadDeprecated(domain_hashes_json));
   if (!domains_dict || domains_dict->empty())
     return CONFIG_ERROR_BAD_DOMAIN_HASHES_PARAM;
 
diff --git a/chrome/browser/safe_json_parser_browsertest.cc b/chrome/browser/safe_json_parser_browsertest.cc
index 96474f41..807cffc 100644
--- a/chrome/browser/safe_json_parser_browsertest.cc
+++ b/chrome/browser/safe_json_parser_browsertest.cc
@@ -61,8 +61,9 @@
     message_loop_runner_ = new content::MessageLoopRunner;
 
     std::string error;
-    std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-        json, base::JSON_PARSE_RFC, nullptr, &error);
+    std::unique_ptr<base::Value> value =
+        base::JSONReader::ReadAndReturnErrorDeprecated(
+            json, base::JSON_PARSE_RFC, nullptr, &error);
 
     SafeJsonParser::SuccessCallback success_callback;
     SafeJsonParser::ErrorCallback error_callback;
diff --git a/chrome/browser/safe_xml_parser_browsertest.cc b/chrome/browser/safe_xml_parser_browsertest.cc
index 466e28a..039c1a0 100644
--- a/chrome/browser/safe_xml_parser_browsertest.cc
+++ b/chrome/browser/safe_xml_parser_browsertest.cc
@@ -55,7 +55,7 @@
     base::RunLoop run_loop;
     std::unique_ptr<base::Value> expected_value;
     if (!expected_json.empty()) {
-      expected_value = base::JSONReader::Read(expected_json);
+      expected_value = base::JSONReader::ReadDeprecated(expected_json);
       DCHECK(expected_value) << "Bad test, incorrect JSON: " << expected_json;
     }
 
diff --git a/chrome/browser/sessions/better_session_restore_browsertest.cc b/chrome/browser/sessions/better_session_restore_browsertest.cc
index 67d5f77..bb00b86 100644
--- a/chrome/browser/sessions/better_session_restore_browsertest.cc
+++ b/chrome/browser/sessions/better_session_restore_browsertest.cc
@@ -528,8 +528,14 @@
 
 #if BUILDFLAG(ENABLE_BACKGROUND_MODE)
 
+// Flaky on Windows and Linux: https://crbug.com/931778.
+#if defined(OS_WIN) || defined(OS_LINUX)
+#define MAYBE_CookiesClearedOnBrowserClose DISABLED_CookiesClearedOnBrowserClose
+#else
+#define MAYBE_CookiesClearedOnBrowserClose CookiesClearedOnBrowserClose
+#endif
 IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest,
-                       CookiesClearedOnBrowserClose) {
+                       MAYBE_CookiesClearedOnBrowserClose) {
   StoreDataWithPage("cookies.html");
   // Normally cookies are restored.
   Browser* new_browser = QuitBrowserAndRestore(browser(), false);
@@ -552,8 +558,15 @@
 
 // Check that cookies are cleared on a wrench menu quit only if cookies are set
 // to current session only, regardless of whether background mode is enabled.
+// Flaky on Windows and Linux: https://crbug.com/931777
+#if defined(OS_WIN) || defined(OS_LINUX)
+#define MAYBE_CookiesClearedOnCloseAllBrowsers \
+  DISABLED_CookiesClearedOnCloseAllBrowsers
+#else
+#define MAYBE_CookiesClearedOnCloseAllBrowsers CookiesClearedOnCloseAllBrowsers
+#endif
 IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest,
-                       CookiesClearedOnCloseAllBrowsers) {
+                       MAYBE_CookiesClearedOnCloseAllBrowsers) {
   StoreDataWithPage("cookies.html");
   // Normally cookies are restored.
   Browser* new_browser = QuitBrowserAndRestore(browser(), true);
diff --git a/chrome/browser/sessions/session_data_deleter.cc b/chrome/browser/sessions/session_data_deleter.cc
index 5c40627..3670587 100644
--- a/chrome/browser/sessions/session_data_deleter.cc
+++ b/chrome/browser/sessions/session_data_deleter.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/dom_storage_context.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/storage_usage_info.h"
 #include "net/cookies/cookie_util.h"
@@ -37,7 +38,11 @@
   friend class base::RefCountedThreadSafe<SessionDataDeleter>;
   ~SessionDataDeleter();
 
-  bool OriginMatcher(const GURL& origin, storage::SpecialStoragePolicy* policy);
+  // Deletes the local storage described by |usages| for origins which are
+  // session-only.
+  void ClearSessionOnlyLocalStorage(
+      content::StoragePartition* storage_partition,
+      const std::vector<content::StorageUsageInfo>& usages);
 
   // Takes the result of a CookieManager::GetAllCookies() method, and
   // initiates deletion of all cookies that are session only by the
@@ -61,16 +66,10 @@
 
 void SessionDataDeleter::Run(content::StoragePartition* storage_partition) {
   if (storage_policy_.get() && storage_policy_->HasSessionOnlyOrigins()) {
-    // Cookies are not origin scoped, so they are handled separately.
-    const uint32_t removal_mask =
-        content::StoragePartition::REMOVE_DATA_MASK_ALL &
-        ~content::StoragePartition::REMOVE_DATA_MASK_COOKIES;
-    storage_partition->ClearData(
-        removal_mask, content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
-        base::BindRepeating(&SessionDataDeleter::OriginMatcher, this),
-        /*cookie_deletion_filter=*/nullptr,
-        /*perform_storage_cleanup=*/false, base::Time(), base::Time::Max(),
-        base::DoNothing());
+    storage_partition->GetDOMStorageContext()->GetLocalStorageUsage(
+        base::Bind(&SessionDataDeleter::ClearSessionOnlyLocalStorage,
+                   this,
+                   storage_partition));
   }
 
   storage_partition->GetNetworkContext()->GetCookieManager(
@@ -104,12 +103,6 @@
   // side of the pipe is closed, so all deletion requested will still occur.
 }
 
-bool SessionDataDeleter::OriginMatcher(const GURL& origin,
-                                       storage::SpecialStoragePolicy* policy) {
-  return policy->IsStorageSessionOnly(origin) &&
-         !policy->IsStorageProtected(origin);
-}
-
 void SessionDataDeleter::DeleteSessionOnlyOriginCookies(
     const std::vector<net::CanonicalCookie>& cookies) {
   auto delete_cookie_predicate =
@@ -127,6 +120,20 @@
 
 SessionDataDeleter::~SessionDataDeleter() {}
 
+void SessionDataDeleter::ClearSessionOnlyLocalStorage(
+    content::StoragePartition* storage_partition,
+    const std::vector<content::StorageUsageInfo>& usages) {
+  DCHECK(storage_policy_.get());
+  DCHECK(storage_policy_->HasSessionOnlyOrigins());
+  for (size_t i = 0; i < usages.size(); ++i) {
+    const content::StorageUsageInfo& usage = usages[i];
+    if (!storage_policy_->IsStorageSessionOnly(usage.origin.GetURL()))
+      continue;
+    storage_partition->GetDOMStorageContext()->DeleteLocalStorage(
+        usage.origin, base::DoNothing());
+  }
+}
+
 }  // namespace
 
 void DeleteSessionOnlyData(Profile* profile) {
diff --git a/chrome/browser/signin/chrome_signin_helper_unittest.cc b/chrome/browser/signin/chrome_signin_helper_unittest.cc
index 9983954..f3a27ece 100644
--- a/chrome/browser/signin/chrome_signin_helper_unittest.cc
+++ b/chrome/browser/signin/chrome_signin_helper_unittest.cc
@@ -77,7 +77,8 @@
                                                 TRAFFIC_ANNOTATION_FOR_TESTS);
   content::ResourceRequestInfo::AllocateForTesting(
       request_.get(), content::RESOURCE_TYPE_MAIN_FRAME, nullptr, -1, -1, -1,
-      true, false, true, content::PREVIEWS_OFF, nullptr);
+      true, content::ResourceInterceptPolicy::kAllowNone, true,
+      content::PREVIEWS_OFF, nullptr);
   net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
       kGaiaUrl, std::make_unique<TestRequestInterceptor>());
   request_->Start();
diff --git a/chrome/browser/signin/fake_account_fetcher_service_builder.cc b/chrome/browser/signin/fake_account_fetcher_service_builder.cc
deleted file mode 100644
index 4823cf4..0000000
--- a/chrome/browser/signin/fake_account_fetcher_service_builder.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/signin/fake_account_fetcher_service_builder.h"
-
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/suggestions/image_decoder_impl.h"
-#include "chrome/browser/signin/account_tracker_service_factory.h"
-#include "chrome/browser/signin/chrome_signin_client_factory.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "components/signin/core/browser/fake_account_fetcher_service.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
-
-// static
-std::unique_ptr<KeyedService> FakeAccountFetcherServiceBuilder::BuildForTests(
-    content::BrowserContext* context) {
-  FakeAccountFetcherService* service = new FakeAccountFetcherService();
-  Profile* profile = Profile::FromBrowserContext(context);
-  service->Initialize(ChromeSigninClientFactory::GetForProfile(profile),
-                      ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
-                      AccountTrackerServiceFactory::GetForProfile(profile),
-                      std::make_unique<suggestions ::ImageDecoderImpl>());
-  return std::unique_ptr<KeyedService>(service);
-}
diff --git a/chrome/browser/signin/fake_account_fetcher_service_builder.h b/chrome/browser/signin/fake_account_fetcher_service_builder.h
deleted file mode 100644
index 4a399a6..0000000
--- a/chrome/browser/signin/fake_account_fetcher_service_builder.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SIGNIN_FAKE_ACCOUNT_FETCHER_SERVICE_BUILDER_H_
-#define CHROME_BROWSER_SIGNIN_FAKE_ACCOUNT_FETCHER_SERVICE_BUILDER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-
-namespace content {
-class BrowserContext;
-}
-class KeyedService;
-
-class FakeAccountFetcherServiceBuilder {
- public:
-  static std::unique_ptr<KeyedService> BuildForTests(
-      content::BrowserContext* context);
-
- private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(FakeAccountFetcherServiceBuilder);
-};
-
-#endif  // CHROME_BROWSER_SIGNIN_FAKE_ACCOUNT_FETCHER_SERVICE_BUILDER_H_
diff --git a/chrome/browser/signin/signin_global_error_unittest.cc b/chrome/browser/signin/signin_global_error_unittest.cc
index 7fc6ce51..1a0ee10 100644
--- a/chrome/browser/signin/signin_global_error_unittest.cc
+++ b/chrome/browser/signin/signin_global_error_unittest.cc
@@ -81,11 +81,11 @@
   void SetAuthError(GoogleServiceAuthError::State state) {
     identity::IdentityTestEnvironment* identity_test_env =
         identity_test_env_profile_adaptor_->identity_test_env();
-    AccountInfo primary_account_info =
-        identity_test_env->identity_manager()->GetPrimaryAccountInfo();
+    std::string primary_account_id =
+        identity_test_env->identity_manager()->GetPrimaryAccountId();
 
     identity::UpdatePersistentErrorOfRefreshTokenForAccount(
-        identity_test_env->identity_manager(), primary_account_info.account_id,
+        identity_test_env->identity_manager(), primary_account_id,
         GoogleServiceAuthError(state));
   }
 
diff --git a/chrome/browser/signin/signin_profile_attributes_updater.cc b/chrome/browser/signin/signin_profile_attributes_updater.cc
index 830a9e2..835d9ca 100644
--- a/chrome/browser/signin/signin_profile_attributes_updater.cc
+++ b/chrome/browser/signin/signin_profile_attributes_updater.cc
@@ -54,7 +54,7 @@
   std::string old_gaia_id = entry->GetGAIAId();
 
   if (identity_manager_->HasPrimaryAccount()) {
-    AccountInfo account_info = identity_manager_->GetPrimaryAccountInfo();
+    CoreAccountInfo account_info = identity_manager_->GetPrimaryAccountInfo();
     entry->SetAuthInfo(account_info.gaia,
                        base::UTF8ToUTF16(account_info.email));
   } else {
diff --git a/chrome/browser/signin/signin_profile_attributes_updater_unittest.cc b/chrome/browser/signin/signin_profile_attributes_updater_unittest.cc
index 2eac761..e1e0fba 100644
--- a/chrome/browser/signin/signin_profile_attributes_updater_unittest.cc
+++ b/chrome/browser/signin/signin_profile_attributes_updater_unittest.cc
@@ -102,16 +102,15 @@
   EXPECT_FALSE(entry->IsAuthError());
 
   // Set auth error.
-  AccountInfo account_info = identity_manager->GetPrimaryAccountInfo();
+  std::string account_id = identity_manager->GetPrimaryAccountId();
   identity::UpdatePersistentErrorOfRefreshTokenForAccount(
-      identity_manager, account_info.account_id,
+      identity_manager, account_id,
       GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
   EXPECT_TRUE(entry->IsAuthError());
 
   // Remove auth error.
   identity::UpdatePersistentErrorOfRefreshTokenForAccount(
-      identity_manager, account_info.account_id,
-      GoogleServiceAuthError::AuthErrorNone());
+      identity_manager, account_id, GoogleServiceAuthError::AuthErrorNone());
   EXPECT_FALSE(entry->IsAuthError());
 }
 
diff --git a/chrome/browser/signin/signin_util.cc b/chrome/browser/signin/signin_util.cc
index 78965e3..aa6d6bc 100644
--- a/chrome/browser/signin/signin_util.cc
+++ b/chrome/browser/signin/signin_util.cc
@@ -216,7 +216,7 @@
   if (!identity_manager->HasPrimaryAccount())
     return;
 
-  AccountInfo primary_account = identity_manager->GetPrimaryAccountInfo();
+  CoreAccountInfo primary_account = identity_manager->GetPrimaryAccountInfo();
   if (profile->GetPrefs()->GetBoolean(prefs::kSigninAllowed) &&
       identity::LegacyIsUsernameAllowedByPatternFromPrefs(
           g_browser_process->local_state(), primary_account.email,
diff --git a/chrome/browser/speech/tts_controller_delegate_impl.cc b/chrome/browser/speech/tts_controller_delegate_impl.cc
index dbfed89..0390cfe 100644
--- a/chrome/browser/speech/tts_controller_delegate_impl.cc
+++ b/chrome/browser/speech/tts_controller_delegate_impl.cc
@@ -32,7 +32,7 @@
       (voice.engine_id.empty() && !voice.native))
     return false;
   std::unique_ptr<base::DictionaryValue> json =
-      base::DictionaryValue::From(base::JSONReader::Read(voice_id));
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(voice_id));
   std::string default_name;
   std::string default_extension_id;
   json->GetString("name", &default_name);
diff --git a/chrome/browser/spellchecker/spelling_service_client_unittest.cc b/chrome/browser/spellchecker/spelling_service_client_unittest.cc
index d432389..f36f7d6 100644
--- a/chrome/browser/spellchecker/spelling_service_client_unittest.cc
+++ b/chrome/browser/spellchecker/spelling_service_client_unittest.cc
@@ -264,8 +264,8 @@
     // Parse the JSON sent to the service, and verify its parameters.
     std::unique_ptr<base::DictionaryValue> value(
         static_cast<base::DictionaryValue*>(
-            base::JSONReader::Read(intercepted_body,
-                                   base::JSON_ALLOW_TRAILING_COMMAS)
+            base::JSONReader::ReadDeprecated(intercepted_body,
+                                             base::JSON_ALLOW_TRAILING_COMMAS)
                 .release()));
     ASSERT_TRUE(value.get());
     std::string method;
diff --git a/chrome/browser/supervised_user/child_accounts/family_info_fetcher.cc b/chrome/browser/supervised_user/child_accounts/family_info_fetcher.cc
index 1b12006b..2e836c6 100644
--- a/chrome/browser/supervised_user/child_accounts/family_info_fetcher.cc
+++ b/chrome/browser/supervised_user/child_accounts/family_info_fetcher.cc
@@ -286,7 +286,8 @@
 }
 
 void FamilyInfoFetcher::FamilyProfileFetched(const std::string& response) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(response);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(response);
   const base::DictionaryValue* dict = NULL;
   if (!value || !value->GetAsDictionary(&dict)) {
     consumer_->OnFailure(SERVICE_ERROR);
@@ -316,7 +317,8 @@
 }
 
 void FamilyInfoFetcher::FamilyMembersFetched(const std::string& response) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(response);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(response);
   const base::DictionaryValue* dict = NULL;
   if (!value || !value->GetAsDictionary(&dict)) {
     consumer_->OnFailure(SERVICE_ERROR);
diff --git a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc
index 825e0424..3ed98db 100644
--- a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc
+++ b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.cc
@@ -294,7 +294,7 @@
   if (response_body)
     body = std::move(*response_body);
 
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(body);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(body);
   base::DictionaryValue* dict = NULL;
   if (!value || !value->GetAsDictionary(&dict)) {
     LOG(WARNING) << "Invalid top-level dictionary";
diff --git a/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.cc b/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.cc
index 3495da7..a03e9bf 100644
--- a/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.cc
+++ b/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.cc
@@ -135,7 +135,7 @@
     Profile* profile =
         Profile::FromBrowserContext(web_contents->GetBrowserContext());
     auto* identity_manager = IdentityManagerFactory::GetForProfile(profile);
-    AccountInfo account_info = identity_manager->GetPrimaryAccountInfo();
+    CoreAccountInfo account_info = identity_manager->GetPrimaryAccountInfo();
     ReauthenticateChildAccount(
         web_contents, account_info.email,
         base::Bind(&SupervisedUserGoogleAuthNavigationThrottle::
diff --git a/chrome/browser/supervised_user/supervised_user_settings_service.cc b/chrome/browser/supervised_user/supervised_user_settings_service.cc
index 3a37aff..8fdba51 100644
--- a/chrome/browser/supervised_user/supervised_user_settings_service.cc
+++ b/chrome/browser/supervised_user/supervised_user_settings_service.cc
@@ -242,7 +242,7 @@
     const ::sync_pb::ManagedUserSettingSpecifics& supervised_user_setting =
         sync_data.GetSpecifics().managed_user_setting();
     std::unique_ptr<base::Value> value =
-        JSONReader::Read(supervised_user_setting.value());
+        JSONReader::ReadDeprecated(supervised_user_setting.value());
     // Wrongly formatted input will cause null values.
     // SetWithoutPathExpansion below requires non-null values.
     if (!value) {
@@ -366,7 +366,7 @@
       case SyncChange::ACTION_ADD:
       case SyncChange::ACTION_UPDATE: {
         std::unique_ptr<base::Value> value =
-            JSONReader::Read(supervised_user_setting.value());
+            JSONReader::ReadDeprecated(supervised_user_setting.value());
         if (dict->HasKey(key)) {
           DLOG_IF(WARNING, change_type == SyncChange::ACTION_ADD)
               << "Value for key " << key << " already exists";
diff --git a/chrome/browser/supervised_user/supervised_user_settings_service_unittest.cc b/chrome/browser/supervised_user/supervised_user_settings_service_unittest.cc
index d2f472c..a40eb089 100644
--- a/chrome/browser/supervised_user/supervised_user_settings_service_unittest.cc
+++ b/chrome/browser/supervised_user/supervised_user_settings_service_unittest.cc
@@ -109,7 +109,7 @@
     }
 
     std::unique_ptr<base::Value> value =
-        base::JSONReader::Read(supervised_user_setting.value());
+        base::JSONReader::ReadDeprecated(supervised_user_setting.value());
     EXPECT_TRUE(expected_value->Equals(value.get()));
   }
 
diff --git a/chrome/browser/themes/browser_theme_pack_unittest.cc b/chrome/browser/themes/browser_theme_pack_unittest.cc
index d0ac3620..add3cbe 100644
--- a/chrome/browser/themes/browser_theme_pack_unittest.cc
+++ b/chrome/browser/themes/browser_theme_pack_unittest.cc
@@ -152,7 +152,7 @@
 }
 
 void BrowserThemePackTest::LoadColorJSON(const std::string& json) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(json);
   ASSERT_TRUE(value->is_dict());
   LoadColorDictionary(static_cast<base::DictionaryValue*>(value.get()));
 }
@@ -163,7 +163,7 @@
 }
 
 void BrowserThemePackTest::LoadTintJSON(const std::string& json) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(json);
   ASSERT_TRUE(value->is_dict());
   LoadTintDictionary(static_cast<base::DictionaryValue*>(value.get()));
 }
@@ -173,7 +173,7 @@
 }
 
 void BrowserThemePackTest::LoadDisplayPropertiesJSON(const std::string& json) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(json);
   ASSERT_TRUE(value->is_dict());
   LoadDisplayPropertiesDictionary(
       static_cast<base::DictionaryValue*>(value.get()));
@@ -187,7 +187,7 @@
 void BrowserThemePackTest::ParseImageNamesJSON(
     const std::string& json,
     TestFilePathMap* out_file_paths) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(json);
   ASSERT_TRUE(value->is_dict());
   ParseImageNamesDictionary(static_cast<base::DictionaryValue*>(value.get()),
                             out_file_paths);
diff --git a/chrome/browser/tracing/background_tracing_field_trial.cc b/chrome/browser/tracing/background_tracing_field_trial.cc
index 302210c..05ad24de 100644
--- a/chrome/browser/tracing/background_tracing_field_trial.cc
+++ b/chrome/browser/tracing/background_tracing_field_trial.cc
@@ -84,7 +84,8 @@
   if (g_config_text_filter_for_testing)
     (*g_config_text_filter_for_testing)(&config_text);
 
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(config_text);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(config_text);
   if (!value)
     return nullptr;
 
@@ -104,7 +105,8 @@
     return;
   }
 
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(config_text);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(config_text);
   if (!value) {
     LOG(ERROR) << "Background tracing has incorrect config: " << config_text;
     return;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 9a5affe..c0e2dab9 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2655,6 +2655,8 @@
       "views/overlay/close_image_button.h",
       "views/overlay/control_image_button.cc",
       "views/overlay/control_image_button.h",
+      "views/overlay/next_track_image_button.cc",
+      "views/overlay/next_track_image_button.h",
       "views/overlay/overlay_window_views.cc",
       "views/overlay/overlay_window_views.h",
       "views/overlay/playback_image_button.cc",
diff --git a/chrome/browser/ui/ash/assistant/assistant_client.cc b/chrome/browser/ui/ash/assistant/assistant_client.cc
index 492d1c4..d523a271 100644
--- a/chrome/browser/ui/ash/assistant/assistant_client.cc
+++ b/chrome/browser/ui/ash/assistant/assistant_client.cc
@@ -67,6 +67,9 @@
 }
 
 void AssistantClient::MaybeStartAssistantOptInFlow() {
+  if (!initialized_)
+    return;
+
   assistant_setup_->MaybeStartAssistantOptInFlow();
 }
 
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl_browsertest.cc b/chrome/browser/ui/autofill/save_card_bubble_controller_impl_browsertest.cc
index c0faa56..fe2a2a17 100644
--- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl_browsertest.cc
+++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl_browsertest.cc
@@ -40,7 +40,7 @@
   }
 
   std::unique_ptr<base::DictionaryValue> GetTestLegalMessage() {
-    std::unique_ptr<base::Value> value(base::JSONReader::Read(
+    std::unique_ptr<base::Value> value(base::JSONReader::ReadDeprecated(
         "{"
         "  \"line\" : [ {"
         "     \"template\": \"The legal documents are: {0} and {1}.\","
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc
index 737e16d..5af8a8a 100644
--- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc
@@ -100,7 +100,8 @@
                        bool should_request_name_from_user = false,
                        bool should_request_expiration_date_from_user = false,
                        bool show_bubble = true) {
-    std::unique_ptr<base::Value> value(base::JSONReader::Read(message_json));
+    std::unique_ptr<base::Value> value(
+        base::JSONReader::ReadDeprecated(message_json));
     ASSERT_TRUE(value);
     base::DictionaryValue* dictionary;
     ASSERT_TRUE(value->GetAsDictionary(&dictionary));
diff --git a/chrome/browser/ui/cocoa/applescript/apple_event_util_unittest.mm b/chrome/browser/ui/cocoa/applescript/apple_event_util_unittest.mm
index ae507f0..7a58f02e 100644
--- a/chrome/browser/ui/cocoa/applescript/apple_event_util_unittest.mm
+++ b/chrome/browser/ui/cocoa/applescript/apple_event_util_unittest.mm
@@ -230,7 +230,7 @@
 
   for (size_t i = 0; i < base::size(cases); ++i) {
     std::unique_ptr<base::Value> value =
-        base::JSONReader::Read(cases[i].json_input);
+        base::JSONReader::ReadDeprecated(cases[i].json_input);
     NSAppleEventDescriptor* descriptor =
         chrome::mac::ValueToAppleEventDescriptor(value.get());
 
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc b/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc
index ad7fa32..faf8655 100644
--- a/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc
+++ b/chrome/browser/ui/extensions/extension_action_view_controller_unittest.cc
@@ -379,8 +379,9 @@
       .SetLocation(extensions::Manifest::INTERNAL);
   switch (permission_type) {
     case PermissionType::kScriptableHost: {
-      std::unique_ptr<base::Value> content_scripts = base::JSONReader::Read(
-          R"([{
+      std::unique_ptr<base::Value> content_scripts =
+          base::JSONReader::ReadDeprecated(
+              R"([{
                      "matches": ["https://www.google.com/*"],
                      "js": ["script.js"]
                  }])");
diff --git a/chrome/browser/ui/page_info/page_info.cc b/chrome/browser/ui/page_info/page_info.cc
index c46a986..bfcf810 100644
--- a/chrome/browser/ui/page_info/page_info.cc
+++ b/chrome/browser/ui/page_info/page_info.cc
@@ -81,6 +81,8 @@
 #endif
 
 #if !defined(OS_ANDROID)
+#include "chrome/browser/serial/serial_chooser_context.h"
+#include "chrome/browser/serial/serial_chooser_context_factory.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
@@ -295,14 +297,26 @@
   return UsbChooserContextFactory::GetForProfile(profile);
 }
 
+#if !defined(OS_ANDROID)
+ChooserContextBase* GetSerialChooserContext(Profile* profile) {
+  return SerialChooserContextFactory::GetForProfile(profile);
+}
+#endif
+
 // The list of chooser types that need to display entries in the Website
 // Settings UI. THE ORDER OF THESE ITEMS IS IMPORTANT. To propose changing it,
 // email security-dev@chromium.org.
 const PageInfo::ChooserUIInfo kChooserUIInfo[] = {
     {CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA, &GetUsbChooserContext,
-     IDS_PAGE_INFO_USB_DEVICE_LABEL, IDS_PAGE_INFO_USB_DEVICE_SECONDARY_LABEL,
+     IDS_PAGE_INFO_USB_DEVICE_SECONDARY_LABEL,
      IDS_PAGE_INFO_USB_DEVICE_ALLOWED_BY_POLICY_LABEL,
      IDS_PAGE_INFO_DELETE_USB_DEVICE, "name"},
+#if !defined(OS_ANDROID)
+    {CONTENT_SETTINGS_TYPE_SERIAL_CHOOSER_DATA, &GetSerialChooserContext,
+     IDS_PAGE_INFO_SERIAL_PORT_SECONDARY_LABEL,
+     /*allowed_by_policy_description_string_id=*/-1,
+     IDS_PAGE_INFO_DELETE_SERIAL_PORT, "name"},
+#endif
 };
 
 // Time open histogram prefixes.
diff --git a/chrome/browser/ui/page_info/page_info.h b/chrome/browser/ui/page_info/page_info.h
index 4dfe8ee..2007d3c3f 100644
--- a/chrome/browser/ui/page_info/page_info.h
+++ b/chrome/browser/ui/page_info/page_info.h
@@ -130,7 +130,6 @@
   struct ChooserUIInfo {
     ContentSettingsType content_settings_type;
     ChooserContextBase* (*get_context)(Profile*);
-    int name_string_id;
     int description_string_id;
     int allowed_by_policy_description_string_id;
     int delete_tooltip_string_id;
diff --git a/chrome/browser/ui/page_info/page_info_ui.cc b/chrome/browser/ui/page_info/page_info_ui.cc
index 9fadb3a1..ca2d82f 100644
--- a/chrome/browser/ui/page_info/page_info_ui.cc
+++ b/chrome/browser/ui/page_info/page_info_ui.cc
@@ -578,9 +578,21 @@
     const ChosenObjectInfo& object,
     bool deleted,
     SkColor related_text_color) {
-  DCHECK_EQ(CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA,
-            object.ui_info.content_settings_type);
-  const gfx::VectorIcon* icon = &vector_icons::kUsbIcon;
+  const gfx::VectorIcon* icon = &gfx::kNoneIcon;
+  switch (object.ui_info.content_settings_type) {
+    case CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA:
+      icon = &vector_icons::kUsbIcon;
+      break;
+    case CONTENT_SETTINGS_TYPE_SERIAL_CHOOSER_DATA:
+      icon = &vector_icons::kSerialPortIcon;
+      break;
+    default:
+      // All other content settings types do not represent chosen object
+      // permissions.
+      NOTREACHED();
+      break;
+  }
+
   if (deleted) {
     return gfx::CreateVectorIconWithBadge(
         *icon, kVectorIconSize,
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_bubble_views.cc b/chrome/browser/ui/views/autofill/local_card_migration_bubble_views.cc
index 472062fe..292725d 100644
--- a/chrome/browser/ui/views/autofill/local_card_migration_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/local_card_migration_bubble_views.cc
@@ -106,7 +106,10 @@
       ChromeLayoutProvider::Get()->GetDistanceMetric(
           DISTANCE_RELATED_CONTROL_VERTICAL_SMALL)));
   gfx::ImageSkia image = gfx::ImageSkiaOperations::CreateTiledImage(
-      gfx::CreateVectorIcon(kGooglePayLogoIcon, gfx::kPlaceholderColor),
+      gfx::CreateVectorIcon(kGooglePayLogoIcon,
+                            GetNativeTheme()->SystemDarkModeEnabled()
+                                ? gfx::kGoogleGrey200
+                                : gfx::kGoogleGrey700),
       /*x=*/0, /*y=*/0, kMigrationBubbleGooglePayLogoWidth,
       kMigrationBubbleGooglePayLogoHeight);
   views::ImageView* icon_view = new views::ImageView();
diff --git a/chrome/browser/ui/views/autofill/view_util.cc b/chrome/browser/ui/views/autofill/view_util.cc
index 9e6deec..7cc1dfa 100644
--- a/chrome/browser/ui/views/autofill/view_util.cc
+++ b/chrome/browser/ui/views/autofill/view_util.cc
@@ -63,7 +63,10 @@
   // kGooglePayLogoIcon is square, and CreateTiledImage() will clip it whereas
   // setting the icon size would rescale it incorrectly.
   gfx::ImageSkia image = gfx::ImageSkiaOperations::CreateTiledImage(
-      gfx::CreateVectorIcon(kGooglePayLogoIcon, gfx::kPlaceholderColor),
+      gfx::CreateVectorIcon(kGooglePayLogoIcon,
+                            GetNativeTheme()->SystemDarkModeEnabled()
+                                ? gfx::kGoogleGrey200
+                                : gfx::kGoogleGrey700),
       /*x=*/0, /*y=*/0, kGooglePayLogoWidth, kGooglePayLogoHeight);
   auto* icon_view = new views::ImageView();
   icon_view->SetImage(&image);
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
index 8f3dfc5..8c1e486 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
@@ -54,24 +54,18 @@
   LocatedEventRetargeter() {}
   ~LocatedEventRetargeter() override {}
 
-  ui::EventRewriteStatus RewriteEvent(
+  ui::EventDispatchDetails RewriteEvent(
       const ui::Event& event,
-      std::unique_ptr<ui::Event>* rewritten_event) override {
+      const Continuation continuation) override {
     if (!event.IsLocatedEvent())
-      return ui::EVENT_REWRITE_CONTINUE;
+      return SendEvent(continuation, &event);
 
-    *rewritten_event = ui::Event::Clone(event);
+    std::unique_ptr<ui::Event> replacement_event = ui::Event::Clone(event);
     // Cloning strips the EventTarget. The only goal of this EventRewriter is to
     // null the target, so there's no need to do anything extra here.
-    DCHECK(!(*rewritten_event)->target());
+    DCHECK(!replacement_event->target());
 
-    return ui::EVENT_REWRITE_REWRITTEN;
-  }
-
-  ui::EventRewriteStatus NextDispatchEvent(
-      const ui::Event& last_event,
-      std::unique_ptr<ui::Event>* new_event) override {
-    return ui::EVENT_REWRITE_CONTINUE;
+    return SendEventFinally(continuation, replacement_event.get());
   }
 
  private:
@@ -119,7 +113,7 @@
 void ImmersiveModeControllerAsh::Init(BrowserView* browser_view) {
   browser_view_ = browser_view;
   controller_->Init(this, browser_view_->frame(),
-      browser_view_->top_container());
+                    browser_view_->top_container());
 
   observed_windows_.Add(
       !features::IsUsingWindowService()
@@ -281,15 +275,15 @@
   browser_view_->frame()->GetFrameView()->UpdateClientArea();
 }
 
-std::vector<gfx::Rect>
-ImmersiveModeControllerAsh::GetVisibleBoundsInScreen() const {
+std::vector<gfx::Rect> ImmersiveModeControllerAsh::GetVisibleBoundsInScreen()
+    const {
   views::View* top_container_view = browser_view_->top_container();
   gfx::Rect top_container_view_bounds = top_container_view->GetVisibleBounds();
   // TODO(tdanderson): Implement View::ConvertRectToScreen().
   gfx::Point top_container_view_bounds_in_screen_origin(
       top_container_view_bounds.origin());
-  views::View::ConvertPointToScreen(top_container_view,
-      &top_container_view_bounds_in_screen_origin);
+  views::View::ConvertPointToScreen(
+      top_container_view, &top_container_view_bounds_in_screen_origin);
   gfx::Rect top_container_view_bounds_in_screen(
       top_container_view_bounds_in_screen_origin,
       top_container_view_bounds.size());
@@ -309,8 +303,8 @@
     return;
 
   // Auto hide the shelf in immersive browser fullscreen.
-  bool in_tab_fullscreen = content::Source<FullscreenController>(source)->
-      IsWindowFullscreenForTabOrPending();
+  bool in_tab_fullscreen = content::Source<FullscreenController>(source)
+                               ->IsWindowFullscreenForTabOrPending();
   browser_view_->GetNativeWindow()->SetProperty(
       ash::kHideShelfWhenFullscreenKey, in_tab_fullscreen);
 }
diff --git a/chrome/browser/ui/views/overlay/next_track_image_button.cc b/chrome/browser/ui/views/overlay/next_track_image_button.cc
new file mode 100644
index 0000000..2d19dad
--- /dev/null
+++ b/chrome/browser/ui/views/overlay/next_track_image_button.cc
@@ -0,0 +1,60 @@
+// 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/views/overlay/next_track_image_button.h"
+
+#include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/vector_icons/vector_icons.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/views/vector_icons.h"
+
+namespace {
+
+SkColor kNextTrackIconColor = SK_ColorWHITE;
+
+}  // namespace
+
+namespace views {
+
+NextTrackImageButton::NextTrackImageButton(ButtonListener* listener)
+    : ImageButton(listener) {
+  SetImageAlignment(views::ImageButton::ALIGN_CENTER,
+                    views::ImageButton::ALIGN_MIDDLE);
+
+  // Accessibility.
+  SetFocusForPlatform();
+  const base::string16 next_track_button_label(l10n_util::GetStringUTF16(
+      IDS_PICTURE_IN_PICTURE_NEXT_TRACK_CONTROL_ACCESSIBLE_TEXT));
+  SetAccessibleName(next_track_button_label);
+  SetTooltipText(next_track_button_label);
+  SetInstallFocusRingOnFocus(true);
+}
+
+NextTrackImageButton::~NextTrackImageButton() = default;
+
+gfx::Size NextTrackImageButton::GetLastVisibleSize() const {
+  return size().IsEmpty() ? last_visible_size_ : size();
+}
+
+void NextTrackImageButton::OnBoundsChanged(const gfx::Rect&) {
+  SetImage(views::Button::STATE_NORMAL,
+           gfx::CreateVectorIcon(vector_icons::kMediaNextTrackIcon,
+                                 GetLastVisibleSize().width() / 2,
+                                 kNextTrackIconColor));
+}
+
+void NextTrackImageButton::ToggleVisibility(bool is_visible) {
+  if (is_visible && !size().IsEmpty()) {
+    last_visible_size_ = size();
+  }
+
+  SetVisible(is_visible);
+  SetEnabled(is_visible);
+  SetSize(is_visible ? GetLastVisibleSize() : gfx::Size());
+}
+
+}  // namespace views
diff --git a/chrome/browser/ui/views/overlay/next_track_image_button.h b/chrome/browser/ui/views/overlay/next_track_image_button.h
new file mode 100644
index 0000000..3f265cb3
--- /dev/null
+++ b/chrome/browser/ui/views/overlay/next_track_image_button.h
@@ -0,0 +1,38 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_OVERLAY_NEXT_TRACK_IMAGE_BUTTON_H_
+#define CHROME_BROWSER_UI_VIEWS_OVERLAY_NEXT_TRACK_IMAGE_BUTTON_H_
+
+#include "chrome/browser/ui/views/overlay/overlay_window_views.h"
+#include "ui/views/controls/button/image_button.h"
+
+namespace views {
+
+// A resizable next track image button.
+class NextTrackImageButton : public views::ImageButton {
+ public:
+  explicit NextTrackImageButton(ButtonListener*);
+  ~NextTrackImageButton() override;
+
+  // Get button size when visible.
+  gfx::Size GetLastVisibleSize() const;
+
+  // Toggle visibility.
+  void ToggleVisibility(bool is_visible);
+
+ protected:
+  // Overridden from views::View.
+  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
+
+ private:
+  // Last visible size of the image button.
+  gfx::Size last_visible_size_;
+
+  DISALLOW_COPY_AND_ASSIGN(NextTrackImageButton);
+};
+
+}  // namespace views
+
+#endif  // CHROME_BROWSER_UI_VIEWS_OVERLAY_NEXT_TRACK_IMAGE_BUTTON_H_
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc
index 8b03bced..08d35ae4 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.cc
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/ui/views/overlay/back_to_tab_image_button.h"
 #include "chrome/browser/ui/views/overlay/close_image_button.h"
 #include "chrome/browser/ui/views/overlay/control_image_button.h"
+#include "chrome/browser/ui/views/overlay/next_track_image_button.h"
 #include "chrome/browser/ui/views/overlay/playback_image_button.h"
 #include "chrome/browser/ui/views/overlay/resize_handle_button.h"
 #include "chrome/browser/ui/views/overlay/skip_ad_label_button.h"
@@ -60,7 +61,11 @@
 // smaller of the screen's width and height.
 const float kControlRatioToWindow = 0.3;
 
+// Track buttons sizes are 60% smaller than Play/Pause button.
+const float kTrackButtonSizeScale = 0.6;
+
 const int kMinControlButtonSize = 48;
+const int kControlButtonMargin = 12;
 
 // Colors for the control buttons.
 SkColor kBgColor = SK_ColorWHITE;
@@ -122,7 +127,8 @@
          window->GetCloseControlsBounds().Contains(point) ||
          window->GetFirstCustomControlsBounds().Contains(point) ||
          window->GetSecondCustomControlsBounds().Contains(point) ||
-         window->GetPlayPauseControlsBounds().Contains(point))) {
+         window->GetPlayPauseControlsBounds().Contains(point) ||
+         window->GetNextTrackControlsBounds().Contains(point))) {
       return window_component;
     }
 
@@ -196,6 +202,7 @@
       resize_handle_view_(new views::ResizeHandleButton(this)),
 #endif
       play_pause_controls_view_(new views::PlaybackImageButton(this)),
+      next_track_controls_view_(new views::NextTrackImageButton(this)),
       hide_controls_timer_(
           FROM_HERE,
           base::TimeDelta::FromMilliseconds(2500 /* 2.5 seconds */),
@@ -376,6 +383,9 @@
       controller_->IsPlayerActive() ? kPlaying : kPaused);
   play_pause_controls_view_->set_owned_by_client();
 
+  // views::View that holds the next-track image button. ----------------------
+  next_track_controls_view_->set_owned_by_client();
+
 #if defined(OS_CHROMEOS)
   // views::View that shows the affordance that the window can be resized. ----
   resize_handle_view_->SetPaintToLayer(ui::LAYER_TEXTURED);
@@ -386,6 +396,7 @@
 
   // Set up view::Views hierarchy. --------------------------------------------
   controls_parent_view_->AddChildView(play_pause_controls_view_.get());
+  controls_parent_view_->AddChildView(next_track_controls_view_.get());
   GetContentsView()->AddChildView(controls_scrim_view_.get());
   GetContentsView()->AddChildView(controls_parent_view_.get());
   GetContentsView()->AddChildView(skip_ad_controls_view_.get());
@@ -395,7 +406,7 @@
   GetContentsView()->AddChildView(resize_handle_view_.get());
 #endif
 
-  UpdatePlayPauseControlsSize();
+  UpdateButtonControlsSize();
   UpdateControlsVisibility(false);
 }
 
@@ -429,6 +440,8 @@
 void OverlayWindowViews::UpdateControlsVisibility(bool is_visible) {
   play_pause_controls_view_->SetVisible(is_visible &&
                                         !always_hide_play_pause_button_);
+  next_track_controls_view_->ToggleVisibility(is_visible &&
+                                              show_next_track_button_);
   GetControlsScrimLayer()->SetVisible(is_visible);
   GetControlsParentLayer()->SetVisible(is_visible);
   GetBackToTabControlsLayer()->SetVisible(is_visible);
@@ -462,7 +475,17 @@
   controls_parent_view_->SetBoundsRect(
       gfx::Rect(gfx::Point(0, 0), GetBounds().size()));
 
-  UpdateControlsPositions();
+  // FIXME: Merge with UpdateControlsPositions when custom controls are removed.
+  if (show_next_track_button_) {
+    int mid_window_x = GetBounds().size().width() / 2;
+    play_pause_controls_view_->SetBoundsRect(CalculateControlsBounds(
+        mid_window_x - button_size_.width() / 2, button_size_));
+    next_track_controls_view_->SetBoundsRect(CalculateControlsBounds(
+        mid_window_x + button_size_.width() / 2 + kControlButtonMargin,
+        next_track_controls_view_->GetLastVisibleSize()));
+  } else {
+    UpdateControlsPositions();
+  }
 }
 
 void OverlayWindowViews::UpdateButtonSize() {
@@ -504,9 +527,13 @@
                                      &control_background);
 }
 
-void OverlayWindowViews::UpdatePlayPauseControlsSize() {
+void OverlayWindowViews::UpdateButtonControlsSize() {
+  // FIXME: Inline UpdateButtonSize() when custom controls are removed.
   UpdateButtonSize();
-  play_pause_controls_view_->SetButtonSize(button_size_);
+  play_pause_controls_view_->SetSize(button_size_);
+  gfx::Size track_button_size =
+      gfx::ScaleToRoundedSize(button_size_, kTrackButtonSizeScale);
+  next_track_controls_view_->SetSize(track_button_size);
 }
 
 void OverlayWindowViews::CreateCustomControl(
@@ -648,6 +675,14 @@
   show_skip_ad_button_ = is_visible;
 }
 
+void OverlayWindowViews::SetNextTrackButtonVisibility(bool is_visible) {
+  if (show_next_track_button_ == is_visible)
+    return;
+
+  show_next_track_button_ = is_visible;
+  UpdateControlsBounds();
+}
+
 void OverlayWindowViews::SetPictureInPictureCustomControls(
     const std::vector<blink::PictureInPictureControlInfo>& controls) {
   // Clear any existing controls.
@@ -725,7 +760,7 @@
   // Update the view layers to scale to |new_size|.
   UpdateCustomControlsSize(first_custom_controls_view_.get());
   UpdateCustomControlsSize(second_custom_controls_view_.get());
-  UpdatePlayPauseControlsSize();
+  UpdateButtonControlsSize();
   UpdateLayerBoundsWithLetterboxing(new_size);
 
   views::Widget::OnNativeWidgetSizeChanged(new_size);
@@ -833,6 +868,9 @@
   } else if (GetPlayPauseControlsBounds().Contains(event->location())) {
     TogglePlayPause();
     event->SetHandled();
+  } else if (GetNextTrackControlsBounds().Contains(event->location())) {
+    controller_->NextTrack();
+    event->SetHandled();
   }
 }
 
@@ -851,6 +889,9 @@
   if (sender == play_pause_controls_view_.get())
     TogglePlayPause();
 
+  if (sender == next_track_controls_view_.get())
+    controller_->NextTrack();
+
   if (sender == first_custom_controls_view_.get())
     controller_->CustomControlPressed(first_custom_controls_view_->id());
 
@@ -878,6 +919,10 @@
   return play_pause_controls_view_->GetMirroredBounds();
 }
 
+gfx::Rect OverlayWindowViews::GetNextTrackControlsBounds() {
+  return next_track_controls_view_->GetMirroredBounds();
+}
+
 gfx::Rect OverlayWindowViews::GetFirstCustomControlsBounds() {
   if (!first_custom_controls_view_)
     return gfx::Rect();
@@ -906,10 +951,6 @@
   return back_to_tab_controls_view_->layer();
 }
 
-ui::Layer* OverlayWindowViews::GetSkipAdControlsLayer() {
-  return skip_ad_controls_view_->layer();
-}
-
 ui::Layer* OverlayWindowViews::GetCloseControlsLayer() {
   return close_controls_view_->layer();
 }
@@ -935,6 +976,11 @@
   return play_pause_controls_view_.get();
 }
 
+views::NextTrackImageButton*
+OverlayWindowViews::next_track_controls_view_for_testing() const {
+  return next_track_controls_view_.get();
+}
+
 gfx::Point OverlayWindowViews::back_to_tab_image_position_for_testing() const {
   return back_to_tab_controls_view_->origin();
 }
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.h b/chrome/browser/ui/views/overlay/overlay_window_views.h
index 7f5048b2..b305837 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.h
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.h
@@ -20,6 +20,7 @@
 class BackToTabImageButton;
 class ControlImageButton;
 class CloseImageButton;
+class NextTrackImageButton;
 class PlaybackImageButton;
 class ResizeHandleButton;
 class SkipAdLabelButton;
@@ -50,6 +51,7 @@
   void SetPlaybackState(PlaybackState playback_state) override;
   void SetAlwaysHidePlayPauseButton(bool is_visible) override;
   void SetSkipAdButtonVisibility(bool is_visible) override;
+  void SetNextTrackButtonVisibility(bool is_visible) override;
   void SetPictureInPictureCustomControls(
       const std::vector<blink::PictureInPictureControlInfo>& controls) override;
   ui::Layer* GetWindowBackgroundLayer() override;
@@ -77,6 +79,7 @@
   gfx::Rect GetCloseControlsBounds();
   gfx::Rect GetResizeHandleControlsBounds();
   gfx::Rect GetPlayPauseControlsBounds();
+  gfx::Rect GetNextTrackControlsBounds();
   gfx::Rect GetFirstCustomControlsBounds();
   gfx::Rect GetSecondCustomControlsBounds();
 
@@ -89,6 +92,7 @@
   bool AreControlsVisible() const;
 
   views::PlaybackImageButton* play_pause_controls_view_for_testing() const;
+  views::NextTrackImageButton* next_track_controls_view_for_testing() const;
   gfx::Point back_to_tab_image_position_for_testing() const;
   views::SkipAdLabelButton* skip_ad_controls_view_for_testing() const;
   gfx::Point close_image_position_for_testing() const;
@@ -124,7 +128,7 @@
 
   // Update the size of each controls view as the size of the window changes.
   void UpdateCustomControlsSize(views::ControlImageButton* control_button);
-  void UpdatePlayPauseControlsSize();
+  void UpdateButtonControlsSize();
 
   void CreateCustomControl(
       std::unique_ptr<views::ControlImageButton>& control_button,
@@ -144,7 +148,6 @@
 
   ui::Layer* GetControlsScrimLayer();
   ui::Layer* GetBackToTabControlsLayer();
-  ui::Layer* GetSkipAdControlsLayer();
   ui::Layer* GetCloseControlsLayer();
   ui::Layer* GetResizeHandleLayer();
   ui::Layer* GetControlsParentLayer();
@@ -203,6 +206,7 @@
   std::unique_ptr<views::CloseImageButton> close_controls_view_;
   std::unique_ptr<views::ResizeHandleButton> resize_handle_view_;
   std::unique_ptr<views::PlaybackImageButton> play_pause_controls_view_;
+  std::unique_ptr<views::NextTrackImageButton> next_track_controls_view_;
   std::unique_ptr<views::ControlImageButton> first_custom_controls_view_;
   std::unique_ptr<views::ControlImageButton> second_custom_controls_view_;
 #if defined(OS_CHROMEOS)
@@ -220,6 +224,10 @@
   // case when Media Session "skipad" action is handled by the website.
   bool show_skip_ad_button_ = false;
 
+  // Whether or not the next track button will be shown. This is the
+  // case when Media Session "nexttrack" action is handled by the website.
+  bool show_next_track_button_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(OverlayWindowViews);
 };
 
diff --git a/chrome/browser/ui/views/overlay/playback_image_button.cc b/chrome/browser/ui/views/overlay/playback_image_button.cc
index b8f06c13..8bb24d7 100644
--- a/chrome/browser/ui/views/overlay/playback_image_button.cc
+++ b/chrome/browser/ui/views/overlay/playback_image_button.cc
@@ -35,19 +35,17 @@
 
 PlaybackImageButton::~PlaybackImageButton() = default;
 
-void PlaybackImageButton::SetButtonSize(const gfx::Size& size) {
-  SetSize(size);
-
+void PlaybackImageButton::OnBoundsChanged(const gfx::Rect&) {
   play_image_ = gfx::CreateVectorIcon(vector_icons::kPlayArrowIcon,
-                                      size.width() / 2, kPlaybackIconColor);
+                                      size().width() / 2, kPlaybackIconColor);
   pause_image_ = gfx::CreateVectorIcon(vector_icons::kPauseIcon,
-                                       size.width() / 2, kPlaybackIconColor);
+                                       size().width() / 2, kPlaybackIconColor);
   replay_image_ = gfx::CreateVectorIcon(vector_icons::kReplayIcon,
-                                        size.width() / 2, kPlaybackIconColor);
+                                        size().width() / 2, kPlaybackIconColor);
 
   const gfx::ImageSkia background_image_ =
       gfx::CreateVectorIcon(kPictureInPictureControlBackgroundIcon,
-                            size.width(), kPlaybackIconBackgroundColor);
+                            size().width(), kPlaybackIconBackgroundColor);
   SetBackgroundImage(kPlaybackIconBackgroundColor, &background_image_,
                      &background_image_);
 
diff --git a/chrome/browser/ui/views/overlay/playback_image_button.h b/chrome/browser/ui/views/overlay/playback_image_button.h
index f10d57f..8453f28 100644
--- a/chrome/browser/ui/views/overlay/playback_image_button.h
+++ b/chrome/browser/ui/views/overlay/playback_image_button.h
@@ -13,15 +13,16 @@
 // A resizable playback button with 3 states: play/pause/replay.
 class PlaybackImageButton : public views::ImageButton {
  public:
-  explicit PlaybackImageButton(ButtonListener* listener);
+  explicit PlaybackImageButton(ButtonListener*);
   ~PlaybackImageButton() override;
 
-  // Set button size and make sure images are sized accordindly.
-  void SetButtonSize(const gfx::Size& size);
-
   // Show appropriate images based on playback state.
   void SetPlaybackState(const OverlayWindowViews::PlaybackState playback_state);
 
+ protected:
+  // Overridden from views::View.
+  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
+
  private:
   void UpdateImageAndTooltipText();
 
diff --git a/chrome/browser/ui/views/page_info/chosen_object_view.cc b/chrome/browser/ui/views/page_info/chosen_object_view.cc
index 525614b..b455d3b 100644
--- a/chrome/browser/ui/views/page_info/chosen_object_view.cc
+++ b/chrome/browser/ui/views/page_info/chosen_object_view.cc
@@ -70,9 +70,7 @@
 
   // Create the label that displays the chosen object name.
   views::Label* label = new views::Label(
-      l10n_util::GetStringFUTF16(info_->ui_info.name_string_id,
-                                 PageInfoUI::ChosenObjectToUIString(*info_)),
-      CONTEXT_BODY_TEXT_LARGE);
+      PageInfoUI::ChosenObjectToUIString(*info_), CONTEXT_BODY_TEXT_LARGE);
   icon_->SetImage(
       PageInfoUI::GetChosenObjectIcon(*info_, false, label->enabled_color()));
   layout->AddView(label);
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.cc b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
index d01dfd2..756e78e 100644
--- a/chrome/browser/ui/views/profiles/profile_chooser_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
@@ -1421,11 +1421,10 @@
   // crbug.com/311124.
   auto* identity_manager = IdentityManagerFactory::GetForProfile(profile);
   DCHECK(identity_manager->HasPrimaryAccount());
-  AccountInfo primary_account = identity_manager->GetPrimaryAccountInfo();
+  std::string primary_account_id = identity_manager->GetPrimaryAccountId();
 
-  CreateAccountButton(layout, primary_account.account_id, true,
-                      error_account_id == primary_account.account_id,
-                      menu_width_);
+  CreateAccountButton(layout, primary_account_id, true,
+                      error_account_id == primary_account_id, menu_width_);
   for (const AccountInfo& account :
        profiles::GetSecondaryAccountsForSignedInProfile(profile))
     CreateAccountButton(layout, account.account_id, false,
diff --git a/chrome/browser/ui/webui/browser_switcher/browser_switch_ui.cc b/chrome/browser/ui/webui/browser_switcher/browser_switch_ui.cc
index 74087ca..fcd2487 100644
--- a/chrome/browser/ui/webui/browser_switcher/browser_switch_ui.cc
+++ b/chrome/browser/ui/webui/browser_switcher/browser_switch_ui.cc
@@ -24,13 +24,24 @@
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/grit/components_resources.h"
+#include "content/public/browser/page_navigator.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "content/public/browser/web_ui_message_handler.h"
+#include "ui/base/page_transition_types.h"
+#include "url/gurl.h"
 
 namespace {
 
+void GotoNewTabPage(content::WebContents* web_contents) {
+  GURL url(chrome::kChromeUINewTabURL);
+  content::OpenURLParams params(url, content::Referrer(),
+                                WindowOpenDisposition::CURRENT_TAB,
+                                ui::PAGE_TRANSITION_AUTO_TOPLEVEL, false);
+  web_contents->OpenURL(params);
+}
+
 // Returns true if there's only 1 tab left open in this profile. Incognito
 // window tabs count as the same profile.
 bool IsLastTab(const Profile* profile) {
@@ -94,6 +105,9 @@
   // JavaScript promise is not resolved, because we close the tab anyways.
   void HandleLaunchAlternativeBrowserAndCloseTab(const base::ListValue* args);
 
+  // Navigates to the New Tab Page.
+  void HandleGotoNewTabPage(const base::ListValue* args);
+
   DISALLOW_COPY_AND_ASSIGN(BrowserSwitchHandler);
 };
 
@@ -106,6 +120,10 @@
       base::BindRepeating(
           &BrowserSwitchHandler::HandleLaunchAlternativeBrowserAndCloseTab,
           base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "gotoNewTabPage",
+      base::BindRepeating(&BrowserSwitchHandler::HandleGotoNewTabPage,
+                          base::Unretained(this)));
 }
 
 void BrowserSwitchHandler::HandleLaunchAlternativeBrowserAndCloseTab(
@@ -139,13 +157,10 @@
     return;
   }
 
-  // TODO(nicolaso): Find a fix: when the last tab closes, restarting Chrome
-  // causes it to immediately open the alternative browser, and then close
-  // Chrome again.
   auto* profile = Profile::FromWebUI(web_ui());
 
   if (service->prefs().KeepLastTab() && IsLastTab(profile)) {
-    // TODO(nicolaso): Show the NTP after cancelling the navigation.
+    GotoNewTabPage(web_ui()->GetWebContents());
   } else {
     // We don't need to resolve the promise, because the tab will close anyways.
     base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -155,6 +170,10 @@
   }
 }
 
+void BrowserSwitchHandler::HandleGotoNewTabPage(const base::ListValue* args) {
+  GotoNewTabPage(web_ui()->GetWebContents());
+}
+
 }  // namespace
 
 BrowserSwitchUI::BrowserSwitchUI(content::WebUI* web_ui)
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
index 178edbb..fce3c4f 100644
--- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -640,7 +640,7 @@
     return;
   }
   std::unique_ptr<base::ListValue> options =
-      base::ListValue::From(base::JSONReader::Read(
+      base::ListValue::From(base::JSONReader::ReadDeprecated(
           unlocked_data, base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS));
   if (!options) {
     ShowError(IDS_AD_JOIN_CONFIG_NOT_PARSED, true);
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index a4b4b14..8ebe168 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -188,6 +188,14 @@
      IDS_MD_EXTENSIONS_ACCESSIBILITY_ERROR_MULTI_LINE},
     {"activityLogPageHeading", IDS_MD_EXTENSIONS_ACTIVITY_LOG_PAGE_HEADING},
     {"activityLogSearchLabel", IDS_MD_EXTENSIONS_ACTIVITY_LOG_SEARCH_LABEL},
+    {"activityLogHistoryTabHeading",
+     IDS_MD_EXTENSIONS_ACTIVITY_LOG_HISTORY_TAB_HEADING},
+    {"activityLogStreamTabHeading",
+     IDS_MD_EXTENSIONS_ACTIVITY_LOG_STREAM_TAB_HEADING},
+    {"startActivityStream", IDS_MD_EXTENSIONS_START_ACTIVITY_STREAM},
+    {"stopActivityStream", IDS_MD_EXTENSIONS_STOP_ACTIVITY_STREAM},
+    {"emptyStreamStarted", IDS_MD_EXTENSIONS_EMPTY_STREAM_STARTED},
+    {"emptyStreamStopped", IDS_MD_EXTENSIONS_EMPTY_STREAM_STOPPED},
     {"appIcon", IDS_MD_EXTENSIONS_APP_ICON},
     {"extensionIcon", IDS_MD_EXTENSIONS_EXTENSION_ICON},
     {"extensionA11yAssociation", IDS_MD_EXTENSIONS_EXTENSION_A11Y_ASSOCIATION},
diff --git a/chrome/browser/ui/webui/policy_tool_ui_browsertest.cc b/chrome/browser/ui/webui/policy_tool_ui_browsertest.cc
index 6ad0ddf..d8ab47c 100644
--- a/chrome/browser/ui/webui/policy_tool_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/policy_tool_ui_browsertest.cc
@@ -235,7 +235,7 @@
   std::string json;
   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
       browser()->tab_strip_model()->GetActiveWebContents(), javascript, &json));
-  return base::DictionaryValue::From(base::JSONReader::Read(json));
+  return base::DictionaryValue::From(base::JSONReader::ReadDeprecated(json));
 }
 
 std::unique_ptr<base::ListValue> PolicyToolUITest::ExtractSessionsList() {
@@ -249,7 +249,7 @@
   std::string json;
   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
       browser()->tab_strip_model()->GetActiveWebContents(), javascript, &json));
-  return base::ListValue::From(base::JSONReader::Read(json));
+  return base::ListValue::From(base::JSONReader::ReadDeprecated(json));
 }
 
 bool PolicyToolUITest::IsInvalidSessionNameErrorMessageDisplayed() {
@@ -532,7 +532,7 @@
   std::string file_contents;
   base::ReadFileToString(GetSessionPath(GetDefaultSessionName()),
                          &file_contents);
-  values = base::JSONReader::Read(file_contents);
+  values = base::JSONReader::ReadDeprecated(file_contents);
   expected.SetDictionary("extensionPolicies",
                          std::make_unique<base::DictionaryValue>());
   expected.Remove("chromePolicies." + name + ".status", nullptr);
@@ -798,7 +798,7 @@
   base::ReadFileToString(GetSessionPath(FILE_PATH_LITERAL("test_session")),
                          &file_session_content);
   // The format of every session file is JSON.
-  policy::PlistWrite(*base::JSONReader::Read(file_session_content),
+  policy::PlistWrite(*base::JSONReader::ReadDeprecated(file_session_content),
                      &file_session_content);
   EXPECT_TRUE(file_export_content == file_session_content);
   TestSelectFileDialogPolicyTool::SetFactory(nullptr);
diff --git a/chrome/browser/ui/webui/policy_tool_ui_handler.cc b/chrome/browser/ui/webui/policy_tool_ui_handler.cc
index 39ae4cf..a8da30c 100644
--- a/chrome/browser/ui/webui/policy_tool_ui_handler.cc
+++ b/chrome/browser/ui/webui/policy_tool_ui_handler.cc
@@ -86,7 +86,7 @@
     return nullptr;
   if (policy_value->type() == base::Value::Type::STRING &&
       policy_schema.type() != base::Value::Type::STRING) {
-    return base::JSONReader::Read(policy_value->GetString());
+    return base::JSONReader::ReadDeprecated(policy_value->GetString());
   }
   return base::Value::ToUniquePtrValue(policy_value->Clone());
 }
@@ -244,7 +244,7 @@
     return;
   }
   std::unique_ptr<base::DictionaryValue> value =
-      base::DictionaryValue::From(base::JSONReader::Read(contents));
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(contents));
 
   // If contents is not a properly formed JSON string, disable editing in the
   // UI to prevent the user from accidentally overriding it.
diff --git a/chrome/browser/ui/webui/policy_ui_browsertest.cc b/chrome/browser/ui/webui/policy_ui_browsertest.cc
index 5f59f5b7..ed3e48b 100644
--- a/chrome/browser/ui/webui/policy_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/policy_ui_browsertest.cc
@@ -299,7 +299,8 @@
   std::string json;
   ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents, javascript,
                                                      &json));
-  std::unique_ptr<base::Value> value_ptr = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value_ptr =
+      base::JSONReader::ReadDeprecated(json);
   const base::ListValue* actual_policies = NULL;
   ASSERT_TRUE(value_ptr.get());
   ASSERT_TRUE(value_ptr->GetAsList(&actual_policies));
@@ -343,7 +344,7 @@
       base::ReadFileToString(export_policies_test_file_path, &file_contents));
 
   std::unique_ptr<base::Value> value_ptr =
-      base::JSONReader::Read(file_contents);
+      base::JSONReader::ReadDeprecated(file_contents);
 
   // Check that the file contains a valid dictionary.
   EXPECT_TRUE(value_ptr.get());
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index 042fed5..5d78e5b 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -282,7 +282,8 @@
 // Get the print job settings dictionary from |json_str|.
 // Returns |base::Value()| on failure.
 base::Value GetSettingsDictionary(const std::string& json_str) {
-  std::unique_ptr<base::Value> settings = base::JSONReader::Read(json_str);
+  std::unique_ptr<base::Value> settings =
+      base::JSONReader::ReadDeprecated(json_str);
   if (!settings->is_dict()) {
     NOTREACHED() << "Print job settings must be a dictionary.";
     return base::Value();
diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc
index da6493b..458c086 100644
--- a/chrome/browser/ui/webui/settings/people_handler.cc
+++ b/chrome/browser/ui/webui/settings/people_handler.cc
@@ -98,7 +98,8 @@
 SyncConfigInfo::~SyncConfigInfo() {}
 
 bool GetConfiguration(const std::string& json, SyncConfigInfo* config) {
-  std::unique_ptr<base::Value> parsed_value = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> parsed_value =
+      base::JSONReader::ReadDeprecated(json);
   base::DictionaryValue* result;
   if (!parsed_value || !parsed_value->GetAsDictionary(&result)) {
     DLOG(ERROR) << "GetConfiguration() not passed a Dictionary";
diff --git a/chrome/browser/ui/webui/settings/people_handler_unittest.cc b/chrome/browser/ui/webui/settings/people_handler_unittest.cc
index d438e8e..b6c45073 100644
--- a/chrome/browser/ui/webui/settings/people_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/people_handler_unittest.cc
@@ -876,7 +876,8 @@
   SetupInitializedProfileSyncService();
 
   auto* identity_manager = identity_test_env()->identity_manager();
-  AccountInfo primary_account_info = identity_manager->GetPrimaryAccountInfo();
+  CoreAccountInfo primary_account_info =
+      identity_manager->GetPrimaryAccountInfo();
   DCHECK_EQ(primary_account_info.email, kTestUser);
 
   auto* accounts_mutator = identity_manager->GetAccountsMutator();
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
index a521680b..56ba54a9 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
@@ -1518,7 +1518,7 @@
                                            *user_granted_device_info_);
 
     // Add the policy granted permissions for testing.
-    auto policy_value = base::JSONReader::Read(kUsbPolicySetting);
+    auto policy_value = base::JSONReader::ReadDeprecated(kUsbPolicySetting);
     DCHECK(policy_value);
     profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
                                *policy_value);
diff --git a/chrome/browser/ui/webui/settings/tts_handler.cc b/chrome/browser/ui/webui/settings/tts_handler.cc
index 31682187..440e917 100644
--- a/chrome/browser/ui/webui/settings/tts_handler.cc
+++ b/chrome/browser/ui/webui/settings/tts_handler.cc
@@ -132,7 +132,7 @@
     return;
 
   std::unique_ptr<base::DictionaryValue> json =
-      base::DictionaryValue::From(base::JSONReader::Read(voice_id));
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(voice_id));
   std::string name;
   std::string extension_id;
   json->GetString("name", &name);
diff --git a/chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.cc b/chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.cc
index a787163..d0a2735 100644
--- a/chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.cc
+++ b/chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.cc
@@ -174,8 +174,8 @@
 void SigninEmailConfirmationDialog::OnDialogClosed(
     const std::string& json_retval) {
   Action action = CLOSE;
-  std::unique_ptr<base::DictionaryValue> ret_value(
-      base::DictionaryValue::From(base::JSONReader::Read(json_retval)));
+  std::unique_ptr<base::DictionaryValue> ret_value(base::DictionaryValue::From(
+      base::JSONReader::ReadDeprecated(json_retval)));
   if (ret_value) {
     std::string action_string;
     if (ret_value->GetString(kSigninEmailConfirmationActionKey,
diff --git a/chrome/browser/ui/webui/site_settings_helper_unittest.cc b/chrome/browser/ui/webui/site_settings_helper_unittest.cc
index c0fc59f..3973786 100644
--- a/chrome/browser/ui/webui/site_settings_helper_unittest.cc
+++ b/chrome/browser/ui/webui/site_settings_helper_unittest.cc
@@ -482,7 +482,7 @@
                                            *ephemeral_device_info);
 
     // Add the policy granted permissions for testing.
-    auto policy_value = base::JSONReader::Read(kUsbPolicySetting);
+    auto policy_value = base::JSONReader::ReadDeprecated(kUsbPolicySetting);
     DCHECK(policy_value);
     profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
                                *policy_value);
diff --git a/chrome/browser/ui/webui/system_info_ui.cc b/chrome/browser/ui/webui/system_info_ui.cc
index 4b617b26..e2947a2 100644
--- a/chrome/browser/ui/webui/system_info_ui.cc
+++ b/chrome/browser/ui/webui/system_info_ui.cc
@@ -27,9 +27,10 @@
 #include "chrome/grit/browser_resources.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/feedback/system_logs/system_logs_fetcher.h"
-#include "content/public/browser/url_data_source.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
 #include "content/public/browser/web_ui_message_handler.h"
 #include "net/base/directory_lister.h"
 #include "net/base/escape.h"
@@ -42,47 +43,36 @@
 using content::WebUIMessageHandler;
 using system_logs::SystemLogsResponse;
 
-class SystemInfoUIHTMLSource : public content::URLDataSource{
- public:
-  SystemInfoUIHTMLSource();
-  ~SystemInfoUIHTMLSource() override {}
+namespace {
 
-  // content::URLDataSource implementation.
-  std::string GetSource() const override;
-  void StartDataRequest(
-      const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
-      const content::URLDataSource::GotDataCallback& callback) override;
-  std::string GetMimeType(const std::string&) const override {
-    return "text/html";
-  }
-  std::string GetContentSecurityPolicyScriptSrc() const override {
-    // 'unsafe-eval' and 'unsafe-inline' are added to script-src.
-    return "script-src 'self' chrome://resources 'unsafe-eval' "
-        "'unsafe-inline';";
-  }
+content::WebUIDataSource* CreateSystemInfoUIDataSource() {
+  content::WebUIDataSource* html_source =
+      content::WebUIDataSource::Create(chrome::kChromeUISystemInfoHost);
 
-  std::string GetContentSecurityPolicyStyleSrc() const override {
-    return "style-src 'self' chrome://resources 'unsafe-inline';";
-  }
+  html_source->AddLocalizedString("title", IDS_ABOUT_SYS_TITLE);
+  html_source->AddLocalizedString("description", IDS_ABOUT_SYS_DESC);
+  html_source->AddLocalizedString("tableTitle", IDS_ABOUT_SYS_TABLE_TITLE);
 
- private:
-  void SysInfoComplete(std::unique_ptr<SystemLogsResponse> response);
-  void RequestComplete();
-  void WaitForData();
+  html_source->AddLocalizedString("logFileTableTitle",
+                                  IDS_ABOUT_SYS_LOG_FILE_TABLE_TITLE);
+  html_source->AddLocalizedString("expandAllBtn", IDS_ABOUT_SYS_EXPAND_ALL);
+  html_source->AddLocalizedString("collapseAllBtn", IDS_ABOUT_SYS_COLLAPSE_ALL);
+  html_source->AddLocalizedString("expandBtn", IDS_ABOUT_SYS_EXPAND);
+  html_source->AddLocalizedString("collapseBtn", IDS_ABOUT_SYS_COLLAPSE);
+  html_source->AddLocalizedString("parseError", IDS_ABOUT_SYS_PARSE_ERROR);
 
-  // Stored data from StartDataRequest()
-  std::string path_;
-  content::URLDataSource::GotDataCallback callback_;
+  html_source->AddResourcePath("about_sys.js", IDR_ABOUT_SYS_JS);
+  html_source->AddResourcePath("about_sys.css", IDR_ABOUT_SYS_CSS);
+  html_source->SetDefaultResource(IDR_ABOUT_SYS_HTML);
+  html_source->SetJsonPath("strings.js");
+  html_source->UseGzip();
+  return html_source;
+}
 
-  std::unique_ptr<SystemLogsResponse> response_;
-  base::WeakPtrFactory<SystemInfoUIHTMLSource> weak_ptr_factory_;
-  DISALLOW_COPY_AND_ASSIGN(SystemInfoUIHTMLSource);
-};
+}  // namespace
 
 // The handler for Javascript messages related to the "system" view.
-class SystemInfoHandler : public WebUIMessageHandler,
-                          public base::SupportsWeakPtr<SystemInfoHandler> {
+class SystemInfoHandler : public WebUIMessageHandler {
  public:
   SystemInfoHandler();
   ~SystemInfoHandler() override;
@@ -90,97 +80,55 @@
   // WebUIMessageHandler implementation.
   void RegisterMessages() override;
 
+  // Callback for the "requestSystemInfo" message. This asynchronously requests
+  // system info and eventually returns it to the front end.
+  void HandleRequestSystemInfo(const base::ListValue*);
+
+  void OnSystemInfo(std::unique_ptr<SystemLogsResponse> sys_info);
+
  private:
+  base::WeakPtrFactory<SystemInfoHandler> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(SystemInfoHandler);
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //
-// SystemInfoUIHTMLSource
-//
-////////////////////////////////////////////////////////////////////////////////
-
-SystemInfoUIHTMLSource::SystemInfoUIHTMLSource() : weak_ptr_factory_(this) {}
-
-std::string SystemInfoUIHTMLSource::GetSource() const {
-  return chrome::kChromeUISystemInfoHost;
-}
-
-void SystemInfoUIHTMLSource::StartDataRequest(
-    const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
-    const content::URLDataSource::GotDataCallback& callback) {
-  path_ = path;
-  callback_ = callback;
-
-  system_logs::SystemLogsFetcher* fetcher =
-      system_logs::BuildAboutSystemLogsFetcher();
-  fetcher->Fetch(base::Bind(&SystemInfoUIHTMLSource::SysInfoComplete,
-                            weak_ptr_factory_.GetWeakPtr()));
-}
-
-void SystemInfoUIHTMLSource::SysInfoComplete(
-    std::unique_ptr<SystemLogsResponse> sys_info) {
-  response_ = std::move(sys_info);
-  RequestComplete();
-}
-
-void SystemInfoUIHTMLSource::RequestComplete() {
-  base::DictionaryValue strings;
-  strings.SetString("title", l10n_util::GetStringUTF16(IDS_ABOUT_SYS_TITLE));
-  strings.SetString("description",
-                    l10n_util::GetStringUTF16(IDS_ABOUT_SYS_DESC));
-  strings.SetString("tableTitle",
-                    l10n_util::GetStringUTF16(IDS_ABOUT_SYS_TABLE_TITLE));
-  strings.SetString(
-      "logFileTableTitle",
-      l10n_util::GetStringUTF16(IDS_ABOUT_SYS_LOG_FILE_TABLE_TITLE));
-  strings.SetString("expandAllBtn",
-                    l10n_util::GetStringUTF16(IDS_ABOUT_SYS_EXPAND_ALL));
-  strings.SetString("collapseAllBtn",
-                    l10n_util::GetStringUTF16(IDS_ABOUT_SYS_COLLAPSE_ALL));
-  strings.SetString("expandBtn",
-                    l10n_util::GetStringUTF16(IDS_ABOUT_SYS_EXPAND));
-  strings.SetString("collapseBtn",
-                    l10n_util::GetStringUTF16(IDS_ABOUT_SYS_COLLAPSE));
-  strings.SetString("parseError",
-                    l10n_util::GetStringUTF16(IDS_ABOUT_SYS_PARSE_ERROR));
-
-  const std::string& app_locale = g_browser_process->GetApplicationLocale();
-  webui::SetLoadTimeDataDefaults(app_locale, &strings);
-
-  if (response_.get()) {
-    auto details = std::make_unique<base::ListValue>();
-    for (SystemLogsResponse::const_iterator it = response_->begin();
-         it != response_->end();
-         ++it) {
-      std::unique_ptr<base::DictionaryValue> val(new base::DictionaryValue);
-      val->SetString("statName", it->first);
-      val->SetString("statValue", it->second);
-      details->Append(std::move(val));
-    }
-    strings.Set("details", std::move(details));
-  }
-  static const base::StringPiece systeminfo_html(
-      ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
-          IDR_ABOUT_SYS_HTML));
-  std::string full_html = webui::GetI18nTemplateHtml(systeminfo_html, &strings);
-  callback_.Run(base::RefCountedString::TakeString(&full_html));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
 // SystemInfoHandler
 //
 ////////////////////////////////////////////////////////////////////////////////
-SystemInfoHandler::SystemInfoHandler() {
-}
+SystemInfoHandler::SystemInfoHandler() : weak_ptr_factory_(this) {}
 
-SystemInfoHandler::~SystemInfoHandler() {
-}
+SystemInfoHandler::~SystemInfoHandler() {}
 
 void SystemInfoHandler::RegisterMessages() {
-  // TODO(stevenjb): add message registration, callbacks...
+  web_ui()->RegisterMessageCallback(
+      "requestSystemInfo",
+      base::BindRepeating(&SystemInfoHandler::HandleRequestSystemInfo,
+                          weak_ptr_factory_.GetWeakPtr()));
+}
+
+void SystemInfoHandler::HandleRequestSystemInfo(const base::ListValue*) {
+  AllowJavascript();
+  system_logs::SystemLogsFetcher* fetcher =
+      system_logs::BuildAboutSystemLogsFetcher();
+  fetcher->Fetch(base::BindOnce(&SystemInfoHandler::OnSystemInfo,
+                                weak_ptr_factory_.GetWeakPtr()));
+}
+
+void SystemInfoHandler::OnSystemInfo(
+    std::unique_ptr<SystemLogsResponse> sys_info) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (!sys_info)
+    return;
+  base::ListValue data;
+  for (SystemLogsResponse::const_iterator it = sys_info->begin();
+       it != sys_info->end(); ++it) {
+    auto val = std::make_unique<base::DictionaryValue>();
+    val->SetString("statName", it->first);
+    val->SetString("statValue", it->second);
+    data.Append(std::move(val));
+  }
+  CallJavascriptFunction("returnSystemInfo", data);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -193,6 +141,6 @@
   web_ui->AddMessageHandler(std::make_unique<SystemInfoHandler>());
 
   // Set up the chrome://system/ source.
-  content::URLDataSource::Add(Profile::FromWebUI(web_ui),
-                              std::make_unique<SystemInfoUIHTMLSource>());
+  content::WebUIDataSource::Add(Profile::FromWebUI(web_ui),
+                                CreateSystemInfoUIDataSource());
 }
diff --git a/chrome/browser/usb/usb_chooser_context_unittest.cc b/chrome/browser/usb/usb_chooser_context_unittest.cc
index 27ea63c9..8155ca9 100644
--- a/chrome/browser/usb/usb_chooser_context_unittest.cc
+++ b/chrome/browser/usb/usb_chooser_context_unittest.cc
@@ -457,7 +457,7 @@
   ExpectNoPermissions(store, *specific_device_info);
 
   profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
-                             *base::JSONReader::Read(kPolicySetting));
+                             *base::JSONReader::ReadDeprecated(kPolicySetting));
 
   ExpectCorrectPermissions(store, kValidRequestingOrigins,
                            kInvalidRequestingOrigins, *specific_device_info);
@@ -480,7 +480,7 @@
   ExpectNoPermissions(store, *vendor_related_device_info);
 
   profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
-                             *base::JSONReader::Read(kPolicySetting));
+                             *base::JSONReader::ReadDeprecated(kPolicySetting));
 
   ExpectCorrectPermissions(store, kValidRequestingOrigins,
                            kInvalidRequestingOrigins,
@@ -505,7 +505,7 @@
   ExpectNoPermissions(store, *unrelated_device_info);
 
   profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
-                             *base::JSONReader::Read(kPolicySetting));
+                             *base::JSONReader::ReadDeprecated(kPolicySetting));
 
   EXPECT_TRUE(store->HasDevicePermission(kGadgetOrigin, kCoolOrigin,
                                          *unrelated_device_info));
@@ -552,7 +552,7 @@
                                           *unrelated_device_info));
 
   profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
-                             *base::JSONReader::Read(kPolicySetting));
+                             *base::JSONReader::ReadDeprecated(kPolicySetting));
 
   EXPECT_TRUE(store->HasDevicePermission(
       kProductVendorOrigin, kProductVendorOrigin, *specific_device_info));
@@ -775,7 +775,7 @@
        GetAllGrantedObjectsWithOnlyPolicyAllowedDevices) {
   auto* store = GetChooserContext(profile());
   profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
-                             *base::JSONReader::Read(kPolicySetting));
+                             *base::JSONReader::ReadDeprecated(kPolicySetting));
 
   auto objects = store->GetAllGrantedObjects();
   ASSERT_EQ(objects.size(), 4u);
@@ -817,7 +817,7 @@
 TEST_F(UsbChooserContextTest,
        GetAllGrantedObjectsWithUserAndPolicyAllowedDevices) {
   profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
-                             *base::JSONReader::Read(kPolicySetting));
+                             *base::JSONReader::ReadDeprecated(kPolicySetting));
 
   const GURL kGoogleOrigin("https://www.google.com");
   UsbDeviceInfoPtr persistent_device_info =
@@ -898,7 +898,7 @@
        GetAllGrantedObjectsWithSpecificPolicyAndUserGrantedDevice) {
   auto* store = GetChooserContext(profile());
   profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
-                             *base::JSONReader::Read(kPolicySetting));
+                             *base::JSONReader::ReadDeprecated(kPolicySetting));
 
   const GURL kProductVendorOrigin("https://product.vendor.com");
   UsbDeviceInfoPtr persistent_device_info = device_manager_.CreateAndAddDevice(
@@ -960,7 +960,7 @@
 
   auto* store = GetChooserContext(profile());
   profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
-                             *base::JSONReader::Read(kPolicySetting));
+                             *base::JSONReader::ReadDeprecated(kPolicySetting));
 
   EXPECT_CALL(
       mock_permission_observer_,
@@ -1015,7 +1015,7 @@
 
   auto* store = GetChooserContext(profile());
   profile()->GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls,
-                             *base::JSONReader::Read(kPolicySetting));
+                             *base::JSONReader::ReadDeprecated(kPolicySetting));
 
   EXPECT_CALL(
       mock_permission_observer_,
diff --git a/chrome/browser/usb/usb_policy_allowed_devices_unittest.cc b/chrome/browser/usb/usb_policy_allowed_devices_unittest.cc
index f9285a1..591d8fd 100644
--- a/chrome/browser/usb/usb_policy_allowed_devices_unittest.cc
+++ b/chrome/browser/usb/usb_policy_allowed_devices_unittest.cc
@@ -90,7 +90,7 @@
 
 TEST_F(UsbPolicyAllowedDevicesTest, InitializeWithExistingPrefValue) {
   std::unique_ptr<base::Value> pref_value =
-      base::JSONReader::Read(kPolicySetting);
+      base::JSONReader::ReadDeprecated(kPolicySetting);
 
   SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value);
 
@@ -134,7 +134,7 @@
 
   // Ensure that the allowed devices can be dynamically updated.
   std::unique_ptr<base::Value> pref_value =
-      base::JSONReader::Read(kPolicySetting);
+      base::JSONReader::ReadDeprecated(kPolicySetting);
 
   SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value);
 
@@ -170,7 +170,7 @@
 TEST_F(UsbPolicyAllowedDevicesTest,
        InitializeWithExistingPolicyThenRemovePolicy) {
   std::unique_ptr<base::Value> pref_value =
-      base::JSONReader::Read(kPolicySetting);
+      base::JSONReader::ReadDeprecated(kPolicySetting);
 
   SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value);
 
@@ -232,7 +232,7 @@
 
 TEST_F(UsbPolicyAllowedDevicesTest,
        InitializeWithExistingPrefValueContainingDuplicateDevices) {
-  std::unique_ptr<base::Value> pref_value = base::JSONReader::Read(
+  std::unique_ptr<base::Value> pref_value = base::JSONReader::ReadDeprecated(
       kPolicySettingWithEntriesContainingDuplicateDevices);
 
   SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value);
@@ -273,8 +273,8 @@
 }  // namespace
 
 TEST_F(UsbPolicyAllowedDevicesTest, IsDeviceAllowed) {
-  std::unique_ptr<base::Value> pref_value =
-      base::JSONReader::Read(kPolicySettingWithEntriesMatchingMultipleDevices);
+  std::unique_ptr<base::Value> pref_value = base::JSONReader::ReadDeprecated(
+      kPolicySettingWithEntriesMatchingMultipleDevices);
 
   SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value);
 
@@ -341,8 +341,8 @@
 }
 
 TEST_F(UsbPolicyAllowedDevicesTest, IsDeviceAllowedForUrlsNotInPref) {
-  std::unique_ptr<base::Value> pref_value =
-      base::JSONReader::Read(kPolicySettingWithEntriesMatchingMultipleDevices);
+  std::unique_ptr<base::Value> pref_value = base::JSONReader::ReadDeprecated(
+      kPolicySettingWithEntriesMatchingMultipleDevices);
 
   SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value);
 
@@ -364,8 +364,8 @@
 }
 
 TEST_F(UsbPolicyAllowedDevicesTest, IsDeviceAllowedForDeviceNotInPref) {
-  std::unique_ptr<base::Value> pref_value =
-      base::JSONReader::Read(kPolicySettingWithEntriesMatchingMultipleDevices);
+  std::unique_ptr<base::Value> pref_value = base::JSONReader::ReadDeprecated(
+      kPolicySettingWithEntriesMatchingMultipleDevices);
 
   SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value);
 
@@ -401,8 +401,8 @@
 
 TEST_F(UsbPolicyAllowedDevicesTest,
        IsDeviceAllowedForUrlContainingEmbeddingOrigin) {
-  std::unique_ptr<base::Value> pref_value =
-      base::JSONReader::Read(kPolicySettingWithUrlContainingEmbeddingOrigin);
+  std::unique_ptr<base::Value> pref_value = base::JSONReader::ReadDeprecated(
+      kPolicySettingWithUrlContainingEmbeddingOrigin);
 
   SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value);
 
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 029c4a1..cf5447d 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut_mac.mm
+++ b/chrome/browser/web_applications/components/web_app_shortcut_mac.mm
@@ -823,6 +823,14 @@
             forKey:app_mode::kLSHasLocalizedDisplayNameKey];
   [plist setObject:[NSNumber numberWithBool:YES]
             forKey:app_mode::kNSHighResolutionCapableKey];
+  [plist
+      setObject:[NSNumber numberWithUnsignedInteger:
+                              app_mode::kCurrentChromeAppModeInfoMajorVersion]
+         forKey:app_mode::kCrAppModeMajorVersionKey];
+  [plist
+      setObject:[NSNumber numberWithUnsignedInteger:
+                              app_mode::kCurrentChromeAppModeInfoMinorVersion]
+         forKey:app_mode::kCrAppModeMinorVersionKey];
   if (info_->extension_id == app_mode::kAppListModeId) {
     // Prevent the app list from bouncing in the dock, and getting a run light.
     [plist setObject:[NSNumber numberWithBool:YES] forKey:kLSUIElement];
diff --git a/chrome/chrome_cleaner/parsers/json_parser/test_json_parser.cc b/chrome/chrome_cleaner/parsers/json_parser/test_json_parser.cc
index 43a205f4..d5eeafd 100644
--- a/chrome/chrome_cleaner/parsers/json_parser/test_json_parser.cc
+++ b/chrome/chrome_cleaner/parsers/json_parser/test_json_parser.cc
@@ -14,10 +14,12 @@
                            ParseDoneCallback callback) {
   int error_code;
   std::string error;
-  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-      json,
-      base::JSON_ALLOW_TRAILING_COMMAS | base::JSON_REPLACE_INVALID_CHARACTERS,
-      &error_code, &error);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          json,
+          base::JSON_ALLOW_TRAILING_COMMAS |
+              base::JSON_REPLACE_INVALID_CHARACTERS,
+          &error_code, &error);
   if (value) {
     std::move(callback).Run(base::make_optional(std::move(*value)),
                             base::nullopt);
diff --git a/chrome/chrome_cleaner/parsers/target/parser_impl.cc b/chrome/chrome_cleaner/parsers/target/parser_impl.cc
index 2d2a5812..b501230 100644
--- a/chrome/chrome_cleaner/parsers/target/parser_impl.cc
+++ b/chrome/chrome_cleaner/parsers/target/parser_impl.cc
@@ -24,10 +24,12 @@
                            ParseJsonCallback callback) {
   int error_code;
   std::string error;
-  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-      json,
-      base::JSON_ALLOW_TRAILING_COMMAS | base::JSON_REPLACE_INVALID_CHARACTERS,
-      &error_code, &error);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadAndReturnErrorDeprecated(
+          json,
+          base::JSON_ALLOW_TRAILING_COMMAS |
+              base::JSON_REPLACE_INVALID_CHARACTERS,
+          &error_code, &error);
   if (value) {
     std::move(callback).Run(base::make_optional(std::move(*value)),
                             base::nullopt);
diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc
index 2bd0853..cbfea8e 100644
--- a/chrome/common/chrome_content_client.cc
+++ b/chrome/common/chrome_content_client.cc
@@ -264,8 +264,9 @@
   if (!base::ReadFileToString(manifest_path, &manifest_data))
     return false;
 
-  std::unique_ptr<base::DictionaryValue> manifest = base::DictionaryValue::From(
-      base::JSONReader::Read(manifest_data, base::JSON_ALLOW_TRAILING_COMMAS));
+  std::unique_ptr<base::DictionaryValue> manifest =
+      base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
+          manifest_data, base::JSON_ALLOW_TRAILING_COMMAS));
   if (!manifest)
     return false;
 
diff --git a/chrome/common/cloud_print/cloud_print_helpers.cc b/chrome/common/cloud_print/cloud_print_helpers.cc
index e214002..54187afa7 100644
--- a/chrome/common/cloud_print/cloud_print_helpers.cc
+++ b/chrome/common/cloud_print/cloud_print_helpers.cc
@@ -188,7 +188,7 @@
     const std::string& response_data,
     bool* succeeded) {
   std::unique_ptr<base::Value> message_value(
-      base::JSONReader::Read(response_data));
+      base::JSONReader::ReadDeprecated(response_data));
   if (!message_value.get())
     return std::unique_ptr<base::DictionaryValue>();
 
diff --git a/chrome/common/mac/app_mode_common.h b/chrome/common/mac/app_mode_common.h
index 8b9423c..91f6440 100644
--- a/chrome/common/mac/app_mode_common.h
+++ b/chrome/common/mac/app_mode_common.h
@@ -119,6 +119,10 @@
 // system using this key.
 extern NSString* const kLastRunAppBundlePathPrefsKey;
 
+// The key for the major and minor version of an app.
+extern NSString* const kCrAppModeMajorVersionKey;
+extern NSString* const kCrAppModeMinorVersionKey;
+
 // Placeholders used in the app mode loader bundle' Info.plist:
 extern NSString* const kShortcutIdPlaceholder; // Extension shortcut ID.
 extern NSString* const kShortcutNamePlaceholder; // Extension name.
diff --git a/chrome/common/mac/app_mode_common.mm b/chrome/common/mac/app_mode_common.mm
index 4ffaaac..ad6c5441 100644
--- a/chrome/common/mac/app_mode_common.mm
+++ b/chrome/common/mac/app_mode_common.mm
@@ -44,6 +44,8 @@
 NSString* const kCrAppModeUserDataDirKey = @"CrAppModeUserDataDir";
 NSString* const kCrAppModeProfileDirKey = @"CrAppModeProfileDir";
 NSString* const kCrAppModeProfileNameKey = @"CrAppModeProfileName";
+NSString* const kCrAppModeMajorVersionKey = @"CrAppModeMajorVersionKey";
+NSString* const kCrAppModeMinorVersionKey = @"CrAppModeMinorVersionKey";
 
 NSString* const kLastRunAppBundlePathPrefsKey = @"LastRunAppBundlePath";
 
diff --git a/chrome/credential_provider/gaiacp/dllmain.cc b/chrome/credential_provider/gaiacp/dllmain.cc
index 0728b17..b549dae 100644
--- a/chrome/credential_provider/gaiacp/dllmain.cc
+++ b/chrome/credential_provider/gaiacp/dllmain.cc
@@ -164,8 +164,8 @@
 
   HRESULT hr = S_OK;
   base::DictionaryValue* dict = nullptr;
-  std::unique_ptr<base::Value> properties =
-      base::JSONReader::Read(buffer, base::JSON_ALLOW_TRAILING_COMMAS);
+  std::unique_ptr<base::Value> properties = base::JSONReader::ReadDeprecated(
+      buffer, base::JSON_ALLOW_TRAILING_COMMAS);
   if (!properties || !properties->GetAsDictionary(&dict)) {
     LOGFN(ERROR) << "base::JSONReader::Read failed length=" << buffer_len_bytes;
     hr = E_FAIL;
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base.cc b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
index 08e095c..ba1c5dc 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
@@ -1595,8 +1595,8 @@
   std::string json_string;
   base::UTF16ToUTF8(OLE2CW(authentication_info),
                     ::SysStringLen(authentication_info), &json_string);
-  std::unique_ptr<base::Value> properties =
-      base::JSONReader::Read(json_string, base::JSON_ALLOW_TRAILING_COMMAS);
+  std::unique_ptr<base::Value> properties = base::JSONReader::ReadDeprecated(
+      json_string, base::JSON_ALLOW_TRAILING_COMMAS);
   if (!properties || !properties->is_dict()) {
     LOGFN(ERROR) << "base::JSONReader::Read failed to translate to JSON";
     *status_text = AllocErrorString(IDS_INVALID_UI_RESPONSE_BASE);
diff --git a/chrome/renderer/net/net_error_helper_core.cc b/chrome/renderer/net/net_error_helper_core.cc
index 5b81f53d..0f660af 100644
--- a/chrome/renderer/net/net_error_helper_core.cc
+++ b/chrome/renderer/net/net_error_helper_core.cc
@@ -275,7 +275,8 @@
 std::unique_ptr<NavigationCorrectionResponse> ParseNavigationCorrectionResponse(
     const std::string raw_response) {
   // TODO(mmenke):  Open source related protocol buffers and use them directly.
-  std::unique_ptr<base::Value> parsed = base::JSONReader::Read(raw_response);
+  std::unique_ptr<base::Value> parsed =
+      base::JSONReader::ReadDeprecated(raw_response);
   std::unique_ptr<NavigationCorrectionResponse> response(
       new NavigationCorrectionResponse());
   base::JSONValueConverter<NavigationCorrectionResponse> converter;
diff --git a/chrome/service/cloud_print/print_system_cups.cc b/chrome/service/cloud_print/print_system_cups.cc
index 1a4af699..64654eec 100644
--- a/chrome/service/cloud_print/print_system_cups.cc
+++ b/chrome/service/cloud_print/print_system_cups.cc
@@ -530,7 +530,8 @@
     const std::string& print_ticket_mime_type) {
   DCHECK(initialized_);
   std::unique_ptr<base::DictionaryValue> ticket_value(
-      base::DictionaryValue::From(base::JSONReader::Read(print_ticket_data)));
+      base::DictionaryValue::From(
+          base::JSONReader::ReadDeprecated(print_ticket_data)));
   return !!ticket_value;
 }
 
@@ -540,7 +541,8 @@
     std::map<std::string, std::string>* options) {
   DCHECK(options);
   std::unique_ptr<base::DictionaryValue> ticket_value(
-      base::DictionaryValue::From(base::JSONReader::Read(print_ticket)));
+      base::DictionaryValue::From(
+          base::JSONReader::ReadDeprecated(print_ticket)));
   if (!ticket_value)
     return false;
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 30e9d34..5fd776c 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -571,6 +571,7 @@
       "../../apps/app_restore_service_browsertest.cc",
       "../../apps/load_and_launch_browsertest.cc",
       "../app/chrome_version.rc.version",
+      "../browser/accessibility/accessibility_labels_service_browsertest.cc",
       "../browser/accessibility/browser_accessibility_state_browsertest.cc",
       "../browser/accessibility/interstitial_accessibility_browsertest.cc",
       "../browser/app_controller_mac_browsertest.mm",
diff --git a/chrome/test/base/extension_js_browser_test.cc b/chrome/test/base/extension_js_browser_test.cc
index f2695ce9..1a68bef 100644
--- a/chrome/test/base/extension_js_browser_test.cc
+++ b/chrome/test/base/extension_js_browser_test.cc
@@ -53,7 +53,8 @@
           load_waiter_->extension_id(),
           script);
 
-  std::unique_ptr<base::Value> value_result = base::JSONReader::Read(result);
+  std::unique_ptr<base::Value> value_result =
+      base::JSONReader::ReadDeprecated(result);
   CHECK_EQ(base::Value::Type::DICTIONARY, value_result->type());
   base::DictionaryValue* dict_value =
       static_cast<base::DictionaryValue*>(value_result.get());
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index 2561bddc..88339f4 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -49,7 +49,6 @@
 #include "chrome/browser/profiles/storage_partition_descriptor.h"
 #include "chrome/browser/search_engines/template_url_fetcher_factory.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/browser/signin/gaia_cookie_manager_service_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/signin_util.h"
 #include "chrome/browser/sync/bookmark_sync_service_factory.h"
diff --git a/chrome/test/chromedriver/chrome/browser_info.cc b/chrome/test/chromedriver/chrome/browser_info.cc
index 33698eda..d36e690 100644
--- a/chrome/test/chromedriver/chrome/browser_info.cc
+++ b/chrome/test/chromedriver/chrome/browser_info.cc
@@ -34,7 +34,7 @@
 BrowserInfo::~BrowserInfo() {}
 
 Status ParseBrowserInfo(const std::string& data, BrowserInfo* browser_info) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(data);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(data);
   if (!value.get())
     return Status(kUnknownError, "version info not in JSON");
 
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.cc b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
index 491b9e2..1c39d43 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl.cc
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
@@ -32,7 +32,8 @@
     "Execution context with given id not found.";
 
 Status ParseInspectorError(const std::string& error_json) {
-  std::unique_ptr<base::Value> error = base::JSONReader::Read(error_json);
+  std::unique_ptr<base::Value> error =
+      base::JSONReader::ReadDeprecated(error_json);
   base::DictionaryValue* error_dict;
   if (!error || !error->GetAsDictionary(&error_dict))
     return Status(kUnknownError, "inspector error with no error message");
@@ -599,8 +600,8 @@
     InspectorCommandResponse* command_response) {
   // We want to allow invalid characters in case they are valid ECMAScript
   // strings. For example, webplatform tests use this to check string handling
-  std::unique_ptr<base::Value> message_value =
-      base::JSONReader::Read(message, base::JSON_REPLACE_INVALID_CHARACTERS);
+  std::unique_ptr<base::Value> message_value = base::JSONReader::ReadDeprecated(
+      message, base::JSON_REPLACE_INVALID_CHARACTERS);
   base::DictionaryValue* message_dict;
   if (!message_value || !message_value->GetAsDictionary(&message_dict))
     return false;
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc b/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
index ddee2c9..b82b37f5 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
@@ -43,7 +43,8 @@
 
   bool Send(const std::string& message) override {
     EXPECT_TRUE(connected_);
-    std::unique_ptr<base::Value> value = base::JSONReader::Read(message);
+    std::unique_ptr<base::Value> value =
+        base::JSONReader::ReadDeprecated(message);
     base::DictionaryValue* dict = NULL;
     EXPECT_TRUE(value->GetAsDictionary(&dict));
     if (!dict)
@@ -713,7 +714,8 @@
 
   bool Send(const std::string& message) override {
     EXPECT_TRUE(connected_);
-    std::unique_ptr<base::Value> value = base::JSONReader::Read(message);
+    std::unique_ptr<base::Value> value =
+        base::JSONReader::ReadDeprecated(message);
     base::DictionaryValue* dict = NULL;
     EXPECT_TRUE(value->GetAsDictionary(&dict));
     if (!dict)
@@ -1118,7 +1120,8 @@
   bool Connect(const GURL& url) override { return true; }
 
   bool Send(const std::string& message) override {
-    std::unique_ptr<base::Value> value = base::JSONReader::Read(message);
+    std::unique_ptr<base::Value> value =
+        base::JSONReader::ReadDeprecated(message);
     base::DictionaryValue* dict = nullptr;
     EXPECT_TRUE(value->GetAsDictionary(&dict));
     if (!dict)
diff --git a/chrome/test/chromedriver/chrome/devtools_http_client.cc b/chrome/test/chromedriver/chrome/devtools_http_client.cc
index cb7731f6..451ffabb 100644
--- a/chrome/test/chromedriver/chrome/devtools_http_client.cc
+++ b/chrome/test/chromedriver/chrome/devtools_http_client.cc
@@ -279,7 +279,7 @@
 namespace internal {
 
 Status ParseWebViewsInfo(const std::string& data, WebViewsInfo* views_info) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(data);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(data);
   if (!value.get())
     return Status(kUnknownError, "DevTools returned invalid JSON");
   base::ListValue* list;
diff --git a/chrome/test/chromedriver/chrome/dom_tracker_unittest.cc b/chrome/test/chromedriver/chrome/dom_tracker_unittest.cc
index da0938e6..8a1388e 100644
--- a/chrome/test/chromedriver/chrome/dom_tracker_unittest.cc
+++ b/chrome/test/chromedriver/chrome/dom_tracker_unittest.cc
@@ -60,7 +60,7 @@
       "     {\"nodeId\":102,\"frameId\":\"f\"}]"
       "}]";
   base::DictionaryValue params;
-  params.Set("nodes", base::JSONReader::Read(nodes));
+  params.Set("nodes", base::JSONReader::ReadDeprecated(nodes));
   ASSERT_EQ(kOk, tracker.OnEvent(&client, "DOM.setChildNodes", params).code());
   ASSERT_TRUE(tracker.GetFrameIdForNode(101, &frame_id).IsError());
   ASSERT_TRUE(frame_id.empty());
@@ -79,15 +79,15 @@
   std::string frame_id;
 
   base::DictionaryValue params;
-  params.Set("node", base::JSONReader::Read("{\"nodeId\":1}"));
+  params.Set("node", base::JSONReader::ReadDeprecated("{\"nodeId\":1}"));
   ASSERT_EQ(kOk,
             tracker.OnEvent(&client, "DOM.childNodeInserted", params).code());
   ASSERT_TRUE(tracker.GetFrameIdForNode(1, &frame_id).IsError());
   ASSERT_TRUE(frame_id.empty());
 
   params.Clear();
-  params.Set("node",
-             base::JSONReader::Read("{\"nodeId\":2,\"frameId\":\"f\"}"));
+  params.Set("node", base::JSONReader::ReadDeprecated(
+                         "{\"nodeId\":2,\"frameId\":\"f\"}"));
   ASSERT_EQ(kOk,
             tracker.OnEvent(&client, "DOM.childNodeInserted", params).code());
   ASSERT_TRUE(tracker.GetFrameIdForNode(2, &frame_id).IsOk());
diff --git a/chrome/test/chromedriver/chrome/frame_tracker_unittest.cc b/chrome/test/chromedriver/chrome/frame_tracker_unittest.cc
index d5cce7d..78af54d2 100644
--- a/chrome/test/chromedriver/chrome/frame_tracker_unittest.cc
+++ b/chrome/test/chromedriver/chrome/frame_tracker_unittest.cc
@@ -20,7 +20,7 @@
 
   const char context[] = "{\"id\":100,\"frameId\":\"f\"}";
   base::DictionaryValue params;
-  params.Set("context", base::JSONReader::Read(context));
+  params.Set("context", base::JSONReader::ReadDeprecated(context));
   ASSERT_EQ(kOk,
             tracker.OnEvent(&client, "Runtime.executionContextCreated", params)
                 .code());
@@ -51,7 +51,7 @@
 
   const char context[] = "{\"id\":100,\"auxData\":{}}";
   base::DictionaryValue params;
-  params.Set("context", base::JSONReader::Read(context));
+  params.Set("context", base::JSONReader::ReadDeprecated(context));
   params.SetString("context.auxData.frameId", "f");
   params.SetBoolean("context.auxData.isDefault", true);
   ASSERT_EQ(kOk,
@@ -70,7 +70,7 @@
 
   const char context[] = "{\"id\":1,\"frameId\":\"f\"}";
   base::DictionaryValue params;
-  params.Set("context", base::JSONReader::Read(context));
+  params.Set("context", base::JSONReader::ReadDeprecated(context));
   ASSERT_EQ(kOk,
             tracker.OnEvent(&client, "Runtime.executionContextCreated", params)
                 .code());
@@ -92,7 +92,7 @@
 
   const char context[] = "{\"id\":1,\"frameId\":\"f\"}";
   base::DictionaryValue params;
-  params.Set("context", base::JSONReader::Read(context));
+  params.Set("context", base::JSONReader::ReadDeprecated(context));
   ASSERT_EQ(kOk,
             tracker.OnEvent(&client, "Runtime.executionContextCreated", params)
                 .code());
diff --git a/chrome/test/chromedriver/chrome/heap_snapshot_taker.cc b/chrome/test/chromedriver/chrome/heap_snapshot_taker.cc
index 2eff863..9ea56718 100644
--- a/chrome/test/chromedriver/chrome/heap_snapshot_taker.cc
+++ b/chrome/test/chromedriver/chrome/heap_snapshot_taker.cc
@@ -28,7 +28,8 @@
 
   Status status3(kOk);
   if (status1.IsOk() && status2.IsOk()) {
-    std::unique_ptr<base::Value> value = base::JSONReader::Read(snapshot_);
+    std::unique_ptr<base::Value> value =
+        base::JSONReader::ReadDeprecated(snapshot_);
     if (!value) {
       status3 = Status(kUnknownError, "heap snapshot not in JSON format");
     } else {
diff --git a/chrome/test/chromedriver/chrome/log.cc b/chrome/test/chromedriver/chrome/log.cc
index 7ea41db..d564f94 100644
--- a/chrome/test/chromedriver/chrome/log.cc
+++ b/chrome/test/chromedriver/chrome/log.cc
@@ -104,7 +104,7 @@
 }
 
 std::string FormatJsonForDisplay(const std::string& json) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(json);
   if (!value)
     value.reset(new base::Value(json));
   return FormatValueForDisplay(*value);
diff --git a/chrome/test/chromedriver/chrome_launcher.cc b/chrome/test/chromedriver/chrome_launcher.cc
index d840d70..1a33052 100644
--- a/chrome/test/chromedriver/chrome_launcher.cc
+++ b/chrome/test/chromedriver/chrome_launcher.cc
@@ -842,7 +842,7 @@
   if (!base::ReadFileToString(manifest_path, &manifest_data))
     return Status(kUnknownError, "cannot read manifest");
   std::unique_ptr<base::Value> manifest_value =
-      base::JSONReader::Read(manifest_data);
+      base::JSONReader::ReadDeprecated(manifest_data);
   base::DictionaryValue* manifest;
   if (!manifest_value || !manifest_value->GetAsDictionary(&manifest))
     return Status(kUnknownError, "invalid manifest");
@@ -951,8 +951,8 @@
   int code;
   std::string error_msg;
   std::unique_ptr<base::Value> template_value =
-      base::JSONReader::ReadAndReturnError(template_string, 0, &code,
-                                           &error_msg);
+      base::JSONReader::ReadAndReturnErrorDeprecated(template_string, 0, &code,
+                                                     &error_msg);
   base::DictionaryValue* prefs;
   if (!template_value || !template_value->GetAsDictionary(&prefs)) {
     return Status(kUnknownError,
diff --git a/chrome/test/chromedriver/chrome_launcher_unittest.cc b/chrome/test/chromedriver/chrome_launcher_unittest.cc
index 88a27989c..1f4d385 100644
--- a/chrome/test/chromedriver/chrome_launcher_unittest.cc
+++ b/chrome/test/chromedriver/chrome_launcher_unittest.cc
@@ -92,7 +92,8 @@
   std::string manifest_txt;
   ASSERT_TRUE(base::ReadFileToString(
       temp_ext_path.AppendASCII("manifest.json"), &manifest_txt));
-  std::unique_ptr<base::Value> manifest = base::JSONReader::Read(manifest_txt);
+  std::unique_ptr<base::Value> manifest =
+      base::JSONReader::ReadDeprecated(manifest_txt);
   ASSERT_TRUE(manifest);
   base::DictionaryValue* manifest_dict = NULL;
   ASSERT_TRUE(manifest->GetAsDictionary(&manifest_dict));
@@ -184,7 +185,8 @@
                                   .Append(chrome::kPreferencesFilename);
   std::string prefs_str;
   ASSERT_TRUE(base::ReadFileToString(prefs_file, &prefs_str));
-  std::unique_ptr<base::Value> prefs_value = base::JSONReader::Read(prefs_str);
+  std::unique_ptr<base::Value> prefs_value =
+      base::JSONReader::ReadDeprecated(prefs_str);
   const base::DictionaryValue* prefs_dict = NULL;
   ASSERT_TRUE(prefs_value->GetAsDictionary(&prefs_dict));
   AssertEQ(*prefs_dict, "myPrefsKey", "ok");
@@ -195,7 +197,7 @@
   std::string local_state_str;
   ASSERT_TRUE(base::ReadFileToString(local_state_file, &local_state_str));
   std::unique_ptr<base::Value> local_state_value =
-      base::JSONReader::Read(local_state_str);
+      base::JSONReader::ReadDeprecated(local_state_str);
   const base::DictionaryValue* local_state_dict = NULL;
   ASSERT_TRUE(local_state_value->GetAsDictionary(&local_state_dict));
   AssertEQ(*local_state_dict, "myLocalKey", "ok");
diff --git a/chrome/test/chromedriver/log_replay/log_replay_socket.cc b/chrome/test/chromedriver/log_replay/log_replay_socket.cc
index 9653a405..8dad3bc 100644
--- a/chrome/test/chromedriver/log_replay/log_replay_socket.cc
+++ b/chrome/test/chromedriver/log_replay/log_replay_socket.cc
@@ -28,7 +28,7 @@
 }
 
 bool LogReplaySocket::Send(const std::string& message) {
-  std::unique_ptr<base::Value> json = base::JSONReader::Read(message);
+  std::unique_ptr<base::Value> json = base::JSONReader::ReadDeprecated(message);
   int id = json->FindKey("id")->GetInt();
   max_id_ = id;
   return true;
diff --git a/chrome/test/chromedriver/performance_logger_unittest.cc b/chrome/test/chromedriver/performance_logger_unittest.cc
index 071755c..40ec2847 100644
--- a/chrome/test/chromedriver/performance_logger_unittest.cc
+++ b/chrome/test/chromedriver/performance_logger_unittest.cc
@@ -132,8 +132,9 @@
 std::unique_ptr<base::DictionaryValue> ParseDictionary(
     const std::string& json) {
   std::string error;
-  std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
-      json, base::JSON_PARSE_RFC, nullptr, &error);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadAndReturnErrorDeprecated(json, base::JSON_PARSE_RFC,
+                                                     nullptr, &error);
   if (value == nullptr) {
     SCOPED_TRACE(json.c_str());
     SCOPED_TRACE(error.c_str());
diff --git a/chrome/test/chromedriver/server/http_handler.cc b/chrome/test/chromedriver/server/http_handler.cc
index 5ac166a99..e569da1aa 100644
--- a/chrome/test/chromedriver/server/http_handler.cc
+++ b/chrome/test/chromedriver/server/http_handler.cc
@@ -887,7 +887,7 @@
   if (request.data.length()) {
     base::DictionaryValue* body_params;
     std::unique_ptr<base::Value> parsed_body =
-        base::JSONReader::Read(request.data);
+        base::JSONReader::ReadDeprecated(request.data);
     if (!parsed_body || !parsed_body->GetAsDictionary(&body_params)) {
       if (kW3CDefault) {
         PrepareResponse(trimmed_path, send_response_func,
diff --git a/chrome/test/chromedriver/session_commands_unittest.cc b/chrome/test/chromedriver/session_commands_unittest.cc
index 37b9addd..39a7009 100644
--- a/chrome/test/chromedriver/session_commands_unittest.cc
+++ b/chrome/test/chromedriver/session_commands_unittest.cc
@@ -220,7 +220,8 @@
 
 Status ProcessCapabilitiesJson(const std::string& paramsJson,
                                base::DictionaryValue* result_capabilities) {
-  std::unique_ptr<base::Value> params = base::JSONReader::Read(paramsJson);
+  std::unique_ptr<base::Value> params =
+      base::JSONReader::ReadDeprecated(paramsJson);
   if (!params || !params->is_dict())
     return Status(kUnknownError);
   return ProcessCapabilities(
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 8acf770..ee0cbc8c 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -3315,6 +3315,16 @@
     ]
   },
 
+  "SchedulerConfiguration": {
+    "os": ["chromeos"],
+    "test_policy": { "SchedulerConfiguration": "performance" },
+    "pref_mappings": [
+      { "pref": "chromeos.scheduler_configuration",
+        "local_state": true
+      }
+    ]
+  },
+
   "CloudPolicyOverridesMachinePolicy": {
     "os": ["win", "linux", "mac"],
     "test_policy": { "CloudPolicyOverridesMachinePolicy": false },
diff --git a/chrome/test/data/webui/extensions/activity_log_stream_test.js b/chrome/test/data/webui/extensions/activity_log_stream_test.js
new file mode 100644
index 0000000..99aef3f7
--- /dev/null
+++ b/chrome/test/data/webui/extensions/activity_log_stream_test.js
@@ -0,0 +1,39 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** @fileoverview Suite of tests for activity-log-item. */
+suite('ExtensionsActivityLogStreamTest', function() {
+  /**
+   * Extension activityLogStream created before each test.
+   * @type {extensions.ActivityLogStream}
+   */
+  let activityLogStream;
+  let testVisible;
+
+  // Initialize an extension activity log item before each test.
+  setup(function() {
+    PolymerTest.clearBody();
+
+    activityLogStream = new extensions.ActivityLogStream();
+    testVisible = extension_test_util.testVisible.bind(null, activityLogStream);
+
+    document.body.appendChild(activityLogStream);
+  });
+
+  teardown(function() {
+    activityLogStream.remove();
+  });
+
+  test('button toggles stream on/off', function() {
+    Polymer.dom.flush();
+
+    // Stream should be on when element is first attached to the DOM.
+    testVisible('#activity-log-stream-header', true);
+    testVisible('#empty-stream-message', true);
+    expectTrue(activityLogStream.isStreamOnForTest());
+
+    activityLogStream.$$('#toggle-stream-button').click();
+    expectFalse(activityLogStream.isStreamOnForTest());
+  });
+});
diff --git a/chrome/test/data/webui/extensions/activity_log_test.js b/chrome/test/data/webui/extensions/activity_log_test.js
index a0d9e84dd..44e2d0e 100644
--- a/chrome/test/data/webui/extensions/activity_log_test.js
+++ b/chrome/test/data/webui/extensions/activity_log_test.js
@@ -173,4 +173,30 @@
     expectDeepEquals(
         currentPage, {page: Page.DETAILS, extensionId: EXTENSION_ID});
   });
+
+  test('tab transitions', function() {
+    Polymer.dom.flush();
+    // Default view should be the history view.
+    testVisible('activity-log-history', true);
+
+    // Navigate to the activity log stream.
+    activityLog.$$('#real-time-tab').click();
+    Polymer.dom.flush();
+    testVisible('activity-log-stream', true);
+
+    const activityLogStream = activityLog.$$('activity-log-stream');
+    assertTrue(activityLogStream.isStreamOnForTest());
+
+    // Navigate back to the activity log history tab.
+    activityLog.$$('#history-tab').click();
+
+    // Expect a refresh of the activity log.
+    proxyDelegate.whenCalled('getExtensionActivityLog').then(() => {
+      Polymer.dom.flush();
+      testVisible('activity-log-history', true);
+
+      // Stream should be turned off.
+      assertFalse(activityLogStream.isStreamOnForTest());
+    });
+  });
 });
diff --git a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
index 3ffd6939..731d0180 100644
--- a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
+++ b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
@@ -257,6 +257,26 @@
 });
 
 ////////////////////////////////////////////////////////////////////////////////
+// Extension Activity Log Stream Tests
+
+CrExtensionsActivityLogStreamTest = class extends CrExtensionsBrowserTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://extensions/activity_log/activity_log_stream.html';
+  }
+
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'activity_log_stream_test.js',
+    ]);
+  }
+};
+
+TEST_F('CrExtensionsActivityLogStreamTest', 'All', () => {
+  mocha.run();
+});
+
+////////////////////////////////////////////////////////////////////////////////
 // Extension Detail View Tests
 
 CrExtensionsDetailViewTest = class extends CrExtensionsBrowserTest {
diff --git a/chrome/test/media_router/media_router_integration_browsertest.cc b/chrome/test/media_router/media_router_integration_browsertest.cc
index a1d21bc..ba16fd1 100644
--- a/chrome/test/media_router/media_router_integration_browsertest.cc
+++ b/chrome/test/media_router/media_router_integration_browsertest.cc
@@ -114,8 +114,8 @@
   // Read the test result, the test result set by javascript is a
   // JSON string with the following format:
   // {"passed": "<true/false>", "errorMessage": "<error_message>"}
-  std::unique_ptr<base::Value> value =
-      base::JSONReader::Read(result, base::JSON_ALLOW_TRAILING_COMMAS);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
+      result, base::JSON_ALLOW_TRAILING_COMMAS);
 
   // Convert to dictionary.
   base::DictionaryValue* dict_value = nullptr;
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index cad10a0..74157733 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -328,13 +328,13 @@
 
 // Split tests into multiple tests, making it easier to isolate which tests are
 // failing, and reducing chance of timeout.
-PPAPI_SOCKET_TEST(TCPSocket_Connect);
-PPAPI_SOCKET_TEST(TCPSocket_ReadWrite);
-PPAPI_SOCKET_TEST(TCPSocket_SetOption);
-PPAPI_SOCKET_TEST(TCPSocket_Listen);
-PPAPI_SOCKET_TEST(TCPSocket_Backlog);
-PPAPI_SOCKET_TEST(TCPSocket_Interface_1_0);
-PPAPI_SOCKET_TEST(TCPSocket_UnexpectedCalls);
+PPAPI_SOCKET_TEST(TCPSocket_Connect)
+PPAPI_SOCKET_TEST(TCPSocket_ReadWrite)
+PPAPI_SOCKET_TEST(TCPSocket_SetOption)
+PPAPI_SOCKET_TEST(TCPSocket_Listen)
+PPAPI_SOCKET_TEST(TCPSocket_Backlog)
+PPAPI_SOCKET_TEST(TCPSocket_Interface_1_0)
+PPAPI_SOCKET_TEST(TCPSocket_UnexpectedCalls)
 
 TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(TCPServerSocketPrivate_Listen)
 TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(TCPServerSocketPrivate_Backlog)
@@ -875,136 +875,136 @@
 
 TCP_SOCKET_FAILURE_TEST(TCPSocket_ConnectClosePipe,
                         TCPSocket_ConnectFails,
-                        TCPFailureType::kConnectClosePipe);
+                        TCPFailureType::kConnectClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_ConnectError,
                         TCPSocket_ConnectFails,
-                        TCPFailureType::kConnectError);
+                        TCPFailureType::kConnectError)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_ConnectHangs,
                         TCPSocket_ConnectHangs,
-                        TCPFailureType::kConnectHangs);
+                        TCPFailureType::kConnectHangs)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_WriteClosePipe,
                         TCPSocket_WriteFails,
-                        TCPFailureType::kWriteClosePipe);
+                        TCPFailureType::kWriteClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_WriteError,
                         TCPSocket_WriteFails,
-                        TCPFailureType::kWriteError);
+                        TCPFailureType::kWriteError)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_ReadClosePipe,
                         TCPSocket_ReadFails,
-                        TCPFailureType::kReadClosePipe);
+                        TCPFailureType::kReadClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_ReadError,
                         TCPSocket_ReadFails,
-                        TCPFailureType::kReadError);
+                        TCPFailureType::kReadError)
 
 TCP_SOCKET_FAILURE_TEST(TCPSocket_SetSendBufferSizeClosePipe,
                         TCPSocket_SetSendBufferSizeFails,
-                        TCPFailureType::kSetOptionsClosePipe);
+                        TCPFailureType::kSetOptionsClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_SetSendBufferSizeError,
                         TCPSocket_SetSendBufferSizeFails,
-                        TCPFailureType::kSetOptionsError);
+                        TCPFailureType::kSetOptionsError)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_SetReceiveBufferSizeClosePipe,
                         TCPSocket_SetReceiveBufferSizeFails,
-                        TCPFailureType::kSetOptionsClosePipe);
+                        TCPFailureType::kSetOptionsClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_SetReceiveBufferSizeError,
                         TCPSocket_SetReceiveBufferSizeFails,
-                        TCPFailureType::kSetOptionsError);
+                        TCPFailureType::kSetOptionsError)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_SetNoDelayClosePipe,
                         TCPSocket_SetNoDelayFails,
-                        TCPFailureType::kSetOptionsClosePipe);
+                        TCPFailureType::kSetOptionsClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_SetNoDelayError,
                         TCPSocket_SetNoDelayFails,
-                        TCPFailureType::kSetOptionsError);
+                        TCPFailureType::kSetOptionsError)
 
 // Can't use TCPSocket_BindFailsConnectSucceeds for this one, because
 // BindClosePipe has to close the NetworkContext pipe.
 TCP_SOCKET_FAILURE_TEST(TCPSocket_BindClosePipe,
                         TCPSocket_BindFails,
-                        TCPFailureType::kBindClosePipe);
+                        TCPFailureType::kBindClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_BindError,
                         TCPSocket_BindFailsConnectSucceeds,
-                        TCPFailureType::kBindError);
+                        TCPFailureType::kBindError)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_BindHangs,
                         TCPSocket_BindHangs,
-                        TCPFailureType::kBindHangs);
+                        TCPFailureType::kBindHangs)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_ListenClosePipe,
                         TCPSocket_ListenFails,
-                        TCPFailureType::kCreateTCPServerSocketClosePipe);
+                        TCPFailureType::kCreateTCPServerSocketClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_ListenError,
                         TCPSocket_ListenFails,
-                        TCPFailureType::kCreateTCPServerSocketError);
+                        TCPFailureType::kCreateTCPServerSocketError)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_ListenHangs,
                         TCPSocket_ListenHangs,
-                        TCPFailureType::kCreateTCPServerSocketHangs);
+                        TCPFailureType::kCreateTCPServerSocketHangs)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_AcceptClosePipe,
                         TCPSocket_AcceptFails,
-                        TCPFailureType::kAcceptDropPipe);
+                        TCPFailureType::kAcceptDropPipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_AcceptError,
                         TCPSocket_AcceptFails,
-                        TCPFailureType::kAcceptError);
+                        TCPFailureType::kAcceptError)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_AcceptHangs,
                         TCPSocket_AcceptHangs,
-                        TCPFailureType::kAcceptHangs);
+                        TCPFailureType::kAcceptHangs)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_AcceptedSocketWriteClosePipe,
                         TCPSocket_AcceptedSocketWriteFails,
-                        TCPFailureType::kWriteClosePipe);
+                        TCPFailureType::kWriteClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_AcceptedSocketWriteError,
                         TCPSocket_AcceptedSocketWriteFails,
-                        TCPFailureType::kWriteError);
+                        TCPFailureType::kWriteError)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_AcceptedSocketReadClosePipe,
                         TCPSocket_AcceptedSocketReadFails,
-                        TCPFailureType::kReadClosePipe);
+                        TCPFailureType::kReadClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_AcceptedSocketReadError,
                         TCPSocket_AcceptedSocketReadFails,
-                        TCPFailureType::kReadError);
+                        TCPFailureType::kReadError)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_BindConnectClosePipe,
                         TCPSocket_BindConnectFails,
-                        TCPFailureType::kConnectClosePipe);
+                        TCPFailureType::kConnectClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_BindConnectError,
                         TCPSocket_BindConnectFails,
-                        TCPFailureType::kConnectError);
+                        TCPFailureType::kConnectError)
 TCP_SOCKET_FAILURE_TEST(TCPSocket_BindConnectHangs,
                         TCPSocket_BindConnectHangs,
-                        TCPFailureType::kConnectHangs);
+                        TCPFailureType::kConnectHangs)
 
 TCP_SOCKET_FAILURE_TEST(TCPSocketPrivate_SSLHandshakeClosePipe,
                         TCPSocketPrivate_SSLHandshakeFails,
-                        TCPFailureType::kUpgradeToTLSClosePipe);
+                        TCPFailureType::kUpgradeToTLSClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocketPrivate_SSLHandshakeError,
                         TCPSocketPrivate_SSLHandshakeFails,
-                        TCPFailureType::kUpgradeToTLSError);
+                        TCPFailureType::kUpgradeToTLSError)
 TCP_SOCKET_FAILURE_TEST(TCPSocketPrivate_SSLHandshakeHangs,
                         TCPSocketPrivate_SSLHandshakeHangs,
-                        TCPFailureType::kUpgradeToTLSHangs);
+                        TCPFailureType::kUpgradeToTLSHangs)
 TCP_SOCKET_FAILURE_TEST(TCPSocketPrivate_SSLWriteClosePipe,
                         TCPSocketPrivate_SSLWriteFails,
-                        TCPFailureType::kSSLWriteClosePipe);
+                        TCPFailureType::kSSLWriteClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocketPrivate_SSLWriteError,
                         TCPSocketPrivate_SSLWriteFails,
-                        TCPFailureType::kSSLWriteError);
+                        TCPFailureType::kSSLWriteError)
 TCP_SOCKET_FAILURE_TEST(TCPSocketPrivate_SSLReadClosePipe,
                         TCPSocketPrivate_SSLReadFails,
-                        TCPFailureType::kSSLReadClosePipe);
+                        TCPFailureType::kSSLReadClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPSocketPrivate_SSLReadError,
                         TCPSocketPrivate_SSLReadFails,
-                        TCPFailureType::kSSLReadError);
+                        TCPFailureType::kSSLReadError)
 
 TCP_SOCKET_FAILURE_TEST(TCPServerSocketPrivate_ListenClosePipe,
                         TCPServerSocketPrivate_ListenFails,
-                        TCPFailureType::kCreateTCPServerSocketClosePipe);
+                        TCPFailureType::kCreateTCPServerSocketClosePipe)
 TCP_SOCKET_FAILURE_TEST(TCPServerSocketPrivate_ListenError,
                         TCPServerSocketPrivate_ListenFails,
-                        TCPFailureType::kCreateTCPServerSocketError);
+                        TCPFailureType::kCreateTCPServerSocketError)
 TCP_SOCKET_FAILURE_TEST(TCPServerSocketPrivate_ListenHangs,
                         TCPServerSocketPrivate_ListenHangs,
-                        TCPFailureType::kCreateTCPServerSocketHangs);
+                        TCPFailureType::kCreateTCPServerSocketHangs)
 TCP_SOCKET_FAILURE_TEST(TCPServerSocketPrivate_AcceptClosePipe,
                         TCPServerSocketPrivate_AcceptFails,
-                        TCPFailureType::kAcceptDropPipe);
+                        TCPFailureType::kAcceptDropPipe)
 TCP_SOCKET_FAILURE_TEST(TCPServerSocketPrivate_AcceptError,
                         TCPServerSocketPrivate_AcceptFails,
-                        TCPFailureType::kAcceptError);
+                        TCPFailureType::kAcceptError)
 TCP_SOCKET_FAILURE_TEST(TCPServerSocketPrivate_AcceptHangs,
                         TCPServerSocketPrivate_AcceptHangs,
-                        TCPFailureType::kAcceptHangs);
+                        TCPFailureType::kAcceptHangs)
 
 // UDPSocket tests.
 
@@ -1216,33 +1216,33 @@
 
 UDPSOCKET_FAILURE_TEST(UDPSocket_BindError,
                        UDPSocket_BindFails,
-                       WrappedUDPSocket::FailureType::kBindError);
+                       WrappedUDPSocket::FailureType::kBindError)
 UDPSOCKET_FAILURE_TEST(UDPSocket_BindDropPipe,
                        UDPSocket_BindFails,
-                       WrappedUDPSocket::FailureType::kBindDropPipe);
+                       WrappedUDPSocket::FailureType::kBindDropPipe)
 UDPSOCKET_FAILURE_TEST(UDPSocket_SetBroadcastError,
                        UDPSocket_SetBroadcastFails,
-                       WrappedUDPSocket::FailureType::kBroadcastError);
+                       WrappedUDPSocket::FailureType::kBroadcastError)
 UDPSOCKET_FAILURE_TEST(UDPSocket_SetBroadcastDropPipe,
                        UDPSocket_SetBroadcastFails,
-                       WrappedUDPSocket::FailureType::kBroadcastDropPipe);
+                       WrappedUDPSocket::FailureType::kBroadcastDropPipe)
 UDPSOCKET_FAILURE_TEST(UDPSocket_SendToBeforeDropPipeFails,
                        UDPSocket_SendToFails,
-                       WrappedUDPSocket::FailureType::kSendToDropPipe);
+                       WrappedUDPSocket::FailureType::kSendToDropPipe)
 UDPSOCKET_FAILURE_TEST(UDPSocket_DropPipeAfterBindSendToFails,
                        UDPSocket_SendToFails,
-                       WrappedUDPSocket::FailureType::kSendToError);
+                       WrappedUDPSocket::FailureType::kSendToError)
 UDPSOCKET_FAILURE_TEST(UDPSocket_ReadError,
                        UDPSocket_ReadFails,
-                       WrappedUDPSocket::FailureType::kReadError);
+                       WrappedUDPSocket::FailureType::kReadError)
 UDPSOCKET_FAILURE_TEST(
     UDPSocket_DropReceiverPipeOnConstruction,
     UDPSocket_ReadFails,
-    WrappedUDPSocket::FailureType::kDropReceiverPipeOnConstruction);
+    WrappedUDPSocket::FailureType::kDropReceiverPipeOnConstruction)
 UDPSOCKET_FAILURE_TEST(
     UDPSocket_DropReceiverPipeOnReceiveMore,
     UDPSocket_ReadFails,
-    WrappedUDPSocket::FailureType::kDropReceiverPipeOnReceiveMore);
+    WrappedUDPSocket::FailureType::kDropReceiverPipeOnReceiveMore)
 
 // Disallowed socket tests.
 TEST_PPAPI_NACL_DISALLOWED_SOCKETS(HostResolverPrivateDisallowed)
@@ -1935,14 +1935,14 @@
   RUN_AUDIO_THREAD_CREATOR_SUBTESTS;
 }
 
-TEST_PPAPI_OUT_OF_PROCESS(View_CreatedVisible);
+TEST_PPAPI_OUT_OF_PROCESS(View_CreatedVisible)
 #if defined(OS_MACOSX)
 // http://crbug.com/474399
 #define MAYBE_View_CreatedVisible DISABLED_View_CreatedVisible
 #else
 #define MAYBE_View_CreatedVisible View_CreatedVisible
 #endif
-TEST_PPAPI_NACL(MAYBE_View_CreatedVisible);
+TEST_PPAPI_NACL(MAYBE_View_CreatedVisible)
 
 // This test ensures that plugins created in a background tab have their
 // initial visibility set to false. We don't bother testing in-process for this
diff --git a/chrome/test/remoting/qunit_browser_test_runner.cc b/chrome/test/remoting/qunit_browser_test_runner.cc
index 6f1ccda2..445f170e 100644
--- a/chrome/test/remoting/qunit_browser_test_runner.cc
+++ b/chrome/test/remoting/qunit_browser_test_runner.cc
@@ -23,8 +23,8 @@
       web_contents, "browserTestHarness.run();", &result));
 
   // Read in the JSON.
-  std::unique_ptr<base::Value> value =
-      base::JSONReader::Read(result, base::JSON_ALLOW_TRAILING_COMMAS);
+  std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(
+      result, base::JSON_ALLOW_TRAILING_COMMAS);
 
   // Convert to dictionary.
   base::DictionaryValue* dict_value = NULL;
diff --git a/chrome/test/remoting/remote_desktop_browsertest.cc b/chrome/test/remoting/remote_desktop_browsertest.cc
index 0054d07..da8394a7 100644
--- a/chrome/test/remoting/remote_desktop_browsertest.cc
+++ b/chrome/test/remoting/remote_desktop_browsertest.cc
@@ -890,8 +890,8 @@
   ASSERT_TRUE(base::ReadFileToString(absolute_path, &accounts_info));
 
   // Get the root dictionary from the input json file contents.
-  std::unique_ptr<base::Value> root =
-      base::JSONReader::Read(accounts_info, base::JSON_ALLOW_TRAILING_COMMAS);
+  std::unique_ptr<base::Value> root = base::JSONReader::ReadDeprecated(
+      accounts_info, base::JSON_ALLOW_TRAILING_COMMAS);
 
   const base::DictionaryValue* root_dict = NULL;
   ASSERT_TRUE(root.get() && root->GetAsDictionary(&root_dict));
diff --git a/chrome/utility/importer/nss_decryptor.cc b/chrome/utility/importer/nss_decryptor.cc
index fdeed09..ae3d785 100644
--- a/chrome/utility/importer/nss_decryptor.cc
+++ b/chrome/utility/importer/nss_decryptor.cc
@@ -296,7 +296,7 @@
   std::string json_content;
   base::ReadFileToString(json_file, &json_content);
   std::unique_ptr<base::Value> parsed_json(
-      base::JSONReader::Read(json_content));
+      base::JSONReader::ReadDeprecated(json_content));
   const base::DictionaryValue* password_dict;
   const base::ListValue* password_list;
   const base::ListValue* blacklist_domains;
diff --git a/chromecast/cast_shell_sandbox_policy b/chromecast/cast_shell_sandbox_policy
index 6e36b50..c0814ffd 100644
--- a/chromecast/cast_shell_sandbox_policy
+++ b/chromecast/cast_shell_sandbox_policy
@@ -16,6 +16,7 @@
       "fuchsia.ui.input.ImeVisibilityService",
       "fuchsia.ui.policy.Presenter",
       "fuchsia.ui.scenic.Scenic",
+      "fuchsia.ui.viewsv1.ViewManager",
       "fuchsia.vulkan.loader.Loader",
       "fuchsia.wlan.service.Wlan"
   ],
diff --git a/chromeos/components/proximity_auth/unlock_manager_impl.cc b/chromeos/components/proximity_auth/unlock_manager_impl.cc
index 5688a86..ce7ae90f 100644
--- a/chromeos/components/proximity_auth/unlock_manager_impl.cc
+++ b/chromeos/components/proximity_auth/unlock_manager_impl.cc
@@ -8,7 +8,9 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "base/time/default_clock.h"
 #include "base/time/time.h"
 #include "chromeos/components/multidevice/logging/logging.h"
 #include "chromeos/components/multidevice/remote_device_ref.h"
@@ -28,12 +30,18 @@
 
 // The maximum amount of time, in seconds, that the unlock manager can stay in
 // the 'waking up' state after resuming from sleep.
-const int kWakingUpDurationSecs = 15;
+constexpr base::TimeDelta kWakingUpDuration = base::TimeDelta::FromSeconds(15);
 
 // The limit, in seconds, on the elapsed time for an auth attempt. If an auth
 // attempt exceeds this limit, it will time out and be rejected. This is
 // provided as a failsafe, in case something goes wrong.
-const int kAuthAttemptTimeoutSecs = 5;
+constexpr base::TimeDelta kAuthAttemptTimeout = base::TimeDelta::FromSeconds(5);
+
+constexpr base::TimeDelta kMinGetUnlockableRemoteStatusDuration =
+    base::TimeDelta::FromMilliseconds(1);
+constexpr base::TimeDelta kMaxGetUnlockableRemoteStatusDuration =
+    base::TimeDelta::FromSeconds(15);
+const int kNumDurationMetricBuckets = 100;
 
 // Returns the remote device's security settings state, for metrics,
 // corresponding to a remote status update.
@@ -99,8 +107,6 @@
 
 }  // namespace
 
-class ProximityAuthPrefManager;
-
 UnlockManagerImpl::UnlockManagerImpl(
     ProximityAuthSystem::ScreenlockType screenlock_type,
     ProximityAuthClient* proximity_auth_client,
@@ -164,9 +170,14 @@
 
   life_cycle_ = life_cycle;
   if (life_cycle_) {
+    attempt_secure_connection_start_time_ =
+        base::DefaultClock::GetInstance()->Now();
+
     AttemptToStartRemoteDeviceLifecycle();
     SetWakingUpState(true /* is_waking_up */);
   } else {
+    ResetPerformanceMetricsTimestamps();
+
     if (proximity_monitor_)
       proximity_monitor_->RemoveObserver(this);
     proximity_monitor_.reset();
@@ -187,6 +198,9 @@
       proximity_monitor_->AddObserver(this);
     }
     GetMessenger()->AddObserver(this);
+
+    attempt_get_remote_status_start_time_ =
+        base::DefaultClock::GetInstance()->Now();
   }
 
   if (state == RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED)
@@ -378,7 +392,7 @@
           reject_auth_attempt_weak_ptr_factory_.GetWeakPtr(),
           SmartLockMetricsRecorder::SmartLockAuthResultFailureReason::
               kAuthAttemptTimedOut),
-      base::TimeDelta::FromSeconds(kAuthAttemptTimeoutSecs));
+      kAuthAttemptTimeout);
 
   if (screenlock_type_ == ProximityAuthSystem::SIGN_IN) {
     SendSignInChallenge();
@@ -509,6 +523,10 @@
 
   PA_LOG(INFO) << "Updating screenlock state from " << screenlock_state_
                << " to " << new_state;
+
+  if (new_state == ScreenlockState::AUTHENTICATED)
+    RecordUnlockableRemoteStatusReceived();
+
   proximity_auth_client_->UpdateScreenlockState(new_state);
   screenlock_state_ = new_state;
 }
@@ -536,7 +554,7 @@
         FROM_HERE,
         base::BindOnce(&UnlockManagerImpl::OnConnectionAttemptTimeOut,
                        clear_waking_up_state_weak_ptr_factory_.GetWeakPtr()),
-        base::TimeDelta::FromSeconds(kWakingUpDurationSecs));
+        kWakingUpDuration);
   }
 
   UpdateLockScreen();
@@ -625,4 +643,40 @@
   return life_cycle_->GetMessenger();
 }
 
+void UnlockManagerImpl::RecordUnlockableRemoteStatusReceived() {
+  if (attempt_secure_connection_start_time_.is_null() ||
+      attempt_get_remote_status_start_time_.is_null()) {
+    PA_LOG(WARNING) << "Attempted to RecordUnlockableRemoteStatusReceived() "
+                       "without initial timestamps recorded.";
+    NOTREACHED();
+  }
+
+  base::Time now = base::DefaultClock::GetInstance()->Now();
+  if (screenlock_type_ == ProximityAuthSystem::SESSION_LOCK) {
+    // Use a custom |max| to account for Smart Lock's timeout (larger than the
+    // default 10 seconds).
+    base::UmaHistogramCustomTimes(
+        "SmartLock.Performance.StartScanToReceiveUnlockableRemoteStatus."
+        "Duration.Unlock",
+        now - attempt_secure_connection_start_time_ /* sample */,
+        kMinGetUnlockableRemoteStatusDuration /* min */,
+        kMaxGetUnlockableRemoteStatusDuration /* max */,
+        kNumDurationMetricBuckets /* buckets */);
+
+    base::UmaHistogramTimes(
+        "SmartLock.Performance.AuthenticationToReceiveUnlockableRemoteStatus."
+        "Duration.Unlock",
+        now - attempt_get_remote_status_start_time_);
+  }
+
+  // TODO(crbug.com/905438): Implement similar SignIn metrics.
+
+  ResetPerformanceMetricsTimestamps();
+}
+
+void UnlockManagerImpl::ResetPerformanceMetricsTimestamps() {
+  attempt_secure_connection_start_time_ = base::Time();
+  attempt_get_remote_status_start_time_ = base::Time();
+}
+
 }  // namespace proximity_auth
diff --git a/chromeos/components/proximity_auth/unlock_manager_impl.h b/chromeos/components/proximity_auth/unlock_manager_impl.h
index dfeffb7..0da19963 100644
--- a/chromeos/components/proximity_auth/unlock_manager_impl.h
+++ b/chromeos/components/proximity_auth/unlock_manager_impl.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "chromeos/components/proximity_auth/messenger_observer.h"
 #include "chromeos/components/proximity_auth/proximity_auth_system.h"
@@ -155,6 +156,13 @@
   // yet authenticated.
   Messenger* GetMessenger();
 
+  // Records UMA performance metrics for the unlockable remote status being
+  // received.
+  void RecordUnlockableRemoteStatusReceived();
+
+  // Clears the timers for beginning a scan and fetching remote status.
+  void ResetPerformanceMetricsTimestamps();
+
   // Whether |this| manager is being used for sign-in or session unlock.
   const ProximityAuthSystem::ScreenlockType screenlock_type_;
 
@@ -197,6 +205,16 @@
   // The state of the current screen lock UI.
   ScreenlockState screenlock_state_;
 
+  // The timestamp of when UnlockManager begins to try to establish a secure
+  // connection to the requested remote device of the provided
+  // RemoteDeviceLifeCycle.
+  base::Time attempt_secure_connection_start_time_;
+
+  // The timestamp of when UnlockManager successfully establishes a secure
+  // connection to the requested remote device of the provided
+  // RemoteDeviceLifeCycle, and begins to try to fetch its "remote status".
+  base::Time attempt_get_remote_status_start_time_;
+
   // Used to clear the waking up state after a timeout.
   base::WeakPtrFactory<UnlockManagerImpl>
       clear_waking_up_state_weak_ptr_factory_;
diff --git a/chromeos/services/device_sync/device_sync_impl.cc b/chromeos/services/device_sync/device_sync_impl.cc
index 88ded80a..8737e74 100644
--- a/chromeos/services/device_sync/device_sync_impl.cc
+++ b/chromeos/services/device_sync/device_sync_impl.cc
@@ -504,13 +504,10 @@
 }
 
 void DeviceSyncImpl::ProcessPrimaryAccountInfo(
-    const AccountInfo& primary_account_info) {
-  // Note: We cannot use |primary_account_info.IsValid()| here because
-  //       IdentityTestEnvironment is buggy: https://crbug.com/830122. For now,
-  //       we simply check that the account ID is set.
-  // TODO(khorimoto): Use IsValid() once the aforementioned bug is fixed.
+    const CoreAccountInfo& primary_account_info) {
   if (primary_account_info.account_id.empty()) {
-    PA_LOG(ERROR) << "Primary account information is invalid; cannot proceed.";
+    PA_LOG(ERROR)
+        << "No primary account information available; cannot proceed.";
 
     // This situation should never occur in practice; early return here to
     // prevent test failures.
diff --git a/chromeos/services/device_sync/device_sync_impl.h b/chromeos/services/device_sync/device_sync_impl.h
index 6e94d1e..f3c5544a 100644
--- a/chromeos/services/device_sync/device_sync_impl.h
+++ b/chromeos/services/device_sync/device_sync_impl.h
@@ -175,7 +175,7 @@
   // DeviceSyncBase:
   void Shutdown() override;
 
-  void ProcessPrimaryAccountInfo(const AccountInfo& primary_account_info);
+  void ProcessPrimaryAccountInfo(const CoreAccountInfo& primary_account_info);
   void ConnectToPrefStore();
   void OnConnectedToPrefService(std::unique_ptr<PrefService> pref_service);
   void InitializeCryptAuthManagementObjects();
@@ -217,7 +217,7 @@
   std::unique_ptr<base::OneShotTimer> set_software_feature_timer_;
 
   Status status_;
-  AccountInfo primary_account_info_;
+  CoreAccountInfo primary_account_info_;
   std::unique_ptr<PrefService> pref_service_;
   base::flat_map<base::UnguessableToken,
                  std::unique_ptr<PendingSetSoftwareFeatureRequest>>
diff --git a/components/autofill/core/common/password_generation_util.cc b/components/autofill/core/common/password_generation_util.cc
index c040a3e..1e5af2baf 100644
--- a/components/autofill/core/common/password_generation_util.cc
+++ b/components/autofill/core/common/password_generation_util.cc
@@ -13,15 +13,6 @@
 namespace autofill {
 namespace password_generation {
 
-PasswordGenerationActions::PasswordGenerationActions()
-    : learn_more_visited(false),
-      password_accepted(false),
-      password_edited(false),
-      password_regenerated(false) {
-}
-
-PasswordGenerationActions::~PasswordGenerationActions() {
-}
 
 PasswordGenerationUIData::PasswordGenerationUIData(
     const gfx::RectF& bounds,
@@ -39,20 +30,6 @@
 
 PasswordGenerationUIData::~PasswordGenerationUIData() = default;
 
-void LogUserActions(PasswordGenerationActions actions) {
-  UserAction action = IGNORE_FEATURE;
-  if (actions.password_accepted) {
-    if (actions.password_edited)
-      action = ACCEPT_AFTER_EDITING;
-    else
-      action = ACCEPT_ORIGINAL_PASSWORD;
-  } else if (actions.learn_more_visited) {
-    action = LEARN_MORE;
-  }
-  UMA_HISTOGRAM_ENUMERATION("PasswordGeneration.UserActions",
-                            action, ACTION_ENUM_COUNT);
-}
-
 void LogPasswordGenerationEvent(PasswordGenerationEvent event) {
   UMA_HISTOGRAM_ENUMERATION("PasswordGeneration.Event",
                             event, EVENT_ENUM_COUNT);
diff --git a/components/autofill/core/common/password_generation_util.h b/components/autofill/core/common/password_generation_util.h
index fa350e9..b84433a 100644
--- a/components/autofill/core/common/password_generation_util.h
+++ b/components/autofill/core/common/password_generation_util.h
@@ -124,33 +124,8 @@
   autofill::PasswordForm password_form;
 };
 
-void LogUserActions(PasswordGenerationActions actions);
-
 void LogPasswordGenerationEvent(PasswordGenerationEvent event);
 
-// Enumerates user actions after password generation bubble is shown.
-// These are visible for testing purposes.
-enum UserAction {
-  // User closes the bubble without any meaningful actions (e.g. use backspace
-  // key, close the bubble, click outside the bubble, etc).
-  IGNORE_FEATURE,
-
-  // User navigates to the learn more page. Note that in the current
-  // implementation this will result in closing the bubble so this action
-  // doesn't overlap with the following two actions.
-  LEARN_MORE,
-
-  // User accepts the generated password without manually editing it (but
-  // including changing it through the regenerate button).
-  ACCEPT_ORIGINAL_PASSWORD,
-
-  // User accepts the gererated password after manually editing it.
-  ACCEPT_AFTER_EDITING,
-
-  // Number of enum entries, used for UMA histogram reporting macros.
-  ACTION_ENUM_COUNT
-};
-
 // Returns true if Password Generation is enabled according to the field
 // trial result and the flags.
 bool IsPasswordGenerationEnabled();
diff --git a/components/certificate_transparency/log_dns_client.cc b/components/certificate_transparency/log_dns_client.cc
index c95e336..518fbbc3 100644
--- a/components/certificate_transparency/log_dns_client.cc
+++ b/components/certificate_transparency/log_dns_client.cc
@@ -27,6 +27,7 @@
 #include "net/dns/dns_config.h"
 #include "net/dns/dns_response.h"
 #include "net/dns/dns_transaction.h"
+#include "net/dns/dns_util.h"
 #include "net/dns/public/dns_protocol.h"
 #include "net/dns/record_parsed.h"
 #include "net/dns/record_rdata.h"
@@ -471,7 +472,7 @@
       qname, net::dns_protocol::kTypeTXT,
       base::BindOnce(&AuditProofQueryImpl::OnDnsTransactionComplete,
                      weak_ptr_factory_.GetWeakPtr()),
-      net_log_);
+      net_log_, net::SecureDnsMode::AUTOMATIC);
 
   current_dns_transaction_->Start();
   return true;
diff --git a/components/crash/core/common/BUILD.gn b/components/crash/core/common/BUILD.gn
index 81912a5..8e2a696 100644
--- a/components/crash/core/common/BUILD.gn
+++ b/components/crash/core/common/BUILD.gn
@@ -65,8 +65,11 @@
     ]
   }
 
-  deps = [
+  public_deps = [
     ":crash_buildflags",
+  ]
+
+  deps = [
     "//base",
   ]
 
diff --git a/components/cronet/android/test/cronet_test_util.cc b/components/cronet/android/test/cronet_test_util.cc
index 00e06997..68563c1 100644
--- a/components/cronet/android/test/cronet_test_util.cc
+++ b/components/cronet/android/test/cronet_test_util.cc
@@ -111,6 +111,10 @@
       jcontext_adapter, base::Bind(&CleanupNetworkThreadOnNetworkThread));
 }
 
+jboolean JNI_CronetTestUtil_CanGetTaggedBytes(JNIEnv* env) {
+  return net::CanGetTaggedBytes();
+}
+
 jlong JNI_CronetTestUtil_GetTaggedBytes(JNIEnv* env,
                                         jint jexpected_tag) {
   return net::GetTaggedBytes(jexpected_tag);
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java
index 98654e5..33abd12 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamTest.java
@@ -27,6 +27,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.Log;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
@@ -55,6 +56,8 @@
  */
 @RunWith(BaseJUnit4ClassRunner.class)
 public class BidirectionalStreamTest {
+    private static final String TAG = BidirectionalStreamTest.class.getSimpleName();
+
     @Rule
     public final CronetTestRule mTestRule = new CronetTestRule();
 
@@ -1586,6 +1589,10 @@
     @OnlyRunNativeCronet
     @RequiresMinApi(10) // Tagging support added in API level 10: crrev.com/c/chromium/src/+/937583
     public void testTagging() throws Exception {
+        if (!CronetTestUtil.nativeCanGetTaggedBytes()) {
+            Log.i(TAG, "Skipping test - GetTaggedBytes unsupported.");
+            return;
+        }
         String url = Http2TestServer.getEchoStreamUrl();
 
         // Test untagged requests are given tag 0.
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java
index 77339a1..92a79f0 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestTest.java
@@ -61,6 +61,8 @@
  */
 @RunWith(BaseJUnit4ClassRunner.class)
 public class CronetUrlRequestTest {
+    private static final String TAG = CronetUrlRequestTest.class.getSimpleName();
+
     // URL used for base tests.
     private static final String TEST_URL = "http://127.0.0.1:8000";
 
@@ -2327,6 +2329,10 @@
     @Feature({"Cronet"})
     @RequiresMinApi(9) // Tagging support added in API level 9: crrev.com/c/chromium/src/+/930086
     public void testTagging() throws Exception {
+        if (!CronetTestUtil.nativeCanGetTaggedBytes()) {
+            Log.i(TAG, "Skipping test - GetTaggedBytes unsupported.");
+            return;
+        }
         String url = NativeTestServer.getEchoMethodURL();
 
         // Test untagged requests are given tag 0.
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
index 95350d0..5931625 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
@@ -22,6 +22,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.Log;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.net.CronetEngine;
@@ -67,6 +68,8 @@
  */
 @RunWith(BaseJUnit4ClassRunner.class)
 public class CronetHttpURLConnectionTest {
+    private static final String TAG = CronetHttpURLConnectionTest.class.getSimpleName();
+
     @Rule
     public final CronetTestRule mTestRule = new CronetTestRule();
 
@@ -1359,6 +1362,10 @@
     @Feature({"Cronet"})
     @RequiresMinApi(9) // Tagging support added in API level 9: crrev.com/c/chromium/src/+/930086
     public void testTagging() throws Exception {
+        if (!CronetTestUtil.nativeCanGetTaggedBytes()) {
+            Log.i(TAG, "Skipping test - GetTaggedBytes unsupported.");
+            return;
+        }
         URL url = new URL(NativeTestServer.getEchoMethodURL());
 
         // Test untagged requests are given tag 0.
diff --git a/components/cronet/android/test/src/org/chromium/net/CronetTestUtil.java b/components/cronet/android/test/src/org/chromium/net/CronetTestUtil.java
index 0b6ea26..5bb884b 100644
--- a/components/cronet/android/test/src/org/chromium/net/CronetTestUtil.java
+++ b/components/cronet/android/test/src/org/chromium/net/CronetTestUtil.java
@@ -87,6 +87,11 @@
     }
 
     /**
+     * Returns whether the device supports calling nativeGetTaggedBytes().
+     */
+    public static native boolean nativeCanGetTaggedBytes();
+
+    /**
      * Query the system to find out how many bytes were received with tag
      * {@code expectedTag} for our UID.
      * @param expectedTag the tag to query for.
diff --git a/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc b/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc
index 5ff2db4..5696fd8a 100644
--- a/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc
+++ b/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc
@@ -105,7 +105,7 @@
     content::ResourceRequestInfo::AllocateForTesting(
         request, resource_type, nullptr, -1, -1, -1,
         resource_type == content::RESOURCE_TYPE_MAIN_FRAME,
-        false,  // allow_download
+        content::ResourceInterceptPolicy::kAllowNone,
         false,  // is_async
         previews_state,
         nullptr);  // navigation_ui_data
diff --git a/components/data_reduction_proxy/content/browser/content_lofi_ui_service_unittest.cc b/components/data_reduction_proxy/content/browser/content_lofi_ui_service_unittest.cc
index 7fa8efb..d1ed6bc 100644
--- a/components/data_reduction_proxy/content/browser/content_lofi_ui_service_unittest.cc
+++ b/components/data_reduction_proxy/content/browser/content_lofi_ui_service_unittest.cc
@@ -74,8 +74,7 @@
         request.get(), content::RESOURCE_TYPE_SUB_FRAME, nullptr,
         web_contents()->GetMainFrame()->GetProcess()->GetID(), -1,
         web_contents()->GetMainFrame()->GetRoutingID(),
-        /*is_main_frame=*/false,
-        /*allow_download=*/false,
+        /*is_main_frame=*/false, content::ResourceInterceptPolicy::kAllowNone,
         /*is_async=*/false, content::SERVER_LOFI_ON,
         /*navigation_ui_data*/ nullptr);
 
diff --git a/components/data_reduction_proxy/content/browser/content_resource_type_provider_unittest.cc b/components/data_reduction_proxy/content/browser/content_resource_type_provider_unittest.cc
index 86baaaf..1832a00 100644
--- a/components/data_reduction_proxy/content/browser/content_resource_type_provider_unittest.cc
+++ b/components/data_reduction_proxy/content/browser/content_resource_type_provider_unittest.cc
@@ -104,7 +104,7 @@
     content::ResourceRequestInfo::AllocateForTesting(
         request, resource_type, nullptr, -1, -1, -1,
         resource_type == content::RESOURCE_TYPE_MAIN_FRAME,
-        false,  // allow_download
+        content::ResourceInterceptPolicy::kAllowNone,
         false,  // is_async
         content::PREVIEWS_OFF,
         nullptr);  // navigation_ui_data
diff --git a/components/language/content/browser/ulp_language_code_locator/s2langquadtree.cc b/components/language/content/browser/ulp_language_code_locator/s2langquadtree.cc
index d621d6d3..eb85e369 100644
--- a/components/language/content/browser/ulp_language_code_locator/s2langquadtree.cc
+++ b/components/language/content/browser/ulp_language_code_locator/s2langquadtree.cc
@@ -12,19 +12,20 @@
     default;
 S2LangQuadTreeNode::~S2LangQuadTreeNode() = default;
 
-std::string S2LangQuadTreeNode::Get(const S2CellId& cell) const {
+std::string S2LangQuadTreeNode::Get(const S2CellId& cell,
+                                    int* level_ptr) const {
   const S2LangQuadTreeNode* node = this;
-  const std::string* language = &(node->language_);
-  for (int current_level = 1; current_level <= cell.level(); ++current_level) {
-    const S2LangQuadTreeNode* const child =
-        node->GetChild(cell.child_position(current_level));
-    if (child == nullptr)
-      break;
-    node = child;
-    if (!node->language_.empty())
-      language = &(node->language_);
+  for (int current_level = 0; current_level <= cell.level(); current_level++) {
+    if (node == nullptr || !node->language_.empty()) {
+      *level_ptr = current_level;
+      return node == nullptr ? "" : node->language_;
+    }
+
+    if (current_level < cell.level())
+      node = node->GetChild(cell.child_position(current_level + 1));
   }
-  return *language;
+  *level_ptr = -1;
+  return "";
 }
 
 const S2LangQuadTreeNode* S2LangQuadTreeNode::GetChild(
diff --git a/components/language/content/browser/ulp_language_code_locator/s2langquadtree.h b/components/language/content/browser/ulp_language_code_locator/s2langquadtree.h
index 1b39848b..befc66e 100644
--- a/components/language/content/browser/ulp_language_code_locator/s2langquadtree.h
+++ b/components/language/content/browser/ulp_language_code_locator/s2langquadtree.h
@@ -21,9 +21,15 @@
   S2LangQuadTreeNode(const S2LangQuadTreeNode& other);
   ~S2LangQuadTreeNode();
 
-  // Return the language in the deepest/lowest/smallest node containing the
-  // given cell.
-  std::string Get(const S2CellId& cell) const;
+  // Return language of the leaf containing the given |cell|.
+  // Empty string if a null-leaf contains given |cell|.
+  // |level_ptr| is set to the level (see S2CellId::level) of the leaf. (-1 if
+  // |cell| matches an internal node).
+  std::string Get(const S2CellId& cell, int* level_ptr) const;
+  std::string Get(const S2CellId& cell) const {
+    int level;
+    return Get(cell, &level);
+  }
 
   // Reconstruct a S2LangQuadTree with structure given by |tree| and with
   // languages given by |languages|. |tree| represents a depth-first traversal
diff --git a/components/language/content/browser/ulp_language_code_locator/s2langquadtree_datatest.cc b/components/language/content/browser/ulp_language_code_locator/s2langquadtree_datatest.cc
index 31d1ec8..3876d058 100644
--- a/components/language/content/browser/ulp_language_code_locator/s2langquadtree_datatest.cc
+++ b/components/language/content/browser/ulp_language_code_locator/s2langquadtree_datatest.cc
@@ -57,19 +57,19 @@
   }
 }
 
-TEST(UlpLanguageCodeLocatorDataTest, TreeContainsDataRank0) {
+TEST(S2LangQuadTreeDataTest, TreeContainsDataRank0) {
   ExpectTreeContainsData(S2LangQuadTreeNode::Deserialize(
                              GetLanguagesRank0(), GetTreeSerializedRank0()),
                          GetData(0));
 }
 
-TEST(UlpLanguageCodeLocatorDataTest, TreeContainsDataRank1) {
+TEST(S2LangQuadTreeDataTest, TreeContainsDataRank1) {
   ExpectTreeContainsData(S2LangQuadTreeNode::Deserialize(
                              GetLanguagesRank1(), GetTreeSerializedRank1()),
                          GetData(1));
 }
 
-TEST(UlpLanguageCodeLocatorDataTest, TreeContainsDataRank2) {
+TEST(S2LangQuadTreeDataTest, TreeContainsDataRank2) {
   ExpectTreeContainsData(S2LangQuadTreeNode::Deserialize(
                              GetLanguagesRank2(), GetTreeSerializedRank2()),
                          GetData(2));
diff --git a/components/language/content/browser/ulp_language_code_locator/s2langquadtree_unittest.cc b/components/language/content/browser/ulp_language_code_locator/s2langquadtree_unittest.cc
index 8149393..f80da8c0 100644
--- a/components/language/content/browser/ulp_language_code_locator/s2langquadtree_unittest.cc
+++ b/components/language/content/browser/ulp_language_code_locator/s2langquadtree_unittest.cc
@@ -26,8 +26,10 @@
 TEST(S2LangQuadTreeTest, Empty) {
   S2LangQuadTreeNode root;
   const S2CellId cell = S2CellId::FromFace(0);
-  const std::string language = root.Get(cell);
+  int level;
+  const std::string language = root.Get(cell, &level);
   EXPECT_TRUE(language.empty());
+  EXPECT_EQ(level, -1);
 }
 
 TEST(S2LangQuadTreeTest, RootIsLeaf_FaceIsPresent) {
@@ -35,8 +37,10 @@
   const std::bitset<2> tree("11");  // String is in reverse order.
   const S2LangQuadTreeNode root = GetTree(languages, tree);
   const S2CellId cell = S2CellId::FromFace(0);
-  const std::string language = root.Get(cell);
+  int level;
+  const std::string language = root.Get(cell, &level);
   EXPECT_EQ(language, "fr");
+  EXPECT_EQ(level, 0);
 }
 
 TEST(S2LangQuadTreeTest, RootIsLeaf_FaceChildGetsFaceLanguage) {
@@ -44,8 +48,10 @@
   const std::bitset<2> tree("11");  // String is in reverse order.
   const S2LangQuadTreeNode root = GetTree(languages, tree);
   const S2CellId cell = S2CellId::FromFace(0).child(0);
-  const std::string language = root.Get(cell);
+  int level;
+  const std::string language = root.Get(cell, &level);
   EXPECT_EQ(language, "fr");
+  EXPECT_EQ(level, 0);
 }
 
 TEST(S2LangQuadTreeTest, RootThenSingleLeaf_LeafIsPresent) {
@@ -53,8 +59,10 @@
   const std::bitset<9> tree("110101010");  // String is in reverse order.
   const S2LangQuadTreeNode root = GetTree(languages, tree);
   const S2CellId cell = S2CellId::FromFace(0).child(3);
-  const std::string language = root.Get(cell);
+  int level;
+  const std::string language = root.Get(cell, &level);
   EXPECT_EQ(language, "fr");
+  EXPECT_EQ(level, 1);
 }
 
 TEST(S2LangQuadTreeTest, RootThenSingleLeaf_ParentIsAbsent) {
@@ -62,9 +70,10 @@
   const std::bitset<9> tree("110101010");  // String is in reverse order.
   const S2LangQuadTreeNode root = GetTree(languages, tree);
   const S2CellId cell = S2CellId::FromFace(0);
-  const std::string language = root.Get(cell);
-  LOG(INFO) << language;
+  int level;
+  const std::string language = root.Get(cell, &level);
   EXPECT_TRUE(language.empty());
+  EXPECT_EQ(level, -1);
 }
 
 TEST(S2LangQuadTreeTest, RootThenSingleLeaf_SiblingIsAbsent) {
@@ -72,8 +81,10 @@
   const std::bitset<9> tree("110101010");  // String is in reverse order.
   const S2LangQuadTreeNode root = GetTree(languages, tree);
   const S2CellId cell = S2CellId::FromFace(0).child(0);
-  const std::string language = root.Get(cell);
+  int level;
+  const std::string language = root.Get(cell, &level);
   EXPECT_TRUE(language.empty());
+  EXPECT_EQ(level, 1);
 }
 
 TEST(S2LangQuadTreeTest, RootThenAllLeaves_LeavesArePresent) {
@@ -82,12 +93,16 @@
   const S2LangQuadTreeNode root = GetTree(languages, tree);
   for (int leaf_index = 0; leaf_index < 3; leaf_index++) {
     const S2CellId cell = S2CellId::FromFace(0).child(leaf_index);
-    const std::string language = root.Get(cell);
+    int level;
+    const std::string language = root.Get(cell, &level);
     EXPECT_EQ(language, "fr");
+    EXPECT_EQ(level, 1);
   }
   const S2CellId cell = S2CellId::FromFace(0).child(3);
-  const std::string language = root.Get(cell);
+  int level;
+  const std::string language = root.Get(cell, &level);
   EXPECT_EQ(language, "en");
+  EXPECT_EQ(level, 1);
 }
 
 TEST(S2LangQuadTreeTest, RootThenAllLeaves_ParentIsAbsent) {
@@ -95,8 +110,10 @@
   const std::bitset<13> tree("0111011011010");  // String is in reverse order.
   const S2LangQuadTreeNode root = GetTree(languages, tree);
   const S2CellId cell = S2CellId::FromFace(0);
-  const std::string language = root.Get(cell);
+  int level;
+  const std::string language = root.Get(cell, &level);
   EXPECT_TRUE(language.empty());
+  EXPECT_EQ(level, -1);
 }
 
 }  // namespace language
diff --git a/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.cc b/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.cc
index 79c36ae7..8db35e6 100644
--- a/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.cc
+++ b/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.cc
@@ -12,9 +12,15 @@
 
 namespace language {
 
+struct UlpLanguageCodeLocator::CellLanguagePair {
+  S2CellId cell = S2CellId::None();
+  std::string language = "";
+};
+
 UlpLanguageCodeLocator::UlpLanguageCodeLocator(
     std::vector<std::unique_ptr<S2LangQuadTreeNode>>&& roots) {
   roots_ = std::move(roots);
+  cache_ = std::vector<CellLanguagePair>(roots_.size());
 }
 
 UlpLanguageCodeLocator::~UlpLanguageCodeLocator() {}
@@ -24,8 +30,22 @@
     double longitude) const {
   S2CellId cell(S2LatLng::FromDegrees(latitude, longitude));
   std::vector<std::string> languages;
-  for (const auto& root : roots_) {
-    const std::string language = root.get()->Get(cell);
+  for (size_t index = 0; index < roots_.size(); index++) {
+    CellLanguagePair cached = cache_[index];
+    std::string language;
+    if (cached.cell.is_valid() && cached.cell.contains(cell)) {
+      language = cached.language;
+    } else {
+      const auto& root = roots_[index];
+      int level;
+      language = root.get()->Get(cell, &level);
+      if (level != -1) {
+        //|cell|.parent(|level|) is the ancestor S2Cell of |cell| for which
+        // there's a matching language in the tree.
+        cache_[index].cell = cell.parent(level);
+        cache_[index].language = language;
+      }
+    }
     if (!language.empty())
       languages.push_back(language);
   }
diff --git a/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.h b/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.h
index 61b0f8e..940daf2 100644
--- a/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.h
+++ b/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.h
@@ -31,6 +31,8 @@
 
  private:
   std::vector<std::unique_ptr<S2LangQuadTreeNode>> roots_;
+  struct CellLanguagePair;
+  mutable std::vector<CellLanguagePair> cache_;
   DISALLOW_COPY_AND_ASSIGN(UlpLanguageCodeLocator);
 };
 }  // namespace language
diff --git a/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator_unittest.cc b/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator_unittest.cc
index 3bdc553..b159ec2 100644
--- a/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator_unittest.cc
+++ b/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator_unittest.cc
@@ -49,7 +49,7 @@
   EXPECT_THAT(languages, ::testing::ElementsAreArray(languages_expected));
 }
 
-TEST(UlpLanguageCodeLocatorTest, QuadrantMatchLanguages) {
+TEST(UlpLanguageCodeLocatorTest, TreeLeaves) {
   std::vector<std::unique_ptr<S2LangQuadTreeNode>> roots = GetTestTrees();
   const UlpLanguageCodeLocator locator(std::move(roots));
   const S2CellId face = S2CellId::FromFace(0);
@@ -59,4 +59,32 @@
   ExpectLatLngHasLanguages(locator, face.child(2), {"fr", "en"});
   ExpectLatLngHasLanguages(locator, face.child(3), {"en", "en"});
 }
+
+TEST(UlpLanguageCodeLocatorTest, Idempotence) {
+  std::vector<std::unique_ptr<S2LangQuadTreeNode>> roots = GetTestTrees();
+  const UlpLanguageCodeLocator locator(std::move(roots));
+  const S2CellId face = S2CellId::FromFace(0);
+
+  ExpectLatLngHasLanguages(locator, face.child(0), {"fr", "de"});
+  ExpectLatLngHasLanguages(locator, face.child(0), {"fr", "de"});
+
+  ExpectLatLngHasLanguages(locator, face.child(3), {"en", "en"});
+  ExpectLatLngHasLanguages(locator, face.child(3), {"en", "en"});
+}
+
+TEST(UlpLanguageCodeLocatorTest, TreeLeafDescendants) {
+  std::vector<std::unique_ptr<S2LangQuadTreeNode>> roots = GetTestTrees();
+  const UlpLanguageCodeLocator locator(std::move(roots));
+  const S2CellId cell = S2CellId::FromFace(0).child(0);
+
+  ExpectLatLngHasLanguages(locator, cell, {"fr", "de"});
+
+  const int depth = 2;
+  // Check that the 4**|depth| descendants of |child| map to the same language.
+  const int level = cell.level() + depth;
+  for (S2CellId descendant = cell.child_begin(level);
+       descendant != cell.child_end(level); descendant = descendant.next())
+    ExpectLatLngHasLanguages(locator, descendant, {"fr", "de"});
+}
+
 }  // namespace language
diff --git a/components/navigation_interception/intercept_navigation_delegate.cc b/components/navigation_interception/intercept_navigation_delegate.cc
index a6163478..3939a36 100644
--- a/components/navigation_interception/intercept_navigation_delegate.cc
+++ b/components/navigation_interception/intercept_navigation_delegate.cc
@@ -10,7 +10,6 @@
 #include "base/android/jni_string.h"
 #include "base/bind.h"
 #include "base/callback.h"
-#include "components/navigation_interception/intercept_navigation_throttle.h"
 #include "components/navigation_interception/navigation_params_android.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_throttle.h"
@@ -70,9 +69,10 @@
 // static
 std::unique_ptr<content::NavigationThrottle>
 InterceptNavigationDelegate::CreateThrottleFor(
-    content::NavigationHandle* handle) {
+    content::NavigationHandle* handle,
+    navigation_interception::SynchronyMode mode) {
   return std::make_unique<InterceptNavigationThrottle>(
-      handle, base::Bind(&CheckIfShouldIgnoreNavigationOnUIThread));
+      handle, base::Bind(&CheckIfShouldIgnoreNavigationOnUIThread), mode);
 }
 
 InterceptNavigationDelegate::InterceptNavigationDelegate(
diff --git a/components/navigation_interception/intercept_navigation_delegate.h b/components/navigation_interception/intercept_navigation_delegate.h
index 1e7e860..1f5b229 100644
--- a/components/navigation_interception/intercept_navigation_delegate.h
+++ b/components/navigation_interception/intercept_navigation_delegate.h
@@ -10,6 +10,7 @@
 #include "base/android/jni_weak_ref.h"
 #include "base/macros.h"
 #include "base/supports_user_data.h"
+#include "components/navigation_interception/intercept_navigation_throttle.h"
 
 namespace content {
 class NavigationHandle;
@@ -49,7 +50,8 @@
   // Creates a InterceptNavigationThrottle that will direct all callbacks to
   // the InterceptNavigationDelegate.
   static std::unique_ptr<content::NavigationThrottle> CreateThrottleFor(
-      content::NavigationHandle* handle);
+      content::NavigationHandle* handle,
+      navigation_interception::SynchronyMode mode);
 
   virtual bool ShouldIgnoreNavigation(
       const NavigationParams& navigation_params);
diff --git a/components/navigation_interception/intercept_navigation_throttle.cc b/components/navigation_interception/intercept_navigation_throttle.cc
index 2010540..bcfea987 100644
--- a/components/navigation_interception/intercept_navigation_throttle.cc
+++ b/components/navigation_interception/intercept_navigation_throttle.cc
@@ -22,10 +22,12 @@
 
 InterceptNavigationThrottle::InterceptNavigationThrottle(
     content::NavigationHandle* navigation_handle,
-    CheckCallback should_ignore_callback)
+    CheckCallback should_ignore_callback,
+    SynchronyMode async_mode)
     : content::NavigationThrottle(navigation_handle),
       should_ignore_callback_(should_ignore_callback),
       ui_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+      mode_(async_mode),
       weak_factory_(this) {}
 
 InterceptNavigationThrottle::~InterceptNavigationThrottle() {
@@ -112,19 +114,16 @@
 
 bool InterceptNavigationThrottle::ShouldCheckAsynchronously() const {
   // Do not apply the async optimization for:
-  // - Non-Android platforms (where the check is always fast)
+  // - Throttles in non-async mode.
   // - POST navigations, to ensure we aren't violating idempotency.
   // - Subframe navigations, which aren't observed on Android, and should be
   //   fast on other platforms.
   // - non-http/s URLs, which are more likely to be intercepted.
-#if defined(OS_ANDROID)
-  return navigation_handle()->IsInMainFrame() &&
+  return mode_ == SynchronyMode::kAsync &&
+         navigation_handle()->IsInMainFrame() &&
          !navigation_handle()->IsPost() &&
          navigation_handle()->GetURL().SchemeIsHTTPOrHTTPS() &&
          base::FeatureList::IsEnabled(kAsyncCheck);
-#else
-  return false;
-#endif
 }
 
 NavigationParams InterceptNavigationThrottle::GetNavigationParams(
diff --git a/components/navigation_interception/intercept_navigation_throttle.h b/components/navigation_interception/intercept_navigation_throttle.h
index ba12086..a961826 100644
--- a/components/navigation_interception/intercept_navigation_throttle.h
+++ b/components/navigation_interception/intercept_navigation_throttle.h
@@ -23,6 +23,13 @@
 
 class NavigationParams;
 
+enum class SynchronyMode {
+  // Support async interception in some cases (See ShouldCheckAsynchronously).
+  kAsync,
+  // Only support synchronous interception.
+  kSync
+};
+
 // This class allows the provider of the Callback to selectively ignore top
 // level navigations. This is a UI thread class.
 class InterceptNavigationThrottle : public content::NavigationThrottle {
@@ -35,7 +42,8 @@
   static const base::Feature kAsyncCheck;
 
   InterceptNavigationThrottle(content::NavigationHandle* navigation_handle,
-                              CheckCallback should_ignore_callback);
+                              CheckCallback should_ignore_callback,
+                              SynchronyMode async_mode);
   ~InterceptNavigationThrottle() override;
 
   // content::NavigationThrottle implementation:
@@ -61,6 +69,8 @@
   // Note that the CheckCallback currently has thread affinity on the Java side.
   scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
 
+  const SynchronyMode mode_ = SynchronyMode::kSync;
+
   // The remaining members are only set for asynchronous checking.
   //
   // How many outbound pending checks are running. Normally this will be either
diff --git a/components/navigation_interception/intercept_navigation_throttle_unittest.cc b/components/navigation_interception/intercept_navigation_throttle_unittest.cc
index a819416..2f239b17 100644
--- a/components/navigation_interception/intercept_navigation_throttle_unittest.cc
+++ b/components/navigation_interception/intercept_navigation_throttle_unittest.cc
@@ -75,7 +75,8 @@
   static std::unique_ptr<content::NavigationThrottle> CreateThrottle(
       InterceptNavigationThrottle::CheckCallback callback,
       content::NavigationHandle* handle) {
-    return std::make_unique<InterceptNavigationThrottle>(handle, callback);
+    return std::make_unique<InterceptNavigationThrottle>(
+        handle, callback, navigation_interception::SynchronyMode::kAsync);
   }
 
   std::unique_ptr<content::TestNavigationThrottleInserter>
diff --git a/components/page_info_strings.grdp b/components/page_info_strings.grdp
index 583cd115..d073787 100644
--- a/components/page_info_strings.grdp
+++ b/components/page_info_strings.grdp
@@ -319,18 +319,21 @@
     </message>
 
     <!-- UI for device access granted to the site using the device chooser (e.g. USB, Bluetooth) -->
-    <message name="IDS_PAGE_INFO_USB_DEVICE_LABEL" desc="The label used to describe a USB device that the user has granted the site permission to access.">
-      <ph name="DEVICE_NAME">$1<ex>Android Phone</ex></ph>
-    </message>
-    <message name="IDS_PAGE_INFO_USB_DEVICE_SECONDARY_LABEL" desc="The label displayed underneath IDS_PAGE_INFO_USB_DEVICE_LABEL to inform the user that the device name listed is a USB device.">
+    <message name="IDS_PAGE_INFO_USB_DEVICE_SECONDARY_LABEL" desc="The label displayed underneath the device name to inform the user that the item refers to a USB device.">
       USB device
     </message>
-    <message name="IDS_PAGE_INFO_USB_DEVICE_ALLOWED_BY_POLICY_LABEL" desc="The label displayed underneath IDS_PAGE_INFO_USB_DEVICE_LABEL to inform the user that the device name listed is a USB device explicitly allowed by the user's enterprise policy.">
+    <message name="IDS_PAGE_INFO_USB_DEVICE_ALLOWED_BY_POLICY_LABEL" desc="The label displayed underneath the device name to inform the user that the item listed is refering to a USB device explicitly allowed by the user's enterprise policy.">
       USB device allowed by your administrator
     </message>
     <message name="IDS_PAGE_INFO_DELETE_USB_DEVICE" desc="The tooltip displayed when hovering over the button that will remove permission to access a USB device that the user previously granted to the site.">
       Revoke access
     </message>
+    <message name="IDS_PAGE_INFO_SERIAL_PORT_SECONDARY_LABEL" desc="The label displayed underneath the port name to inform the user that the permission listed refers to a serial port.">
+      Serial port
+    </message>
+    <message name="IDS_PAGE_INFO_DELETE_SERIAL_PORT" desc="The tooltip displayed when hovering over the button that will remove permission to access a serial port that the user previously granted to the site.">
+      Revoke access
+    </message>
 
     <!-- Site settings link -->
     <message name="IDS_PAGE_INFO_SITE_SETTINGS_LINK" desc="This is the text of the link pointing to Chrome's Site Settings page. This appears at the bottom of the Permissions pane of the Page Information Window.">
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto
index 070a2a9..347009fc 100644
--- a/components/policy/proto/device_management_backend.proto
+++ b/components/policy/proto/device_management_backend.proto
@@ -54,7 +54,7 @@
   enum Type {
     reserved 5;
 
-    TT   = 0;             // Register for TT release.
+    TT = 0;               // Register for TT release.
     USER = 1;             // Register for Chrome OS user polices.
     DEVICE = 2;           // Register for Chrome OS device policies.
     BROWSER = 3;          // Register for desktop Chrome browser user policies.
@@ -133,7 +133,7 @@
     // is mandatory, but it failed and we are doing a fallback to manual
     // enrollment.
     FLAVOR_ENROLLMENT_ATTESTATION_INITIAL_MANUAL_FALLBACK = 15;
-  };
+  }
 
   // Indicates the registration flavor. This is passed to the server FYI when
   // registering for policy so the server can distinguish registration triggers.
@@ -208,12 +208,10 @@
 
 // Request from device to server to unregister device.
 // GoogleDMToken MUST be in HTTP Authorization header.
-message DeviceUnregisterRequest {
-}
+message DeviceUnregisterRequest {}
 
 // Response from server to device for unregister request.
-message DeviceUnregisterResponse {
-}
+message DeviceUnregisterResponse {}
 
 // Request from device to server to upload a device certificate or an enrollment
 // identifier.
@@ -237,8 +235,7 @@
 }
 
 // Response from server to device for cert upload request.
-message DeviceCertUploadResponse {
-}
+message DeviceCertUploadResponse {}
 
 // Request to access a Google service with the given scope.
 message DeviceServiceApiAccessRequest {
@@ -260,7 +257,7 @@
     // to access Google Docs.
     // Please see go/cros-demo-mode and go/demo-mode-account-brainstorm.
     CHROME_OS_DEMO_MODE = 2;
-  };
+  }
 
   // Device type indicates the intended use of the auth code.
   optional DeviceType device_type = 3;
@@ -1281,7 +1278,7 @@
     // Forced Enrollment check with SHA-256 hashes of (brand code + “_” + serial
     // number), truncated to first 8 bytes each.
     ENROLLMENT_CHECK_TYPE_FORCED_ENROLLMENT = 2;
-  };
+  }
 
   // Specifies the type of auto enrollment check that is being made.
   // This also defines the format of the device identifier hash used in this
@@ -1353,7 +1350,7 @@
     RESTORE_MODE_DISABLED = 3;
     // Enterprise enrollment is enforced using Zero-Touch and cannot be skipped.
     RESTORE_MODE_REENROLLMENT_ZERO_TOUCH = 4;
-  };
+  }
   // The server-indicated restore mode.
   optional RestoreMode restore_mode = 1 [default = RESTORE_MODE_NONE];
 
@@ -1389,7 +1386,7 @@
     // Zero-Touch (attestation-based) enrollment is enforced and cannot be
     // skipped.
     INITIAL_ENROLLMENT_MODE_ZERO_TOUCH_ENFORCED = 2;
-  };
+  }
   // The server-indicated initial enrollment mode.
   optional InitialEnrollmentMode initial_enrollment_mode = 1
       [default = INITIAL_ENROLLMENT_MODE_NONE];
@@ -1402,7 +1399,6 @@
 // device. The HTTP request contains an end-user OAuth token and only succeeds
 // if both Host and Controller devices belong to the end-user domain.
 message DevicePairingRequest {
-
   // The device ID of the Host device.
   optional string host_device_id = 1;
 
@@ -1412,7 +1408,6 @@
 
 // Response from the server to the device pairing request.
 message DevicePairingResponse {
-
   // The client should check HTTP status code first. If HTTP status code is not
   // 200 (e.g. 500 internal error), then it means the pairing fails. If HTTP
   // status code is 200, then the client should check the status code within the
@@ -1427,7 +1422,7 @@
     HOST_DEVICE_NOT_FOUND = 2;
 
     // The Controller device cannot be found in the user's domain.
-    CONTROLLER_DEVICE_NOT_FOUND  = 3;
+    CONTROLLER_DEVICE_NOT_FOUND = 3;
 
     // The Host device is deprovisioned.
     HOST_DEVICE_DEPROVISIONED = 4;
@@ -1443,7 +1438,6 @@
 // request contains controller service account OAuth token as well as the
 // DMToken from the Host device.
 message CheckDevicePairingRequest {
-
   // The device ID of the Host device.
   optional string host_device_id = 1;
 
@@ -1453,7 +1447,6 @@
 
 // Response from the server to the check device pairing request.
 message CheckDevicePairingResponse {
-
   // The client should check HTTP status code first. If HTTP status code is not
   // 200 (e.g. 500 internal error), then it means the pairing status is unknown.
   // If HTTP status code is 200, then the client should check the status code
@@ -1468,7 +1461,7 @@
     HOST_DEVICE_NOT_FOUND = 2;
 
     // The Controller device cannot be found in the Host device domain.
-    CONTROLLER_DEVICE_NOT_FOUND  = 3;
+    CONTROLLER_DEVICE_NOT_FOUND = 3;
 
     // The Host device is deprovisioned.
     HOST_DEVICE_DEPROVISIONED = 4;
@@ -1514,6 +1507,9 @@
 
     // Wipe the device (perform a powerwash).
     DEVICE_REMOTE_POWERWASH = 7;
+
+    // Refresh the device machine certificate and re-upload it.
+    DEVICE_REFRESH_ENTERPRISE_MACHINE_CERTIFICATE = 8;
   }
 
   // The command type.
@@ -1581,8 +1577,7 @@
 // Sent by the client to the server to check if the current user is allowed
 // to update attributes (asset id and location).  The HTTP request contains an
 // end-user OAuth token.
-message DeviceAttributeUpdatePermissionRequest {
-}
+message DeviceAttributeUpdatePermissionRequest {}
 
 // Response from the server specifying whether the current user is allowed to
 // update attributes (asset id and location).
@@ -1664,6 +1659,8 @@
   optional bytes device_certificate = 2;
   // regular device registration request
   optional DeviceRegisterRequest device_register_request = 3;
+  // The device owner's email address.
+  optional string device_owner = 4;
 }
 
 // Request to enroll a Chrome browser. Fields match identically named fields
@@ -2194,8 +2191,8 @@
   optional GcmIdUpdateResponse gcm_id_update_response = 17;
 
   // Response to check Android management request.
-  optional CheckAndroidManagementResponse
-      check_android_management_response = 18;
+  optional CheckAndroidManagementResponse check_android_management_response =
+      18;
 
   // Response to an Active Directory Play user enrollment request.
   optional ActiveDirectoryEnrollPlayUserResponse
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 9ebe035..68018df 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -11963,6 +11963,44 @@
       This policy does not apply to kiosk users. If this policy is left not set, the device will behave as if 'DisallowArc' was chosen.''',
     },
     {
+      'name': 'SchedulerConfiguration',
+      'type': 'string-enum',
+      'schema': {
+        'type': 'string',
+        'enum': [
+          'conservative',
+          'performance',
+        ],
+      },
+      'items': [
+        {
+          'name': 'Conservative',
+          'value': 'conservative',
+          'caption': '''Optimize for stability.''',
+        },
+        {
+          'name': 'Performance',
+          'value': 'performance',
+          'caption': '''Optimize for performance.''',
+        },
+      ],
+      'supported_on': ['chrome_os:74-'],
+      'features': {
+        'can_be_recommended': True,
+        'dynamic_refresh': True,
+        'per_profile': False,
+      },
+      'example_value': 'performance',
+      'id': 522,
+      'caption': '''Select task scheduler configuration''',
+      'tags': [],
+      'desc': '''Instructs <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> to use the task scheduler configuration identified by the specified name.
+
+      This policy can be set to "conservative" and "performance", which select task scheduler configurations that are tuned for stability vs. maximum performance, respectively.
+
+      If the policy is left unset, the user can make their own choice.''',
+    },
+    {
       'name': 'NoteTakingAppsLockScreenWhitelist',
       'type': 'list',
       'schema': {
@@ -14769,5 +14807,5 @@
   },
   'placeholders': [],
   'deleted_policy_ids': [412],
-  'highest_id_currently_used':  521
+  'highest_id_currently_used':  522
 }
diff --git a/components/safe_browsing/browser/base_parallel_resource_throttle_unittest.cc b/components/safe_browsing/browser/base_parallel_resource_throttle_unittest.cc
index df742bc..1cbb84f6 100644
--- a/components/safe_browsing/browser/base_parallel_resource_throttle_unittest.cc
+++ b/components/safe_browsing/browser/base_parallel_resource_throttle_unittest.cc
@@ -178,7 +178,8 @@
                                               TRAFFIC_ANNOTATION_FOR_TESTS);
     content::ResourceRequestInfo::AllocateForTesting(
         request_.get(), content::RESOURCE_TYPE_MAIN_FRAME, nullptr, -1, -1, -1,
-        true, true, true, content::PREVIEWS_OFF, nullptr);
+        true, content::ResourceInterceptPolicy::kAllowAll, true,
+        content::PREVIEWS_OFF, nullptr);
 
     database_manager_ = new TestDatabaseManager();
     url_checker_delegate_ = new TestUrlCheckerDelegate(database_manager_);
diff --git a/components/signin/core/browser/account_investigator.cc b/components/signin/core/browser/account_investigator.cc
index f30d933..8b4cf23b 100644
--- a/components/signin/core/browser/account_investigator.cc
+++ b/components/signin/core/browser/account_investigator.cc
@@ -32,7 +32,7 @@
 const char kSignedInHashPrefix[] = "i";
 const char kSignedOutHashPrefix[] = "o";
 
-bool AreSame(const AccountInfo& info, const ListedAccount& account) {
+bool AreSame(const CoreAccountInfo& info, const ListedAccount& account) {
   return info.account_id == account.id;
 }
 
@@ -164,7 +164,7 @@
 
 // static
 AccountRelation AccountInvestigator::DiscernRelation(
-    const AccountInfo& info,
+    const CoreAccountInfo& info,
     const std::vector<ListedAccount>& signed_in_accounts,
     const std::vector<ListedAccount>& signed_out_accounts) {
   if (signed_in_accounts.empty() && signed_out_accounts.empty()) {
diff --git a/components/signin/core/browser/account_investigator.h b/components/signin/core/browser/account_investigator.h
index ce7eabdb..f4ec146 100644
--- a/components/signin/core/browser/account_investigator.h
+++ b/components/signin/core/browser/account_investigator.h
@@ -13,7 +13,7 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "services/identity/public/cpp/identity_manager.h"
 
-struct AccountInfo;
+struct CoreAccountInfo;
 class PrefRegistrySimple;
 class PrefService;
 
@@ -81,7 +81,7 @@
   // potentially signed into Chrome account, to the various account(s) in the
   // given cookie jar.
   static signin_metrics::AccountRelation DiscernRelation(
-      const AccountInfo& info,
+      const CoreAccountInfo& info,
       const std::vector<gaia::ListedAccount>& signed_in_accounts,
       const std::vector<gaia::ListedAccount>& signed_out_accounts);
 
diff --git a/components/signin/core/browser/test_signin_client.cc b/components/signin/core/browser/test_signin_client.cc
index 8b3f7ee..df3c8c6b 100644
--- a/components/signin/core/browser/test_signin_client.cc
+++ b/components/signin/core/browser/test_signin_client.cc
@@ -13,10 +13,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 TestSigninClient::TestSigninClient(PrefService* pref_service)
-    : shared_factory_(
-          base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-              &test_url_loader_factory_)),
-      pref_service_(pref_service),
+    : pref_service_(pref_service),
       are_signin_cookies_allowed_(true),
       network_calls_delayed_(false),
       is_signout_allowed_(true) {}
@@ -39,7 +36,7 @@
 
 scoped_refptr<network::SharedURLLoaderFactory>
 TestSigninClient::GetURLLoaderFactory() {
-  return shared_factory_;
+  return test_url_loader_factory_.GetSafeWeakWrapper();
 }
 
 network::mojom::CookieManager* TestSigninClient::GetCookieManager() {
diff --git a/components/signin/core/browser/test_signin_client.h b/components/signin/core/browser/test_signin_client.h
index 98cbaf0..423c240 100644
--- a/components/signin/core/browser/test_signin_client.h
+++ b/components/signin/core/browser/test_signin_client.h
@@ -91,7 +91,6 @@
 
  private:
   network::TestURLLoaderFactory test_url_loader_factory_;
-  scoped_refptr<network::SharedURLLoaderFactory> shared_factory_;
 
   PrefService* pref_service_;
   std::unique_ptr<network::mojom::CookieManager> cookie_manager_;
diff --git a/components/ui_devtools/OWNERS b/components/ui_devtools/OWNERS
index 6507f289a..95d3eec 100644
--- a/components/ui_devtools/OWNERS
+++ b/components/ui_devtools/OWNERS
@@ -1,5 +1,6 @@
 sadrul@chromium.org
 dgozman@chromium.org
 lgrey@chromium.org
+pfeldman@chromium.org
 
 # COMPONENT: Platform>DevTools
diff --git a/components/ui_devtools/devtools_client.cc b/components/ui_devtools/devtools_client.cc
index 1356bc3..865f209b1 100644
--- a/components/ui_devtools/devtools_client.cc
+++ b/components/ui_devtools/devtools_client.cc
@@ -33,7 +33,7 @@
   int call_id;
   std::string method;
   std::unique_ptr<protocol::Value> protocolCommand =
-      protocol::StringUtil::parseJSON(data);
+      protocol::StringUtil::parseMessage(data, false);
   if (dispatcher_.parseCommand(protocolCommand.get(), &call_id, &method)) {
     dispatcher_.dispatch(call_id, method, std::move(protocolCommand), data);
   }
@@ -60,13 +60,13 @@
     int callId,
     std::unique_ptr<protocol::Serializable> message) {
   if (connected())
-    server_->SendOverWebSocket(connection_id_, message->serialize());
+    server_->SendOverWebSocket(connection_id_, message->serialize(false));
 }
 
 void UiDevToolsClient::sendProtocolNotification(
     std::unique_ptr<protocol::Serializable> message) {
   if (connected())
-    server_->SendOverWebSocket(connection_id_, message->serialize());
+    server_->SendOverWebSocket(connection_id_, message->serialize(false));
 }
 
 void UiDevToolsClient::flushProtocolNotifications() {
diff --git a/components/ui_devtools/ui_devtools_unittest_utils.cc b/components/ui_devtools/ui_devtools_unittest_utils.cc
index 462cc9f2..a2303d5e 100644
--- a/components/ui_devtools/ui_devtools_unittest_utils.cc
+++ b/components/ui_devtools/ui_devtools_unittest_utils.cc
@@ -32,7 +32,7 @@
 void FakeFrontendChannel::sendProtocolNotification(
     std::unique_ptr<protocol::Serializable> message) {
   EXPECT_TRUE(allow_notifications_);
-  protocol_notification_messages_.push_back(message->serialize());
+  protocol_notification_messages_.push_back(message->serialize(false));
 }
 
 }  // namespace ui_devtools
diff --git a/components/vector_icons/BUILD.gn b/components/vector_icons/BUILD.gn
index f6c6984..474e9b5 100644
--- a/components/vector_icons/BUILD.gn
+++ b/components/vector_icons/BUILD.gn
@@ -47,6 +47,7 @@
     "replay.icon",
     "screen_share.icon",
     "search.icon",
+    "serial_port.icon",
     "usb.icon",
     "videocam.icon",
     "warning.icon",
diff --git a/components/vector_icons/serial_port.icon b/components/vector_icons/serial_port.icon
new file mode 100644
index 0000000..84d6f1e
--- /dev/null
+++ b/components/vector_icons/serial_port.icon
@@ -0,0 +1,25 @@
+// 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.
+
+CANVAS_DIMENSIONS, 18,
+STROKE, 0.53f,
+MOVE_TO, 2.01f, 5.55f,
+H_LINE_TO, 16,
+R_CUBIC_TO, 0.44f, 0, 0.81f, 0.58f, 0.7f, 1,
+R_LINE_TO, -1.5f, 5.1f,
+R_CUBIC_TO, -0.12f, 0.43f, -0.35f, 0.8f, -0.8f, 0.8f,
+H_LINE_TO, 3.6f,
+R_CUBIC_TO, -0.44f, 0, -0.67f, -0.37f, -0.8f, -0.8f,
+LINE_TO, 1.33f, 6.59f,
+R_CUBIC_TO, -0.13f, -0.42f, 0.25f, -1.03f, 0.7f, -1.03f,
+CLOSE,
+CIRCLE, 3.63, 7.53, 0.8,
+CIRCLE, 4.66, 10.49, 0.8,
+CIRCLE, 14.49, 7.53, 0.8,
+CIRCLE, 11.78, 7.53, 0.8,
+CIRCLE, 9.06, 7.53, 0.8,
+CIRCLE, 6.34, 7.53, 0.8,
+CIRCLE, 7.5, 10.49, 0.8,
+CIRCLE, 10.34, 10.49, 0.8,
+CIRCLE, 13.18, 10.49, 0.8
diff --git a/content/browser/android/url_request_content_job_unittest.cc b/content/browser/android/url_request_content_job_unittest.cc
index f15fb087..3e6eb17 100644
--- a/content/browser/android/url_request_content_job_unittest.cc
+++ b/content/browser/android/url_request_content_job_unittest.cc
@@ -153,12 +153,12 @@
 
   ResourceRequestInfo::AllocateForTesting(request.get(),
                                           RESOURCE_TYPE_MAIN_FRAME,
-                                          nullptr,       // context
-                                          0,             // render_process_id
-                                          0,             // render_view_id
-                                          0,             // render_frame_id
-                                          true,          // is_main_frame
-                                          false,         // allow_download
+                                          nullptr,  // context
+                                          0,        // render_process_id
+                                          0,        // render_view_id
+                                          0,        // render_frame_id
+                                          true,     // is_main_frame
+                                          ResourceInterceptPolicy::kAllowNone,
                                           true,          // is_async
                                           PREVIEWS_OFF,  // previews_state
                                           nullptr);      // navigation_ui_data
diff --git a/content/browser/browsing_data/clear_site_data_throttle_unittest.cc b/content/browser/browsing_data/clear_site_data_throttle_unittest.cc
index 7d73587..e54b190 100644
--- a/content/browser/browsing_data/clear_site_data_throttle_unittest.cc
+++ b/content/browser/browsing_data/clear_site_data_throttle_unittest.cc
@@ -164,9 +164,9 @@
       ClearSiteDataThrottle::MaybeCreateThrottleForRequest(request.get()));
 
   // We can create the throttle for a valid ResourceRequestInfo.
-  ResourceRequestInfo::AllocateForTesting(request.get(), RESOURCE_TYPE_IMAGE,
-                                          nullptr, 0, 0, 0, false, true, true,
-                                          false, nullptr);
+  ResourceRequestInfo::AllocateForTesting(
+      request.get(), RESOURCE_TYPE_IMAGE, nullptr, 0, 0, 0, false,
+      ResourceInterceptPolicy::kAllowAll, true, false, nullptr);
   EXPECT_TRUE(
       ClearSiteDataThrottle::MaybeCreateThrottleForRequest(request.get()));
 }
@@ -610,7 +610,7 @@
     ResourceRequestInfo::AllocateForTesting(
         request.get(),
         navigation ? RESOURCE_TYPE_SUB_FRAME : RESOURCE_TYPE_IMAGE, nullptr, 0,
-        0, 0, false, true, true, false, nullptr);
+        0, 0, false, ResourceInterceptPolicy::kAllowAll, true, false, nullptr);
 
     std::string output_buffer;
     std::unique_ptr<RedirectableTestThrottle> throttle =
diff --git a/content/browser/devtools/devtools_pipe_handler.cc b/content/browser/devtools/devtools_pipe_handler.cc
index adb9950..dd9ea0b 100644
--- a/content/browser/devtools/devtools_pipe_handler.cc
+++ b/content/browser/devtools/devtools_pipe_handler.cc
@@ -375,4 +375,8 @@
 
 void DevToolsPipeHandler::AgentHostClosed(DevToolsAgentHost* agent_host) {}
 
+bool DevToolsPipeHandler::UsesBinaryProtocol() {
+  return mode_ == ProtocolMode::kCBOR;
+}
+
 }  // namespace content
diff --git a/content/browser/devtools/devtools_pipe_handler.h b/content/browser/devtools/devtools_pipe_handler.h
index f09fa58..61738bc 100644
--- a/content/browser/devtools/devtools_pipe_handler.h
+++ b/content/browser/devtools/devtools_pipe_handler.h
@@ -29,6 +29,7 @@
   void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
                                const std::string& message) override;
   void AgentHostClosed(DevToolsAgentHost* agent_host) override;
+  bool UsesBinaryProtocol() override;
 
   void Shutdown();
 
diff --git a/content/browser/devtools/devtools_session.cc b/content/browser/devtools/devtools_session.cc
index 848922c..dd41a5d 100644
--- a/content/browser/devtools/devtools_session.cc
+++ b/content/browser/devtools/devtools_session.cc
@@ -135,7 +135,8 @@
 
 bool DevToolsSession::DispatchProtocolMessage(const std::string& message) {
   std::unique_ptr<protocol::DictionaryValue> value =
-      protocol::DictionaryValue::cast(protocol::StringUtil::parseJSON(message));
+      protocol::DictionaryValue::cast(protocol::StringUtil::parseMessage(
+          message, client_->UsesBinaryProtocol()));
 
   std::string session_id;
   if (!value || !value->getString(kSessionId, &session_id))
@@ -242,13 +243,15 @@
 void DevToolsSession::sendProtocolResponse(
     int call_id,
     std::unique_ptr<protocol::Serializable> message) {
-  client_->DispatchProtocolMessage(agent_host_, message->serialize());
+  bool binary = client_->UsesBinaryProtocol();
+  client_->DispatchProtocolMessage(agent_host_, message->serialize(binary));
   // |this| may be deleted at this point.
 }
 
 void DevToolsSession::sendProtocolNotification(
     std::unique_ptr<protocol::Serializable> message) {
-  client_->DispatchProtocolMessage(agent_host_, message->serialize());
+  bool binary = client_->UsesBinaryProtocol();
+  client_->DispatchProtocolMessage(agent_host_, message->serialize(binary));
   // |this| may be deleted at this point.
 }
 
diff --git a/content/browser/devtools/devtools_url_interceptor_request_job.cc b/content/browser/devtools/devtools_url_interceptor_request_job.cc
index bbe2926..2b477b2 100644
--- a/content/browser/devtools/devtools_url_interceptor_request_job.cc
+++ b/content/browser/devtools/devtools_url_interceptor_request_job.cc
@@ -151,7 +151,7 @@
       resource_request_info->GetResourceType(),
       resource_request_info->GetPageTransition(),
       resource_request_info->IsDownload(), resource_request_info->is_stream(),
-      resource_request_info->allow_download(),
+      resource_request_info->resource_intercept_policy(),
       resource_request_info->HasUserGesture(),
       resource_request_info->is_load_timing_enabled(),
       resource_request_info->is_upload_progress_enabled(),
@@ -528,7 +528,8 @@
   // should not have this problem, as it's on top of MIME sniffer.
   std::string mime_type;
   subrequest->GetMimeType(&mime_type);
-  return req_info->allow_download() &&
+  return req_info->resource_intercept_policy() ==
+             ResourceInterceptPolicy::kAllowAll &&
          download_utils::IsDownload(orig_request->url(),
                                     subrequest->response_headers(), mime_type);
 }
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc
index ea20d27..b62b5892 100644
--- a/content/browser/devtools/protocol/target_handler.cc
+++ b/content/browser/devtools/protocol/target_handler.cc
@@ -315,9 +315,10 @@
 
   void SendMessageToAgentHost(const std::string& message) {
     if (throttle_) {
+      auto* client = handler_->root_session_->client();
       std::unique_ptr<protocol::DictionaryValue> value =
-          protocol::DictionaryValue::cast(
-              protocol::StringUtil::parseJSON(message));
+          protocol::DictionaryValue::cast(protocol::StringUtil::parseMessage(
+              message, client->UsesBinaryProtocol()));
       std::string method;
       if (value->getString(kMethod, &method) && method == kResumeMethod)
         ResumeIfThrottled();
diff --git a/content/browser/devtools/protocol/tracing_handler.cc b/content/browser/devtools/protocol/tracing_handler.cc
index fd1dcd8..6609d738 100644
--- a/content/browser/devtools/protocol/tracing_handler.cc
+++ b/content/browser/devtools/protocol/tracing_handler.cc
@@ -276,7 +276,7 @@
   message.append(valid_trace_fragment.c_str() +
                  trace_data_buffer_state_.offset);
   message += "] } }";
-  frontend_->sendRawNotification(message);
+  frontend_->sendRawNotification(std::move(message));
 }
 
 void TracingHandler::OnTraceComplete() {
diff --git a/content/browser/frame_host/navigation_controller_android.cc b/content/browser/frame_host/navigation_controller_android.cc
index e4b7eed..03e8693 100644
--- a/content/browser/frame_host/navigation_controller_android.cc
+++ b/content/browser/frame_host/navigation_controller_android.cc
@@ -407,4 +407,11 @@
   navigation_controller_->GetEntryAtIndex(index)->SetExtraData(key, value);
 }
 
+jboolean NavigationControllerAndroid::IsEntryMarkedToBeSkipped(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj,
+    jint index) {
+  return navigation_controller_->IsEntryMarkedToBeSkipped(index);
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/navigation_controller_android.h b/content/browser/frame_host/navigation_controller_android.h
index b9478af..034b761 100644
--- a/content/browser/frame_host/navigation_controller_android.h
+++ b/content/browser/frame_host/navigation_controller_android.h
@@ -126,6 +126,10 @@
                          jint index,
                          const base::android::JavaParamRef<jstring>& jkey,
                          const base::android::JavaParamRef<jstring>& jvalue);
+  jboolean IsEntryMarkedToBeSkipped(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      jint index);
 
  private:
   NavigationControllerImpl* navigation_controller_;
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index 03ee4a6..babf7de 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -1917,7 +1917,7 @@
   // adding the entries from source won't put us over the limit.
   DCHECK_EQ(1, GetEntryCount());
   if (!replace_entry)
-    source->PruneOldestEntryIfFull();
+    source->PruneOldestSkippableEntryIfFull();
 
   // Insert the entries from source. Don't use source->GetCurrentEntryIndex as
   // we don't want to copy over the transient entry. Ignore any pending entry,
@@ -2416,22 +2416,40 @@
     }
   }
 
-  PruneOldestEntryIfFull();
+  PruneOldestSkippableEntryIfFull();
 
   entries_.push_back(std::move(entry));
   last_committed_entry_index_ = static_cast<int>(entries_.size()) - 1;
 }
 
-void NavigationControllerImpl::PruneOldestEntryIfFull() {
+void NavigationControllerImpl::PruneOldestSkippableEntryIfFull() {
   if (entries_.size() < max_entry_count())
     return;
 
   DCHECK_EQ(max_entry_count(), entries_.size());
   DCHECK_GT(last_committed_entry_index_, 0);
-  RemoveEntryAtIndex(0);
-  NotifyPrunedEntries(this, 0 /* start index */, 1 /* count */);
-  // TODO(crbug.com/907167): Consider removing the earliest skippable entry
-  // instead of the first entry.
+  CHECK_EQ(pending_entry_index_, -1);
+
+  int index = 0;
+  if (base::FeatureList::IsEnabled(
+          features::kHistoryManipulationIntervention)) {
+    // Retrieve the oldest skippable entry.
+    for (; index < GetEntryCount(); index++) {
+      if (GetEntryAtIndex(index)->should_skip_on_back_forward_ui())
+        break;
+    }
+  }
+
+  // If there is no skippable entry or if it is the last committed entry then
+  // fall back to pruning the oldest entry. It is not safe to prune the last
+  // committed entry.
+  if (index == GetEntryCount() || index == last_committed_entry_index_)
+    index = 0;
+
+  bool should_succeed = RemoveEntryAtIndex(index);
+  DCHECK_EQ(true, should_succeed);
+
+  NotifyPrunedEntries(this, index, 1);
 }
 
 void NavigationControllerImpl::NavigateToExistingPendingEntry(
diff --git a/content/browser/frame_host/navigation_controller_impl.h b/content/browser/frame_host/navigation_controller_impl.h
index 0268716a..d891162c3 100644
--- a/content/browser/frame_host/navigation_controller_impl.h
+++ b/content/browser/frame_host/navigation_controller_impl.h
@@ -414,9 +414,10 @@
   // Discards only the transient entry.
   void DiscardTransientEntry();
 
-  // If we have the maximum number of entries, remove the oldest one in
-  // preparation to add another.
-  void PruneOldestEntryIfFull();
+  // If we have the maximum number of entries, remove the oldest entry that is
+  // marked to be skipped on back/forward button, in preparation to add another.
+  // If no entry is skippable, then the oldest entry will be pruned.
+  void PruneOldestSkippableEntryIfFull();
 
   // Removes all entries except the last committed entry.  If there is a new
   // pending navigation it is preserved. In contrast to
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 465d40d..ffbd16c 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -8414,8 +8414,8 @@
 
   NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
       shell()->web_contents()->GetController());
-  EXPECT_EQ(controller.GetCurrentEntryIndex(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 2);
+  EXPECT_EQ(2, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
 
   // Last entry should have been marked as skippable.
   EXPECT_TRUE(controller.GetEntryAtIndex(1)->should_skip_on_back_forward_ui());
@@ -8470,8 +8470,8 @@
 
   NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
       shell()->web_contents()->GetController());
-  EXPECT_EQ(controller.GetCurrentEntryIndex(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 2);
+  EXPECT_EQ(2, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
 
   // Last entry should have been marked as skippable.
   EXPECT_TRUE(controller.GetEntryAtIndex(1)->should_skip_on_back_forward_ui());
@@ -8523,8 +8523,8 @@
 
   NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
       shell()->web_contents()->GetController());
-  EXPECT_EQ(controller.GetCurrentEntryIndex(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 2);
+  EXPECT_EQ(2, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
 
   // Last entry should have been marked as skippable.
   EXPECT_TRUE(controller.GetEntryAtIndex(1)->should_skip_on_back_forward_ui());
@@ -8581,8 +8581,8 @@
 
   NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
       shell()->web_contents()->GetController());
-  EXPECT_EQ(controller.GetCurrentEntryIndex(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 2);
+  EXPECT_EQ(2, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
 
   // Last 2 entries should have been marked as skippable.
   EXPECT_TRUE(controller.GetEntryAtIndex(0)->should_skip_on_back_forward_ui());
@@ -8638,8 +8638,8 @@
 
   NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
       shell()->web_contents()->GetController());
-  EXPECT_EQ(controller.GetCurrentEntryIndex(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 2);
+  EXPECT_EQ(2, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
 
   // Last 2 entries should have been marked as skippable.
   EXPECT_TRUE(controller.GetEntryAtIndex(0)->should_skip_on_back_forward_ui());
@@ -8687,8 +8687,8 @@
 
   NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
       shell()->web_contents()->GetController());
-  EXPECT_EQ(controller.GetCurrentEntryIndex(), 1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
+  EXPECT_EQ(1, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
 
   // Last entry should have been marked as skippable.
   EXPECT_TRUE(controller.GetEntryAtIndex(0)->should_skip_on_back_forward_ui());
@@ -8742,8 +8742,8 @@
 
   NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
       shell()->web_contents()->GetController());
-  EXPECT_EQ(controller.GetCurrentEntryIndex(), 1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
+  EXPECT_EQ(1, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
 
   // Last entry should not have been marked as skippable.
   EXPECT_FALSE(controller.GetEntryAtIndex(0)->should_skip_on_back_forward_ui());
@@ -8789,8 +8789,8 @@
 
   NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
       shell()->web_contents()->GetController());
-  EXPECT_EQ(controller.GetCurrentEntryIndex(), 1);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 1);
+  EXPECT_EQ(1, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
 
   // Last entry should not have been marked as skippable.
   EXPECT_FALSE(controller.GetEntryAtIndex(0)->should_skip_on_back_forward_ui());
@@ -8835,8 +8835,8 @@
 
   NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
       shell()->web_contents()->GetController());
-  EXPECT_EQ(controller.GetCurrentEntryIndex(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 2);
+  EXPECT_EQ(2, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
 
   // Last entry should have been marked as skippable.
   EXPECT_TRUE(controller.GetEntryAtIndex(1)->should_skip_on_back_forward_ui());
@@ -8885,8 +8885,8 @@
 
   NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
       shell()->web_contents()->GetController());
-  EXPECT_EQ(controller.GetCurrentEntryIndex(), 2);
-  EXPECT_EQ(controller.GetLastCommittedEntryIndex(), 2);
+  EXPECT_EQ(2, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
 
   // Last entry should have been marked as skippable.
   EXPECT_TRUE(controller.GetEntryAtIndex(1)->should_skip_on_back_forward_ui());
@@ -8911,6 +8911,110 @@
   EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
 }
 
+// Tests that the oldest navigation entry that is marked as skippable is the one
+// that is pruned if max entry count is reached.
+IN_PROC_BROWSER_TEST_F(NavigationControllerHistoryInterventionBrowserTest,
+                       PruneOldestSkippableEntry) {
+  base::HistogramTester histograms;
+
+  // Set the max entry count as 3.
+  NavigationControllerImpl::set_max_entry_count_for_testing(3);
+
+  GURL non_skippable_url(
+      embedded_test_server()->GetURL("/frame_tree/top.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), non_skippable_url));
+
+  GURL skippable_url(embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), skippable_url));
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+
+  EXPECT_FALSE(root->HasBeenActivated());
+  EXPECT_FALSE(root->HasTransientUserActivation());
+
+  // Navigate to a new same-site document from the renderer without a user
+  // gesture.
+  GURL redirected_url(embedded_test_server()->GetURL("/title2.html"));
+  EXPECT_TRUE(
+      NavigateToURLFromRendererWithoutUserGesture(shell(), redirected_url));
+
+  NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
+      shell()->web_contents()->GetController());
+  EXPECT_EQ(2, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(3, controller.GetEntryCount());
+  EXPECT_EQ(non_skippable_url, controller.GetEntryAtIndex(0)->GetURL());
+  EXPECT_EQ(skippable_url, controller.GetEntryAtIndex(1)->GetURL());
+  EXPECT_EQ(redirected_url, controller.GetEntryAtIndex(2)->GetURL());
+
+  // |skippable_url| entry should have been marked as skippable.
+  EXPECT_TRUE(controller.GetEntryAtIndex(1)->should_skip_on_back_forward_ui());
+  EXPECT_FALSE(
+      controller.GetLastCommittedEntry()->should_skip_on_back_forward_ui());
+  histograms.ExpectBucketCount(
+      "Navigation.BackForward.SetShouldSkipOnBackForwardUI", true, 1);
+
+  // A new navigation should lead to |skippable_url| to be pruned.
+  GURL new_navigation_url(embedded_test_server()->GetURL("/title3.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), new_navigation_url));
+  // Should still have 3 entries.
+  EXPECT_EQ(3, controller.GetEntryCount());
+  EXPECT_EQ(non_skippable_url, controller.GetEntryAtIndex(0)->GetURL());
+  EXPECT_EQ(redirected_url, controller.GetEntryAtIndex(1)->GetURL());
+  EXPECT_EQ(new_navigation_url, controller.GetEntryAtIndex(2)->GetURL());
+}
+
+// Tests that we fallback to pruning the oldest entry if the last committed
+// entry is the oldest skippable navigation entry.
+IN_PROC_BROWSER_TEST_F(NavigationControllerHistoryInterventionBrowserTest,
+                       PruneOldestWhenLastCommittedIsSkippable) {
+  base::HistogramTester histograms;
+
+  // Set the max entry count as 2.
+  NavigationControllerImpl::set_max_entry_count_for_testing(2);
+
+  GURL non_skippable_url(
+      embedded_test_server()->GetURL("/frame_tree/top.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), non_skippable_url));
+
+  GURL skippable_url(embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), skippable_url));
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+
+  EXPECT_FALSE(root->HasBeenActivated());
+  EXPECT_FALSE(root->HasTransientUserActivation());
+
+  // Navigate to a new same-site document from the renderer without a user
+  // gesture. This will mark |skippable_url| as skippable but since that is also
+  // the last committed entry, it will not be pruned. Instead the oldest entry
+  // will be removed.
+  GURL redirected_url(embedded_test_server()->GetURL("/title2.html"));
+  EXPECT_TRUE(
+      NavigateToURLFromRendererWithoutUserGesture(shell(), redirected_url));
+
+  NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>(
+      shell()->web_contents()->GetController());
+  EXPECT_EQ(1, controller.GetCurrentEntryIndex());
+  EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
+  EXPECT_EQ(2, controller.GetEntryCount());
+  EXPECT_EQ(skippable_url, controller.GetEntryAtIndex(0)->GetURL());
+  EXPECT_EQ(redirected_url, controller.GetEntryAtIndex(1)->GetURL());
+
+  // |skippable_url| entry should have been marked as skippable.
+  EXPECT_TRUE(controller.GetEntryAtIndex(0)->should_skip_on_back_forward_ui());
+  EXPECT_FALSE(
+      controller.GetLastCommittedEntry()->should_skip_on_back_forward_ui());
+  histograms.ExpectBucketCount(
+      "Navigation.BackForward.SetShouldSkipOnBackForwardUI", true, 1);
+}
+
 // Tests that a same document navigation followed by a client redirect
 // do not add any more session history entries and going to previous entry
 // works.
diff --git a/content/browser/indexed_db/indexed_db_browsertest.cc b/content/browser/indexed_db/indexed_db_browsertest.cc
index 4632cd08..519820c 100644
--- a/content/browser/indexed_db/indexed_db_browsertest.cc
+++ b/content/browser/indexed_db/indexed_db_browsertest.cc
@@ -62,7 +62,7 @@
 
 namespace {
 const Origin kFileOrigin = Origin::Create(GURL("file:///"));
-};
+}
 
 // This browser test is aimed towards exercising the IndexedDB bindings and
 // the actual implementation that lives in the browser side.
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc b/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
index a2e21656..627ee031 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
@@ -109,7 +109,7 @@
         upgrade_txn_id(upgrade_txn_id),
         open_callbacks(new StrictMock<MockMojoIndexedDBCallbacks>()),
         connection_callbacks(
-            new StrictMock<MockMojoIndexedDBDatabaseCallbacks>()){};
+            new StrictMock<MockMojoIndexedDBDatabaseCallbacks>()) {}
   ~TestDatabaseConnection() {}
 
   void Open(IDBFactory* factory) {
diff --git a/content/browser/indexed_db/scopes/README.md b/content/browser/indexed_db/scopes/README.md
index 75982fe..098eeb16 100644
--- a/content/browser/indexed_db/scopes/README.md
+++ b/content/browser/indexed_db/scopes/README.md
@@ -6,13 +6,13 @@
 
 # Status / Current State
 
-The only thing implemented so far is the lock manager interface & descrete implementation.
+The only thing implemented so far is the lock manager interface & discrete implementation.
 
 # Vocabulary
 
 **Scope**
 
-A scope encompases a group of changes that can be reverted. It is basically synonymous with a transaction, and would be used for readwrite and versionchange transactions in LevelDB. The scope has a defined list of key ranges where the changes can occur. It operates by keeping an undo log, which is either discarded on commit, or replayed on revert.
+A scope encompasses a group of changes that can be reverted. It is basically synonymous with a transaction, and would be used for readwrite and versionchange transactions in LevelDB. The scope has a defined list of key ranges where the changes can occur. It operates by keeping an undo log, which is either discarded on commit, or replayed on revert.
 
 **Undo Log**
 
@@ -69,7 +69,7 @@
     * Use the next available scope # (and increment the next scope #)
     * Signal the locks service that the key ranges for this scope are now locked
     * Write undo-scopes-scope# -> key_ranges to LevelDB
-* Enable operations on the scope (probably eventually by binding it using mojo)
+* Enable operations on the scope (probably eventually by binding it using Mojo)
 * For every operation, the scope must read the database to generate the undo log
     * See the [Undo Operation Generation](#undo-operations) section below
 * Output - a Scope
@@ -78,7 +78,7 @@
 **IndexedDB Sequence**
 
 * Input - a Scope
-* The scope is marked as 'committed', the commit point is written to the undo log (undo-scope#-0), and the metadatais updated to remove the key ranges (undo-scopes-scope# -> <empty>). This change is flushed to disk.
+* The scope is marked as 'committed', the commit point is written to the undo log (undo-scope#-0), and the metadata is updated to remove the key ranges (undo-scopes-scope# -> <empty>). This change is flushed to disk.
 * The Cleanup & Revert Sequence is signalled for cleaning up the committed scope #.
 * Output - Scope is committed, and lock is released.
 
@@ -181,4 +181,4 @@
 
 #### Deletion - key range will never be used again.
 
-This is done by having commit ranges in the value of the commit point. A new scope is created, and commited, with the key ranges never-to-be-used-again will be the value of the commit point record.
+This is done by having commit ranges in the value of the commit point. A new scope is created, and committed, with the key ranges never-to-be-used-again will be the value of the commit point record.
diff --git a/content/browser/loader/cross_site_document_resource_handler_unittest.cc b/content/browser/loader/cross_site_document_resource_handler_unittest.cc
index d5a90d2..4a9b759 100644
--- a/content/browser/loader/cross_site_document_resource_handler_unittest.cc
+++ b/content/browser/loader/cross_site_document_resource_handler_unittest.cc
@@ -1185,16 +1185,17 @@
     // Initialize |request_| from the parameters.
     request_ = context_.CreateRequest(GURL(target_url), net::DEFAULT_PRIORITY,
                                       &delegate_, TRAFFIC_ANNOTATION_FOR_TESTS);
-    ResourceRequestInfo::AllocateForTesting(request_.get(), resource_type,
-                                            nullptr,       // context
-                                            3,             // render_process_id
-                                            2,             // render_view_id
-                                            1,             // render_frame_id
-                                            true,          // is_main_frame
-                                            false,         // allow_download
-                                            true,          // is_async
-                                            PREVIEWS_OFF,  // previews_state
-                                            nullptr);      // navigation_ui_data
+    ResourceRequestInfo::AllocateForTesting(
+        request_.get(), resource_type,
+        nullptr,                              // context
+        3,                                    // render_process_id
+        2,                                    // render_view_id
+        1,                                    // render_frame_id
+        true,                                 // is_main_frame
+        ResourceInterceptPolicy::kAllowNone,  // resource_intercept_policy
+        true,                                 // is_async
+        PREVIEWS_OFF,                         // previews_state
+        nullptr);                             // navigation_ui_data
     request_->set_initiator(url::Origin::Create(GURL(initiator_origin)));
 
     // Create a sink handler to capture results.
diff --git a/content/browser/loader/detachable_resource_handler_unittest.cc b/content/browser/loader/detachable_resource_handler_unittest.cc
index 77a2ad4..3e77d918 100644
--- a/content/browser/loader/detachable_resource_handler_unittest.cc
+++ b/content/browser/loader/detachable_resource_handler_unittest.cc
@@ -62,12 +62,12 @@
                                         TRAFFIC_ANNOTATION_FOR_TESTS)) {
     ResourceRequestInfo::AllocateForTesting(request_.get(),
                                             RESOURCE_TYPE_MAIN_FRAME,
-                                            nullptr,       // context
-                                            0,             // render_process_id
-                                            0,             // render_view_id
-                                            0,             // render_frame_id
-                                            true,          // is_main_frame
-                                            true,          // allow_download
+                                            nullptr,  // context
+                                            0,        // render_process_id
+                                            0,        // render_view_id
+                                            0,        // render_frame_id
+                                            true,     // is_main_frame
+                                            ResourceInterceptPolicy::kAllowAll,
                                             true,          // is_async
                                             PREVIEWS_OFF,  // previews_state
                                             nullptr);      // navigation_ui_data
diff --git a/content/browser/loader/intercepting_resource_handler_unittest.cc b/content/browser/loader/intercepting_resource_handler_unittest.cc
index 4ad5954..26493cc 100644
--- a/content/browser/loader/intercepting_resource_handler_unittest.cc
+++ b/content/browser/loader/intercepting_resource_handler_unittest.cc
@@ -47,12 +47,12 @@
             net::URLRequestStatus::FromError(net::ERR_IO_PENDING)) {
     ResourceRequestInfo::AllocateForTesting(request_.get(),
                                             RESOURCE_TYPE_MAIN_FRAME,
-                                            nullptr,       // context
-                                            0,             // render_process_id
-                                            0,             // render_view_id
-                                            0,             // render_frame_id
-                                            true,          // is_main_frame
-                                            true,          // allow_download
+                                            nullptr,  // context
+                                            0,        // render_process_id
+                                            0,        // render_view_id
+                                            0,        // render_frame_id
+                                            true,     // is_main_frame
+                                            ResourceInterceptPolicy::kAllowAll,
                                             true,          // is_async
                                             PREVIEWS_OFF,  // previews_state
                                             nullptr);      // navigation_ui_data
diff --git a/content/browser/loader/mime_sniffing_resource_handler.cc b/content/browser/loader/mime_sniffing_resource_handler.cc
index 29fa240..3b788c4 100644
--- a/content/browser/loader/mime_sniffing_resource_handler.cc
+++ b/content/browser/loader/mime_sniffing_resource_handler.cc
@@ -446,7 +446,8 @@
 
   // Allow requests for object/embed tags to be intercepted as streams.
   if (info->GetResourceType() == content::RESOURCE_TYPE_OBJECT) {
-    DCHECK(!info->allow_download());
+    DCHECK(info->resource_intercept_policy() !=
+           ResourceInterceptPolicy::kAllowAll);
 
     bool handled_by_plugin;
     if (!CheckForPluginHandler(&handled_by_plugin))
@@ -455,10 +456,10 @@
       return true;
   }
 
-  if (!info->allow_download())
+  if (info->resource_intercept_policy() == ResourceInterceptPolicy::kAllowNone)
     return true;
 
-  // info->allow_download() == true implies
+  // A policy unequal to ResourceInterceptPolicy::kAllowNone implies
   // info->GetResourceType() == RESOURCE_TYPE_MAIN_FRAME or
   // info->GetResourceType() == RESOURCE_TYPE_SUB_FRAME.
   DCHECK(info->GetResourceType() == RESOURCE_TYPE_MAIN_FRAME ||
@@ -479,6 +480,11 @@
       return true;
   }
 
+  if (info->resource_intercept_policy() ==
+      ResourceInterceptPolicy::kAllowPluginOnly) {
+    return true;
+  }
+
   // This request is a download.
 
   if (!CheckResponseIsNotProvisional())
diff --git a/content/browser/loader/mime_sniffing_resource_handler_unittest.cc b/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
index 7fd98423..0fb000f 100644
--- a/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
+++ b/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
@@ -182,9 +182,10 @@
 
   void set_plugin_stale(bool plugin_stale) { plugin_stale_ = plugin_stale; }
 
-  bool TestStreamIsIntercepted(bool allow_download,
-                               bool must_download,
-                               ResourceType request_resource_type);
+  bool TestStreamIsIntercepted(
+      ResourceInterceptPolicy resource_intercept_policy,
+      bool must_download,
+      ResourceType request_resource_type);
 
   // Tests the operation of the MimeSniffingHandler when it needs to buffer
   // data (example case: the response is text/plain).
@@ -234,10 +235,10 @@
                                           0,              // render_view_id
                                           0,              // render_frame_id
                                           is_main_frame,  // is_main_frame
-                                          false,          // allow_download
-                                          true,           // is_async
-                                          PREVIEWS_OFF,   // previews_state
-                                          nullptr);       // navigation_ui_data
+                                          ResourceInterceptPolicy::kAllowNone,
+                                          true,          // is_async
+                                          PREVIEWS_OFF,  // previews_state
+                                          nullptr);      // navigation_ui_data
 
   std::unique_ptr<TestResourceHandler> scoped_test_handler(
       new TestResourceHandler());
@@ -257,7 +258,7 @@
 }
 
 bool MimeSniffingResourceHandlerTest::TestStreamIsIntercepted(
-    bool allow_download,
+    ResourceInterceptPolicy resource_intercept_policy,
     bool must_download,
     ResourceType request_resource_type) {
   net::URLRequestContext context;
@@ -266,15 +267,15 @@
       TRAFFIC_ANNOTATION_FOR_TESTS));
   bool is_main_frame = request_resource_type == RESOURCE_TYPE_MAIN_FRAME;
   ResourceRequestInfo::AllocateForTesting(request.get(), request_resource_type,
-                                          nullptr,         // context
-                                          0,               // render_process_id
-                                          0,               // render_view_id
-                                          0,               // render_frame_id
-                                          is_main_frame,   // is_main_frame
-                                          allow_download,  // allow_download
-                                          true,            // is_async
-                                          PREVIEWS_OFF,    // previews_state
-                                          nullptr);        // navigation_ui_data
+                                          nullptr,        // context
+                                          0,              // render_process_id
+                                          0,              // render_view_id
+                                          0,              // render_frame_id
+                                          is_main_frame,  // is_main_frame
+                                          resource_intercept_policy,
+                                          true,          // is_async
+                                          PREVIEWS_OFF,  // previews_state
+                                          nullptr);      // navigation_ui_data
 
   TestResourceDispatcherHost host(stream_has_handler_);
   TestContentBrowserClient new_client(must_download);
@@ -310,7 +311,7 @@
 
   content::RunAllPendingInMessageLoop();
   EXPECT_LT(host.intercepted_as_stream_count(), 2);
-  if (allow_download)
+  if (resource_intercept_policy != ResourceInterceptPolicy::kAllowNone)
     EXPECT_TRUE(intercepting_handler->new_handler_for_testing());
   SetBrowserClientForTesting(old_client);
   return host.intercepted_as_stream();
@@ -329,12 +330,12 @@
       TRAFFIC_ANNOTATION_FOR_TESTS));
   ResourceRequestInfo::AllocateForTesting(request.get(),
                                           RESOURCE_TYPE_MAIN_FRAME,
-                                          nullptr,       // context
-                                          0,             // render_process_id
-                                          0,             // render_view_id
-                                          0,             // render_frame_id
-                                          true,          // is_main_frame
-                                          false,         // allow_download
+                                          nullptr,  // context
+                                          0,        // render_process_id
+                                          0,        // render_view_id
+                                          0,        // render_frame_id
+                                          true,     // is_main_frame
+                                          ResourceInterceptPolicy::kAllowNone,
                                           true,          // is_async
                                           PREVIEWS_OFF,  // previews_state
                                           nullptr);      // navigation_ui_data
@@ -493,12 +494,12 @@
       TRAFFIC_ANNOTATION_FOR_TESTS));
   ResourceRequestInfo::AllocateForTesting(request.get(),
                                           RESOURCE_TYPE_MAIN_FRAME,
-                                          nullptr,       // context
-                                          0,             // render_process_id
-                                          0,             // render_view_id
-                                          0,             // render_frame_id
-                                          true,          // is_main_frame
-                                          false,         // allow_download
+                                          nullptr,  // context
+                                          0,        // render_process_id
+                                          0,        // render_view_id
+                                          0,        // render_frame_id
+                                          true,     // is_main_frame
+                                          ResourceInterceptPolicy::kAllowNone,
                                           true,          // is_async
                                           PREVIEWS_OFF,  // previews_state
                                           nullptr);      // navigation_ui_data
@@ -631,7 +632,7 @@
 // circumstances. Test is not relevent when plugins are disabled.
 #if BUILDFLAG(ENABLE_PLUGINS)
 TEST_F(MimeSniffingResourceHandlerTest, StreamHandling) {
-  bool allow_download;
+  ResourceInterceptPolicy resource_intercept_policy;
   bool must_download;
   ResourceType resource_type;
 
@@ -642,78 +643,86 @@
 
   // Main frame request with no download allowed. Stream shouldn't be
   // intercepted.
-  allow_download = false;
+  resource_intercept_policy = ResourceInterceptPolicy::kAllowNone;
   must_download = false;
   resource_type = RESOURCE_TYPE_MAIN_FRAME;
-  EXPECT_FALSE(
-      TestStreamIsIntercepted(allow_download, must_download, resource_type));
+  EXPECT_FALSE(TestStreamIsIntercepted(resource_intercept_policy, must_download,
+                                       resource_type));
+
+  // Main frame request with no download allowed only after plugin handler is
+  // checked. Stream should be intercepted.
+  resource_intercept_policy = ResourceInterceptPolicy::kAllowPluginOnly;
+  must_download = false;
+  resource_type = RESOURCE_TYPE_MAIN_FRAME;
+  EXPECT_TRUE(TestStreamIsIntercepted(resource_intercept_policy, must_download,
+                                      resource_type));
 
   // Main frame request with download allowed. Stream should be intercepted.
-  allow_download = true;
+  resource_intercept_policy = ResourceInterceptPolicy::kAllowAll;
   must_download = false;
   resource_type = RESOURCE_TYPE_MAIN_FRAME;
-  EXPECT_TRUE(
-      TestStreamIsIntercepted(allow_download, must_download, resource_type));
+  EXPECT_TRUE(TestStreamIsIntercepted(resource_intercept_policy, must_download,
+                                      resource_type));
 
   // Main frame request with download forced. Stream shouldn't be intercepted.
-  allow_download = true;
+  resource_intercept_policy = ResourceInterceptPolicy::kAllowAll;
   must_download = true;
   resource_type = RESOURCE_TYPE_MAIN_FRAME;
-  EXPECT_FALSE(
-      TestStreamIsIntercepted(allow_download, must_download, resource_type));
+  EXPECT_FALSE(TestStreamIsIntercepted(resource_intercept_policy, must_download,
+                                       resource_type));
 
   // Sub-resource request with download not allowed. Stream shouldn't be
   // intercepted.
-  allow_download = false;
+  resource_intercept_policy = ResourceInterceptPolicy::kAllowNone;
   must_download = false;
   resource_type = RESOURCE_TYPE_SUB_RESOURCE;
-  EXPECT_FALSE(
-      TestStreamIsIntercepted(allow_download, must_download, resource_type));
+  EXPECT_FALSE(TestStreamIsIntercepted(resource_intercept_policy, must_download,
+                                       resource_type));
 
   // Plugin resource request with download not allowed. Stream shouldn't be
   // intercepted.
-  allow_download = false;
+  resource_intercept_policy = ResourceInterceptPolicy::kAllowNone;
   must_download = false;
   resource_type = RESOURCE_TYPE_PLUGIN_RESOURCE;
-  EXPECT_FALSE(
-      TestStreamIsIntercepted(allow_download, must_download, resource_type));
+  EXPECT_FALSE(TestStreamIsIntercepted(resource_intercept_policy, must_download,
+                                       resource_type));
 
   // Object request with download not allowed. Stream should be intercepted.
-  allow_download = false;
+  resource_intercept_policy = ResourceInterceptPolicy::kAllowNone;
   must_download = false;
   resource_type = RESOURCE_TYPE_OBJECT;
-  EXPECT_TRUE(
-      TestStreamIsIntercepted(allow_download, must_download, resource_type));
+  EXPECT_TRUE(TestStreamIsIntercepted(resource_intercept_policy, must_download,
+                                      resource_type));
 
   // Test the cases where the stream isn't handled by MaybeInterceptAsStream
   // in the ResourceDispatcherHost.
   set_stream_has_handler(false);
-  allow_download = false;
+  resource_intercept_policy = ResourceInterceptPolicy::kAllowNone;
   must_download = false;
   resource_type = RESOURCE_TYPE_OBJECT;
-  EXPECT_FALSE(
-      TestStreamIsIntercepted(allow_download, must_download, resource_type));
+  EXPECT_FALSE(TestStreamIsIntercepted(resource_intercept_policy, must_download,
+                                       resource_type));
 
   // Test the cases where the stream handled by MaybeInterceptAsStream
   // with plugin not available. This is the case when intercepting streams for
   // the streamsPrivate extensions API.
   set_stream_has_handler(true);
   set_plugin_available(false);
-  allow_download = false;
+  resource_intercept_policy = ResourceInterceptPolicy::kAllowNone;
   must_download = false;
   resource_type = RESOURCE_TYPE_OBJECT;
-  EXPECT_TRUE(
-      TestStreamIsIntercepted(allow_download, must_download, resource_type));
+  EXPECT_TRUE(TestStreamIsIntercepted(resource_intercept_policy, must_download,
+                                      resource_type));
 
   // Test the cases where the stream handled by MaybeInterceptAsStream
   // with plugin not available. This is the case when intercepting streams for
   // the streamsPrivate extensions API with stale plugin.
   set_plugin_stale(true);
-  allow_download = false;
+  resource_intercept_policy = ResourceInterceptPolicy::kAllowNone;
   must_download = false;
   resource_type = RESOURCE_TYPE_OBJECT;
-  EXPECT_TRUE(
-      TestStreamIsIntercepted(allow_download, must_download, resource_type));
+  EXPECT_TRUE(TestStreamIsIntercepted(resource_intercept_policy, must_download,
+                                      resource_type));
 }
 #endif
 
@@ -835,12 +844,12 @@
       TRAFFIC_ANNOTATION_FOR_TESTS));
   ResourceRequestInfo::AllocateForTesting(request.get(),
                                           RESOURCE_TYPE_MAIN_FRAME,
-                                          nullptr,       // context
-                                          0,             // render_process_id
-                                          0,             // render_view_id
-                                          0,             // render_frame_id
-                                          true,          // is_main_frame
-                                          true,          // allow_download
+                                          nullptr,  // context
+                                          0,        // render_process_id
+                                          0,        // render_view_id
+                                          0,        // render_frame_id
+                                          true,     // is_main_frame
+                                          ResourceInterceptPolicy::kAllowAll,
                                           true,          // is_async
                                           PREVIEWS_OFF,  // previews_state
                                           nullptr);      // navigation_ui_data
@@ -886,12 +895,12 @@
       TRAFFIC_ANNOTATION_FOR_TESTS));
   ResourceRequestInfo::AllocateForTesting(request.get(),
                                           RESOURCE_TYPE_MAIN_FRAME,
-                                          nullptr,       // context
-                                          0,             // render_process_id
-                                          0,             // render_view_id
-                                          0,             // render_frame_id
-                                          true,          // is_main_frame
-                                          false,         // allow_download
+                                          nullptr,  // context
+                                          0,        // render_process_id
+                                          0,        // render_view_id
+                                          0,        // render_frame_id
+                                          true,     // is_main_frame
+                                          ResourceInterceptPolicy::kAllowNone,
                                           true,          // is_async
                                           PREVIEWS_OFF,  // previews_state
                                           nullptr);      // navigation_ui_data
@@ -946,12 +955,12 @@
       GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr,
       TRAFFIC_ANNOTATION_FOR_TESTS));
   ResourceRequestInfo::AllocateForTesting(request.get(), RESOURCE_TYPE_SCRIPT,
-                                          nullptr,       // context
-                                          0,             // render_process_id
-                                          0,             // render_view_id
-                                          0,             // render_frame_id
-                                          false,         // is_main_frame
-                                          false,         // allow_download
+                                          nullptr,  // context
+                                          0,        // render_process_id
+                                          0,        // render_view_id
+                                          0,        // render_frame_id
+                                          false,    // is_main_frame
+                                          ResourceInterceptPolicy::kAllowNone,
                                           true,          // is_async
                                           PREVIEWS_OFF,  // previews_state
                                           nullptr);      // navigation_ui_data
@@ -1024,12 +1033,12 @@
       GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr,
       TRAFFIC_ANNOTATION_FOR_TESTS));
   ResourceRequestInfo::AllocateForTesting(request.get(), RESOURCE_TYPE_SCRIPT,
-                                          nullptr,       // context
-                                          0,             // render_process_id
-                                          0,             // render_view_id
-                                          0,             // render_frame_id
-                                          false,         // is_main_frame
-                                          false,         // allow_download
+                                          nullptr,  // context
+                                          0,        // render_process_id
+                                          0,        // render_view_id
+                                          0,        // render_frame_id
+                                          false,    // is_main_frame
+                                          ResourceInterceptPolicy::kAllowNone,
                                           true,          // is_async
                                           PREVIEWS_OFF,  // previews_state
                                           nullptr);      // navigation_ui_data
diff --git a/content/browser/loader/mojo_async_resource_handler_unittest.cc b/content/browser/loader/mojo_async_resource_handler_unittest.cc
index 2eef312..05ecb533 100644
--- a/content/browser/loader/mojo_async_resource_handler_unittest.cc
+++ b/content/browser/loader/mojo_async_resource_handler_unittest.cc
@@ -314,7 +314,7 @@
         kRouteId,                                // render_view_id
         0,                                       // render_frame_id
         true,                                    // is_main_frame
-        false,                                   // allow_download
+        ResourceInterceptPolicy::kAllowNone,     // resource_intercept_policy
         true,                                    // is_async
         PREVIEWS_OFF,                            // previews_state
         nullptr);                                // navigation_ui_data
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 2e568ca..6d60ec6 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -967,10 +967,9 @@
       static_cast<ui::PageTransition>(request_data.transition_type),
       false,  // is download
       false,  // is stream
-      false,  // allow_download,
-      request_data.has_user_gesture, request_data.enable_load_timing,
-      request_data.enable_upload_progress, do_not_prompt_for_login,
-      request_data.keepalive,
+      ResourceInterceptPolicy::kAllowNone, request_data.has_user_gesture,
+      request_data.enable_load_timing, request_data.enable_upload_progress,
+      do_not_prompt_for_login, request_data.keepalive,
       Referrer::NetReferrerPolicyToBlinkReferrerPolicy(
           request_data.referrer_policy),
       request_data.is_prerendering, resource_context, report_raw_headers,
@@ -1167,12 +1166,13 @@
       RESOURCE_TYPE_SUB_RESOURCE, ui::PAGE_TRANSITION_LINK,
       download,  // is_download
       false,     // is_stream
-      download,  // allow_download
-      false,     // has_user_gesture
-      false,     // enable_load_timing
-      false,     // enable_upload_progress
-      false,     // do_not_prompt_for_login
-      false,     // keepalive
+      download ? ResourceInterceptPolicy::kAllowAll
+               : ResourceInterceptPolicy::kAllowNone,
+      false,  // has_user_gesture
+      false,  // enable_load_timing
+      false,  // enable_upload_progress
+      false,  // do_not_prompt_for_login
+      false,  // keepalive
       network::mojom::ReferrerPolicy::kDefault,
       false,  // is_prerendering
       context,
@@ -1510,7 +1510,7 @@
       resource_type, info.common_params.transition,
       false,  // is download
       false,  // is stream
-      IsNavigationDownloadAllowed(info.common_params.download_policy),
+      GetResourceInterceptPolicy(info.common_params.download_policy),
       info.common_params.has_user_gesture,
       true,   // enable_load_timing
       false,  // enable_upload_progress
diff --git a/content/browser/loader/resource_loader_unittest.cc b/content/browser/loader/resource_loader_unittest.cc
index 70f47021..fc32a259 100644
--- a/content/browser/loader/resource_loader_unittest.cc
+++ b/content/browser/loader/resource_loader_unittest.cc
@@ -442,9 +442,9 @@
     ResourceRequestInfo::AllocateForTesting(
         request.get(), resource_type, nullptr /* resource_context */,
         rfh->GetProcess()->GetID(), rfh->GetRenderViewHost()->GetRoutingID(),
-        rfh->GetRoutingID(), belongs_to_main_frame, true /* allow_download */,
-        false /* is_async */, PREVIEWS_OFF /* previews_state */,
-        nullptr /* navigation_ui_data */);
+        rfh->GetRoutingID(), belongs_to_main_frame,
+        ResourceInterceptPolicy::kAllowAll, false /* is_async */,
+        PREVIEWS_OFF /* previews_state */, nullptr /* navigation_ui_data */);
     std::unique_ptr<TestResourceHandler> resource_handler(
         new TestResourceHandler(nullptr, nullptr));
     raw_ptr_resource_handler_ = resource_handler.get();
diff --git a/content/browser/loader/resource_request_info_impl.cc b/content/browser/loader/resource_request_info_impl.cc
index ca07efa..4456f56 100644
--- a/content/browser/loader/resource_request_info_impl.cc
+++ b/content/browser/loader/resource_request_info_impl.cc
@@ -58,7 +58,7 @@
     int render_view_id,
     int render_frame_id,
     bool is_main_frame,
-    bool allow_download,
+    ResourceInterceptPolicy resource_intercept_policy,
     bool is_async,
     PreviewsState previews_state,
     std::unique_ptr<NavigationUIData> navigation_ui_data) {
@@ -80,7 +80,7 @@
       ui::PAGE_TRANSITION_LINK,                  // transition_type
       false,                                     // is_download
       false,                                     // is_stream
-      allow_download,                            // allow_download
+      resource_intercept_policy,                 // resource_intercept_policy
       false,                                     // has_user_gesture
       false,                                     // enable load timing
       request->has_upload(),                     // enable upload progress
@@ -149,7 +149,7 @@
     ui::PageTransition transition_type,
     bool is_download,
     bool is_stream,
-    bool allow_download,
+    ResourceInterceptPolicy resource_intercept_policy,
     bool has_user_gesture,
     bool enable_load_timing,
     bool enable_upload_progress,
@@ -175,7 +175,7 @@
       fetch_window_id_(fetch_window_id),
       is_download_(is_download),
       is_stream_(is_stream),
-      allow_download_(allow_download),
+      resource_intercept_policy_(resource_intercept_policy),
       has_user_gesture_(has_user_gesture),
       enable_load_timing_(enable_load_timing),
       enable_upload_progress_(enable_upload_progress),
diff --git a/content/browser/loader/resource_request_info_impl.h b/content/browser/loader/resource_request_info_impl.h
index 6658ab8..2970918 100644
--- a/content/browser/loader/resource_request_info_impl.h
+++ b/content/browser/loader/resource_request_info_impl.h
@@ -20,6 +20,7 @@
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/common/previews_state.h"
 #include "content/public/common/referrer.h"
+#include "content/public/common/resource_intercept_policy.h"
 #include "content/public/common/resource_type.h"
 #include "net/base/load_states.h"
 #include "services/network/public/cpp/resource_request_body.h"
@@ -57,7 +58,7 @@
       ui::PageTransition transition_type,
       bool is_download,
       bool is_stream,
-      bool allow_download,
+      ResourceInterceptPolicy resource_intercept_policy,
       bool has_user_gesture,
       bool enable_load_timing,
       bool enable_upload_progress,
@@ -134,8 +135,9 @@
   }
   bool keepalive() const { return keepalive_; }
 
-  // Downloads are allowed only as a top level request.
-  bool allow_download() const { return allow_download_; }
+  ResourceInterceptPolicy resource_intercept_policy() const {
+    return resource_intercept_policy_;
+  }
 
   // Whether this is a download.
   void set_is_download(bool download) { is_download_ = download; }
@@ -232,7 +234,7 @@
   base::UnguessableToken fetch_window_id_;
   bool is_download_;
   bool is_stream_;
-  bool allow_download_;
+  ResourceInterceptPolicy resource_intercept_policy_;
   bool has_user_gesture_;
   bool enable_load_timing_;
   bool enable_upload_progress_;
diff --git a/content/browser/media/session/media_metadata_sanitizer.cc b/content/browser/media/session/media_metadata_sanitizer.cc
index 33cd5e4..a46840b 100644
--- a/content/browser/media/session/media_metadata_sanitizer.cc
+++ b/content/browser/media/session/media_metadata_sanitizer.cc
@@ -56,9 +56,8 @@
 
 }  // anonymous namespace
 
-bool MediaMetadataSanitizer::SanitizeAndConvert(
-    const blink::mojom::SpecMediaMetadataPtr& metadata,
-    media_session::MediaMetadata* metadata_out) {
+bool MediaMetadataSanitizer::CheckSanity(
+    const blink::mojom::SpecMediaMetadataPtr& metadata) {
   if (metadata->title.size() > kMaxIPCStringLength)
     return false;
   if (metadata->artist.size() > kMaxIPCStringLength)
@@ -68,15 +67,9 @@
   if (metadata->artwork.size() > kMaxNumberOfMediaImages)
     return false;
 
-  metadata_out->title = metadata->title;
-  metadata_out->artist = metadata->artist;
-  metadata_out->album = metadata->album;
-
   for (const auto& image : metadata->artwork) {
     if (!CheckMediaImageSanity(image))
       return false;
-
-    metadata_out->artwork.push_back(image);
   }
 
   return true;
diff --git a/content/browser/media/session/media_metadata_sanitizer.h b/content/browser/media/session/media_metadata_sanitizer.h
index c3719ee9..0b21ced5 100644
--- a/content/browser/media/session/media_metadata_sanitizer.h
+++ b/content/browser/media/session/media_metadata_sanitizer.h
@@ -7,19 +7,12 @@
 
 #include "third_party/blink/public/platform/modules/mediasession/media_session.mojom.h"
 
-namespace media_session {
-struct MediaMetadata;
-}  // namespace media_session
-
 namespace content {
 
 class MediaMetadataSanitizer {
  public:
-  // Converts |metadata| to a media_session::MediaMetadata object and returns
-  // whether it is valid.
-  static bool SanitizeAndConvert(
-      const blink::mojom::SpecMediaMetadataPtr& metadata,
-      media_session::MediaMetadata* metadata_out);
+  // Check the sanity of |metadata|.
+  static bool CheckSanity(const blink::mojom::SpecMediaMetadataPtr& metadata);
 };
 
 }  // namespace content
diff --git a/content/browser/media/session/media_session_android.cc b/content/browser/media/session/media_session_android.cc
index 0204354..2b94e520 100644
--- a/content/browser/media/session/media_session_android.cc
+++ b/content/browser/media/session/media_session_android.cc
@@ -13,6 +13,7 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/media_session.h"
 #include "jni/MediaSessionImpl_jni.h"
+#include "services/media_session/public/cpp/media_image.h"
 #include "services/media_session/public/mojom/audio_focus.mojom.h"
 
 namespace content {
@@ -121,6 +122,29 @@
       env, j_local_session, base::android::ToJavaIntArray(env, actions_vec));
 }
 
+void MediaSessionAndroid::MediaSessionImagesChanged(
+    const base::flat_map<media_session::mojom::MediaSessionImageType,
+                         std::vector<media_session::MediaImage>>& images) {
+  ScopedJavaLocalRef<jobject> j_local_session = GetJavaObject();
+  if (j_local_session.is_null())
+    return;
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+
+  // Android is only interested in the artwork images.
+  auto it = images.find(media_session::mojom::MediaSessionImageType::kArtwork);
+  if (it == images.end())
+    return;
+
+  // Avoid translating metadata through JNI if there is no Java observer.
+  if (!Java_MediaSessionImpl_hasObservers(env, j_local_session))
+    return;
+
+  Java_MediaSessionImpl_mediaSessionArtworkChanged(
+      env, j_local_session,
+      media_session::MediaImage::ToJavaArray(env, it->second));
+}
+
 void MediaSessionAndroid::Resume(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& j_obj) {
diff --git a/content/browser/media/session/media_session_android.h b/content/browser/media/session/media_session_android.h
index 80907781..7352f286 100644
--- a/content/browser/media/session/media_session_android.h
+++ b/content/browser/media/session/media_session_android.h
@@ -44,7 +44,7 @@
   void MediaSessionImagesChanged(
       const base::flat_map<media_session::mojom::MediaSessionImageType,
                            std::vector<media_session::MediaImage>>& images)
-      override {}
+      override;
 
   // MediaSession method wrappers.
   void Resume(JNIEnv* env, const base::android::JavaParamRef<jobject>& j_obj);
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc
index 45c89ec..4371c70a 100644
--- a/content/browser/media/session/media_session_impl.cc
+++ b/content/browser/media/session/media_session_impl.cc
@@ -1041,10 +1041,15 @@
 }
 
 void MediaSessionImpl::RebuildAndNotifyMetadataChanged() {
-  media_session::MediaMetadata metadata =
-      (routed_service_ && routed_service_->metadata())
-          ? *routed_service_->metadata()
-          : media_session::MediaMetadata();
+  std::vector<media_session::MediaImage> artwork;
+  media_session::MediaMetadata metadata;
+
+  if (routed_service_ && routed_service_->metadata()) {
+    metadata.title = routed_service_->metadata()->title;
+    metadata.artist = routed_service_->metadata()->artist;
+    metadata.album = routed_service_->metadata()->album;
+    artwork = routed_service_->metadata()->artwork;
+  }
 
   metadata.source_title = url_formatter::FormatOriginForSecurityDisplay(
       url::Origin::Create(web_contents()->GetLastCommittedURL()));
@@ -1052,9 +1057,9 @@
   // If we have no artwork in |images_| or the arwork has changed then we should
   // update it with the latest artwork from the routed service.
   auto it = images_.find(MediaSessionImageType::kArtwork);
-  bool images_changed = it == images_.end() || it->second != metadata.artwork;
+  bool images_changed = it == images_.end() || it->second != artwork;
   if (images_changed)
-    images_.insert_or_assign(MediaSessionImageType::kArtwork, metadata.artwork);
+    images_.insert_or_assign(MediaSessionImageType::kArtwork, artwork);
 
   bool metadata_changed = metadata_ != metadata;
   if (metadata_changed)
diff --git a/content/browser/media/session/media_session_service_impl.cc b/content/browser/media/session/media_session_service_impl.cc
index 2173235..3b035d3 100644
--- a/content/browser/media/session/media_session_service_impl.cc
+++ b/content/browser/media/session/media_session_service_impl.cc
@@ -75,9 +75,7 @@
   // When receiving a MediaMetadata, the browser process can't trust that it is
   // coming from a known and secure source. It must be processed accordingly.
   if (!metadata.is_null()) {
-    media_session::MediaMetadata new_metadata;
-
-    if (!MediaMetadataSanitizer::SanitizeAndConvert(metadata, &new_metadata)) {
+    if (!MediaMetadataSanitizer::CheckSanity(metadata)) {
       RenderFrameHost* rfh = GetRenderFrameHost();
       if (rfh) {
         rfh->GetProcess()->ShutdownForBadMessage(
@@ -86,7 +84,7 @@
       return;
     }
 
-    metadata_ = new_metadata;
+    metadata_ = std::move(metadata);
   }
 
   MediaSessionImpl* session = GetMediaSession();
diff --git a/content/browser/media/session/media_session_service_impl.h b/content/browser/media/session/media_session_service_impl.h
index 15baf5d..06a0d36 100644
--- a/content/browser/media/session/media_session_service_impl.h
+++ b/content/browser/media/session/media_session_service_impl.h
@@ -5,14 +5,9 @@
 #ifndef CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_SERVICE_IMPL_H_
 #define CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_SERVICE_IMPL_H_
 
-#include "base/optional.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "third_party/blink/public/platform/modules/mediasession/media_session.mojom.h"
 
-namespace media_session {
-struct MediaMetadata;
-}  // namespace media_session
-
 namespace content {
 
 class RenderFrameHost;
@@ -34,7 +29,7 @@
   blink::mojom::MediaSessionPlaybackState playback_state() const {
     return playback_state_;
   }
-  const base::Optional<media_session::MediaMetadata>& metadata() const {
+  const blink::mojom::SpecMediaMetadataPtr& metadata() const {
     return metadata_;
   }
   const std::set<media_session::mojom::MediaSessionAction>& actions() const {
@@ -71,7 +66,7 @@
   std::unique_ptr<mojo::Binding<blink::mojom::MediaSessionService>> binding_;
   blink::mojom::MediaSessionClientPtr client_;
   blink::mojom::MediaSessionPlaybackState playback_state_;
-  base::Optional<media_session::MediaMetadata> metadata_;
+  blink::mojom::SpecMediaMetadataPtr metadata_;
   std::set<media_session::mojom::MediaSessionAction> actions_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaSessionServiceImpl);
diff --git a/content/browser/media/session/media_session_service_impl_browsertest.cc b/content/browser/media/session/media_session_service_impl_browsertest.cc
index ab961606..986e0c9 100644
--- a/content/browser/media/session/media_session_service_impl_browsertest.cc
+++ b/content/browser/media/session/media_session_service_impl_browsertest.cc
@@ -167,7 +167,7 @@
 
   EXPECT_EQ(blink::mojom::MediaSessionPlaybackState::PLAYING,
             GetService()->playback_state());
-  EXPECT_TRUE(GetService()->metadata().has_value());
+  EXPECT_TRUE(GetService()->metadata());
   EXPECT_EQ(1u, GetService()->actions().size());
 
   // Start a non-same-page navigation and check the playback state, metadata,
@@ -176,7 +176,7 @@
 
   EXPECT_EQ(blink::mojom::MediaSessionPlaybackState::NONE,
             GetService()->playback_state());
-  EXPECT_FALSE(GetService()->metadata().has_value());
+  EXPECT_FALSE(GetService()->metadata());
   EXPECT_EQ(0u, GetService()->actions().size());
 }
 
@@ -204,7 +204,7 @@
 
   EXPECT_EQ(blink::mojom::MediaSessionPlaybackState::PLAYING,
             GetService()->playback_state());
-  EXPECT_TRUE(GetService()->metadata().has_value());
+  EXPECT_TRUE(GetService()->metadata());
   EXPECT_EQ(1u, GetService()->actions().size());
 }
 
diff --git a/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc b/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc
index abefe2a56..028d231 100644
--- a/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc
+++ b/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc
@@ -61,6 +61,7 @@
   ui::Layer* GetVideoLayer() override { return nullptr; }
   gfx::Rect GetVideoBounds() override { return gfx::Rect(); }
   void SetSkipAdButtonVisibility(bool is_visible) override {}
+  void SetNextTrackButtonVisibility(bool is_visible) override {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TestOverlayWindow);
diff --git a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
index b26f9d0..17ec939 100644
--- a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
+++ b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
@@ -73,6 +73,8 @@
   DCHECK(surface_id_.is_valid());
 
   MediaSessionImpl* media_session = MediaSessionImpl::Get(initiator_);
+  media_session_action_next_track_handled_ = media_session->ShouldRouteAction(
+      media_session::mojom::MediaSessionAction::kNextTrack);
   media_session_action_play_handled_ = media_session->ShouldRouteAction(
       media_session::mojom::MediaSessionAction::kPlay);
   media_session_action_pause_handled_ = media_session->ShouldRouteAction(
@@ -82,6 +84,8 @@
 
   UpdatePlayPauseButtonVisibility();
   window_->SetSkipAdButtonVisibility(media_session_action_skip_ad_handled_);
+  window_->SetNextTrackButtonVisibility(
+      media_session_action_next_track_handled_);
   window_->ShowInactive();
   initiator_->SetHasPictureInPictureVideo(true);
 
@@ -237,6 +241,11 @@
     MediaSession::Get(initiator_)->SkipAd();
 }
 
+void PictureInPictureWindowControllerImpl::NextTrack() {
+  if (media_session_action_next_track_handled_)
+    MediaSession::Get(initiator_)->NextTrack();
+}
+
 void PictureInPictureWindowControllerImpl::MediaSessionActionsChanged(
     const std::set<media_session::mojom::MediaSessionAction>& actions) {
   // TODO(crbug.com/919842): Currently, the first Media Session to be created
@@ -244,6 +253,9 @@
   // Skip Ad button for a PiP video from another frame. Ideally, we should have
   // a Media Session per frame, not per tab. This is not implemented yet.
 
+  media_session_action_next_track_handled_ =
+      actions.find(media_session::mojom::MediaSessionAction::kNextTrack) !=
+      actions.end();
   media_session_action_pause_handled_ =
       actions.find(media_session::mojom::MediaSessionAction::kPause) !=
       actions.end();
@@ -259,6 +271,8 @@
 
   UpdatePlayPauseButtonVisibility();
   window_->SetSkipAdButtonVisibility(media_session_action_skip_ad_handled_);
+  window_->SetNextTrackButtonVisibility(
+      media_session_action_next_track_handled_);
 }
 
 void PictureInPictureWindowControllerImpl::MediaStartedPlaying(
diff --git a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
index c9da400..e4655cdd 100644
--- a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
+++ b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
@@ -60,6 +60,7 @@
                                           bool reached_end_of_stream) override;
   CONTENT_EXPORT void SetAlwaysHidePlayPauseButton(bool is_visible) override;
   CONTENT_EXPORT void SkipAd() override;
+  CONTENT_EXPORT void NextTrack() override;
 
   CONTENT_EXPORT void MediaSessionActionsChanged(
       const std::set<media_session::mojom::MediaSessionAction>& actions);
@@ -117,6 +118,7 @@
 
   // Used to show/hide some actions in Picture-in-Picture window. These are set
   // to true when website handles some Media Session actions.
+  bool media_session_action_next_track_handled_ = false;
   bool media_session_action_play_handled_ = false;
   bool media_session_action_pause_handled_ = false;
   bool media_session_action_skip_ad_handled_ = false;
diff --git a/content/browser/renderer_host/direct_manipulation_browsertest.cc b/content/browser/renderer_host/direct_manipulation_browsertest.cc
index d6dcec13..07b0aa2 100644
--- a/content/browser/renderer_host/direct_manipulation_browsertest.cc
+++ b/content/browser/renderer_host/direct_manipulation_browsertest.cc
@@ -119,7 +119,7 @@
   shell2->Close();
 }
 
-// EventLogger is to obserser the events sent from WindowEventTarget (the root
+// EventLogger is to observe the events sent from WindowEventTarget (the root
 // window).
 class EventLogger : public ui::EventRewriter {
  public:
@@ -132,19 +132,12 @@
 
  private:
   // ui::EventRewriter
-  ui::EventRewriteStatus RewriteEvent(
+  ui::EventDispatchDetails RewriteEvent(
       const ui::Event& event,
-      std::unique_ptr<ui::Event>* new_event) override {
+      const Continuation continuation) override {
     DCHECK(!last_event_);
     last_event_ = ui::Event::Clone(event);
-    return ui::EVENT_REWRITE_CONTINUE;
-  }
-
-  // ui::EventRewriter
-  ui::EventRewriteStatus NextDispatchEvent(
-      const ui::Event& last_event,
-      std::unique_ptr<ui::Event>* new_event) override {
-    return ui::EVENT_REWRITE_CONTINUE;
+    return SendEvent(continuation, &event);
   }
 
   std::unique_ptr<ui::Event> last_event_ = nullptr;
diff --git a/content/browser/renderer_host/input/input_router_impl.cc b/content/browser/renderer_host/input/input_router_impl.cc
index e1e36d1b..f26efe9 100644
--- a/content/browser/renderer_host/input/input_router_impl.cc
+++ b/content/browser/renderer_host/input/input_router_impl.cc
@@ -73,7 +73,6 @@
     : client_(client),
       disposition_handler_(disposition_handler),
       frame_tree_node_id_(-1),
-      active_renderer_fling_count_(0),
       touch_scroll_started_sent_(false),
       wheel_event_queue_(this),
       touch_event_queue_(this, config.touch_config),
@@ -217,8 +216,7 @@
 bool InputRouterImpl::HasPendingEvents() const {
   return !touch_event_queue_.Empty() || !gesture_event_queue_.empty() ||
          wheel_event_queue_.has_pending() ||
-         touchpad_pinch_event_queue_.has_pending() ||
-         active_renderer_fling_count_ > 0;
+         touchpad_pinch_event_queue_.has_pending();
 }
 
 void InputRouterImpl::SetDeviceScaleFactor(float device_scale_factor) {
diff --git a/content/browser/renderer_host/input/input_router_impl.h b/content/browser/renderer_host/input/input_router_impl.h
index 11f7290..c6836df 100644
--- a/content/browser/renderer_host/input/input_router_impl.h
+++ b/content/browser/renderer_host/input/input_router_impl.h
@@ -225,11 +225,6 @@
   InputDispositionHandler* disposition_handler_;
   int frame_tree_node_id_;
 
-  // Whether there are any active flings in the renderer. As the fling
-  // end notification is asynchronous, we use a count rather than a boolean
-  // to avoid races in bookkeeping when starting a new fling.
-  int active_renderer_fling_count_;
-
   // Whether the TouchScrollStarted event has been sent for the current
   // gesture scroll yet.
   bool touch_scroll_started_sent_;
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_android.cc b/content/browser/renderer_host/input/synthetic_gesture_target_android.cc
index 760ebcb..3798420 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_target_android.cc
+++ b/content/browser/renderer_host/input/synthetic_gesture_target_android.cc
@@ -6,6 +6,7 @@
 
 #include "base/trace_event/trace_event.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_view_android.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
 #include "jni/SyntheticGestureTarget_jni.h"
 #include "third_party/blink/public/platform/web_input_event.h"
@@ -17,6 +18,7 @@
 
 using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
+using blink::WebGestureEvent;
 using blink::WebInputEvent;
 using blink::WebMouseEvent;
 using blink::WebMouseWheelEvent;
@@ -113,6 +115,15 @@
   TouchInject(MOTION_EVENT_ACTION_SCROLL, 1, web_wheel.TimeStamp());
 }
 
+void SyntheticGestureTargetAndroid::DispatchWebGestureEventToPlatform(
+    const WebGestureEvent& web_gesture,
+    const ui::LatencyInfo& latency_info) {
+  DCHECK_EQ(blink::kWebGestureDeviceTouchpad, web_gesture.SourceDevice());
+  DCHECK(blink::WebInputEvent::IsPinchGestureEventType(web_gesture.GetType()) ||
+         blink::WebInputEvent::IsFlingGestureEventType(web_gesture.GetType()));
+  GetView()->SendGestureEvent(web_gesture);
+}
+
 void SyntheticGestureTargetAndroid::DispatchWebMouseEventToPlatform(
     const WebMouseEvent& web_mouse,
     const ui::LatencyInfo&) {
@@ -136,4 +147,11 @@
   return gfx::ViewConfiguration::GetMinScalingSpanInDips();
 }
 
+RenderWidgetHostViewAndroid* SyntheticGestureTargetAndroid::GetView() const {
+  auto* view = static_cast<RenderWidgetHostViewAndroid*>(
+      render_widget_host()->GetView());
+  DCHECK(view);
+  return view;
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_android.h b/content/browser/renderer_host/input/synthetic_gesture_target_android.h
index f96f715..5f203ae 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_target_android.h
+++ b/content/browser/renderer_host/input/synthetic_gesture_target_android.h
@@ -8,6 +8,7 @@
 #include "base/android/jni_android.h"
 #include "base/android/scoped_java_ref.h"
 #include "content/browser/renderer_host/input/synthetic_gesture_target_base.h"
+#include "content/browser/renderer_host/render_widget_host_view_android.h"
 #include "content/public/browser/android/motion_event_action.h"
 
 namespace ui {
@@ -32,6 +33,9 @@
   void DispatchWebMouseWheelEventToPlatform(
       const blink::WebMouseWheelEvent& web_wheel,
       const ui::LatencyInfo& latency_info) override;
+  void DispatchWebGestureEventToPlatform(
+      const blink::WebGestureEvent& web_gesture,
+      const ui::LatencyInfo& latency_info) override;
   void DispatchWebMouseEventToPlatform(
       const blink::WebMouseEvent& web_mouse,
       const ui::LatencyInfo& latency_info) override;
@@ -49,6 +53,8 @@
                    int pointer_count,
                    base::TimeTicks time);
 
+  RenderWidgetHostViewAndroid* GetView() const;
+
   ui::ViewAndroid* const view_;
   base::android::ScopedJavaGlobalRef<jobject> java_ref_;
 
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc b/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
index 69a354a..45cb261 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
+++ b/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
@@ -87,14 +87,8 @@
       const blink::WebMouseWheelEvent& web_wheel,
       const ui::LatencyInfo&) {
   if (web_wheel.phase == blink::WebMouseWheelEvent::kPhaseEnded) {
-    DCHECK(
-        !render_widget_host()->GetView()->IsRenderWidgetHostViewChildFrame() &&
-        !render_widget_host()->GetView()->IsRenderWidgetHostViewGuest());
     // Send the pending wheel end event immediately.
-    static_cast<RenderWidgetHostViewAura*>(render_widget_host()->GetView())
-        ->event_handler()
-        ->mouse_wheel_phase_handler()
-        .DispatchPendingWheelEndEvent();
+    GetView()->GetMouseWheelPhaseHandler()->DispatchPendingWheelEndEvent();
     return;
   }
   base::TimeTicks timestamp = web_wheel.TimeStamp();
@@ -213,8 +207,15 @@
   return ui::GestureConfiguration::GetInstance()->min_scaling_span_in_pixels();
 }
 
+RenderWidgetHostViewAura* SyntheticGestureTargetAura::GetView() const {
+  auto* view =
+      static_cast<RenderWidgetHostViewAura*>(render_widget_host()->GetView());
+  DCHECK(view);
+  return view;
+}
+
 aura::Window* SyntheticGestureTargetAura::GetWindow() const {
-  aura::Window* window = render_widget_host()->GetView()->GetNativeView();
+  aura::Window* window = GetView()->GetNativeView();
   DCHECK(window);
   return window;
 }
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_aura.h b/content/browser/renderer_host/input/synthetic_gesture_target_aura.h
index 5d5a32b3..3117e31a 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_target_aura.h
+++ b/content/browser/renderer_host/input/synthetic_gesture_target_aura.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "content/browser/renderer_host/input/synthetic_gesture_target_base.h"
+#include "content/browser/renderer_host/render_widget_host_view_aura.h"
 #include "content/common/input/synthetic_gesture_params.h"
 #include "ui/aura/event_injector.h"
 
@@ -47,6 +48,7 @@
   float GetMinScalingSpanInDips() const override;
 
  private:
+  RenderWidgetHostViewAura* GetView() const;
   aura::Window* GetWindow() const;
 
   // Synthetic located event's location and touch event's radius are in DIP and
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_mac.h b/content/browser/renderer_host/input/synthetic_gesture_target_mac.h
index ea9ec3e..475829b 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_target_mac.h
+++ b/content/browser/renderer_host/input/synthetic_gesture_target_mac.h
@@ -22,11 +22,26 @@
   void DispatchWebTouchEventToPlatform(
       const blink::WebTouchEvent& event,
       const ui::LatencyInfo& latency_info) override;
+  void DispatchWebMouseWheelEventToPlatform(
+      const blink::WebMouseWheelEvent& web_wheel,
+      const ui::LatencyInfo& latency_info) override;
   void DispatchWebGestureEventToPlatform(
       const blink::WebGestureEvent& web_gesture,
       const ui::LatencyInfo& latency_info) override;
+  void DispatchWebMouseEventToPlatform(
+      const blink::WebMouseEvent& web_mouse,
+      const ui::LatencyInfo& latency_info) override;
+
+  // SyntheticGestureTarget:
+  SyntheticGestureParams::GestureSourceType
+  GetDefaultSyntheticGestureSourceType() const override;
+
+  float GetTouchSlopInDips() const override;
+  float GetSpanSlopInDips() const override;
+  float GetMinScalingSpanInDips() const override;
 
  private:
+  RenderWidgetHostViewMac* GetView() const;
   RenderWidgetHostViewCocoa* cocoa_view_;
 
   DISALLOW_COPY_AND_ASSIGN(SyntheticGestureTargetMac);
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_mac.mm b/content/browser/renderer_host/input/synthetic_gesture_target_mac.mm
index 08d8639..90871e8 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_target_mac.mm
+++ b/content/browser/renderer_host/input/synthetic_gesture_target_mac.mm
@@ -6,7 +6,9 @@
 
 #include "base/mac/scoped_nsautorelease_pool.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
 #import "content/browser/renderer_host/render_widget_host_view_cocoa.h"
+#include "ui/events/gesture_detection/gesture_configuration.h"
 
 // Unlike some event APIs, Apple does not provide a way to programmatically
 // build a zoom event. To work around this, we leverage ObjectiveC's flexible
@@ -128,7 +130,51 @@
 void SyntheticGestureTargetMac::DispatchWebTouchEventToPlatform(
     const blink::WebTouchEvent& web_touch,
     const ui::LatencyInfo& latency_info) {
-  render_widget_host()->GetView()->InjectTouchEvent(web_touch, latency_info);
+  GetView()->InjectTouchEvent(web_touch, latency_info);
+}
+
+void SyntheticGestureTargetMac::DispatchWebMouseWheelEventToPlatform(
+    const blink::WebMouseWheelEvent& web_wheel,
+    const ui::LatencyInfo& latency_info) {
+  GetView()->RouteOrProcessWheelEvent(web_wheel);
+  if (web_wheel.phase == blink::WebMouseWheelEvent::kPhaseEnded) {
+    // Send the pending wheel end event immediately. Otherwise, the
+    // MouseWheelPhaseHandler will defer the end event in case of momentum
+    // scrolling. We want the end event sent before resolving the completion
+    // callback.
+    GetView()->GetMouseWheelPhaseHandler()->DispatchPendingWheelEndEvent();
+  }
+}
+
+void SyntheticGestureTargetMac::DispatchWebMouseEventToPlatform(
+    const blink::WebMouseEvent& web_mouse,
+    const ui::LatencyInfo& latency_info) {
+  GetView()->RouteOrProcessMouseEvent(web_mouse);
+}
+
+SyntheticGestureParams::GestureSourceType
+SyntheticGestureTargetMac::GetDefaultSyntheticGestureSourceType() const {
+  return SyntheticGestureParams::MOUSE_INPUT;
+}
+
+float SyntheticGestureTargetMac::GetTouchSlopInDips() const {
+  return ui::GestureConfiguration::GetInstance()
+      ->max_touch_move_in_pixels_for_click();
+}
+
+float SyntheticGestureTargetMac::GetSpanSlopInDips() const {
+  return ui::GestureConfiguration::GetInstance()->span_slop();
+}
+
+float SyntheticGestureTargetMac::GetMinScalingSpanInDips() const {
+  return ui::GestureConfiguration::GetInstance()->min_scaling_span_in_pixels();
+}
+
+RenderWidgetHostViewMac* SyntheticGestureTargetMac::GetView() const {
+  auto* view =
+      static_cast<RenderWidgetHostViewMac*>(render_widget_host()->GetView());
+  DCHECK(view);
+  return view;
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index fb40b669..e5755ad 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -347,6 +347,8 @@
     last_pointer_type_ = last_pointer_type;
   }
 
+  MouseWheelPhaseHandler* GetMouseWheelPhaseHandler() override;
+
  protected:
   ~RenderWidgetHostViewAura() override;
 
@@ -458,8 +460,6 @@
   // collide with FrameSinkIds used by RenderWidgetHostImpls.
   static viz::FrameSinkId AllocateFrameSinkIdForGuestViewHack();
 
-  MouseWheelPhaseHandler* GetMouseWheelPhaseHandler() override;
-
   void CreateAuraWindow(aura::client::WindowType type);
 
   // Returns true if a stale frame content needs to be set for the current RWHV.
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 318a27b..68d55c2 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -556,12 +556,6 @@
   return weak_factory_.GetWeakPtr();
 }
 
-std::unique_ptr<SyntheticGestureTarget>
-RenderWidgetHostViewBase::CreateSyntheticGestureTarget() {
-  return std::unique_ptr<SyntheticGestureTarget>(
-      new SyntheticGestureTargetBase(host()));
-}
-
 void RenderWidgetHostViewBase::FocusedNodeTouched(
     bool editable) {
   DVLOG(1) << "FocusedNodeTouched: " << editable;
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 e36a58a2..148c980 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -252,7 +252,7 @@
   // Create a platform specific SyntheticGestureTarget implementation that will
   // be used to inject synthetic input events.
   virtual std::unique_ptr<SyntheticGestureTarget>
-  CreateSyntheticGestureTarget();
+  CreateSyntheticGestureTarget() = 0;
 
   // Create a BrowserAccessibilityManager for a frame in this view.
   // If |for_root_frame| is true, creates a BrowserAccessibilityManager
@@ -340,9 +340,6 @@
       gfx::PointF* transformed_point,
       bool* out_query_renderer);
 
-  virtual void InjectTouchEvent(const blink::WebTouchEvent& event,
-                                const ui::LatencyInfo& latency) {}
-
   virtual void PreProcessMouseEvent(const blink::WebMouseEvent& event) {}
   virtual void PreProcessTouchEvent(const blink::WebTouchEvent& event) {}
 
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
index 4264c56..5d42110 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -29,6 +29,8 @@
 #include "content/browser/renderer_host/cursor_manager.h"
 #include "content/browser/renderer_host/display_util.h"
 #include "content/browser/renderer_host/frame_connector_delegate.h"
+#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
+#include "content/browser/renderer_host/input/synthetic_gesture_target_base.h"
 #include "content/browser/renderer_host/input/touch_selection_controller_client_child_frame.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_delegate.h"
@@ -197,6 +199,13 @@
     frame_connector_->SendIntrinsicSizingInfoToParent(sizing_info);
 }
 
+std::unique_ptr<SyntheticGestureTarget>
+RenderWidgetHostViewChildFrame::CreateSyntheticGestureTarget() {
+  // TODO(mcnee): This should be NOTREACHED. Sythetic gestures should be sent
+  // to the root view. See https://crbug.com/923497
+  return std::make_unique<SyntheticGestureTargetBase>(host());
+}
+
 void RenderWidgetHostViewChildFrame::OnManagerWillDestroy(
     TouchSelectionControllerClientManager* manager) {
   // We get the manager via the observer callback instead of through the
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.h b/content/browser/renderer_host/render_widget_host_view_child_frame.h
index 30858b3..2e92b3e 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.h
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.h
@@ -168,6 +168,8 @@
   void OnRenderFrameMetadataChangedAfterActivation() override;
   void UpdateIntrinsicSizingInfo(
       const blink::WebIntrinsicSizingInfo& sizing_info) override;
+  std::unique_ptr<SyntheticGestureTarget> CreateSyntheticGestureTarget()
+      override;
 
   bool IsRenderWidgetHostViewChildFrame() override;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index 4c9994c..88a2360 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -200,7 +200,7 @@
 
   // Inject synthetic touch events.
   void InjectTouchEvent(const blink::WebTouchEvent& event,
-                        const ui::LatencyInfo& latency_info) override;
+                        const ui::LatencyInfo& latency_info);
 
   bool TransformPointToLocalCoordSpaceLegacy(
       const gfx::PointF& point,
@@ -463,6 +463,8 @@
   void MigrateNSViewBridge(NSViewBridgeFactoryHost* bridge_factory_host,
                            uint64_t parent_ns_view_id);
 
+  MouseWheelPhaseHandler* GetMouseWheelPhaseHandler() override;
+
  protected:
   // This class is to be deleted through the Destroy method.
   ~RenderWidgetHostViewMac() override;
@@ -479,8 +481,6 @@
   // collide with FrameSinkIds used by RenderWidgetHostImpls.
   static viz::FrameSinkId AllocateFrameSinkIdForGuestViewHack();
 
-  MouseWheelPhaseHandler* GetMouseWheelPhaseHandler() override;
-
   // Shuts down the render_widget_host_.  This is a separate function so we can
   // invoke it from the message loop.
   void ShutdownHost();
diff --git a/content/browser/service_worker/service_worker_url_request_job_unittest.cc b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
index 3cf47e1..10abbb5 100644
--- a/content/browser/service_worker/service_worker_url_request_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
@@ -379,8 +379,8 @@
         &url_request_delegate_, TRAFFIC_ANNOTATION_FOR_TESTS);
     ResourceRequestInfo::AllocateForTesting(
         request_.get(), resource_type, browser_context_->GetResourceContext(),
-        -1, -1, -1, resource_type == RESOURCE_TYPE_MAIN_FRAME, true, true,
-        PREVIEWS_OFF, nullptr);
+        -1, -1, -1, resource_type == RESOURCE_TYPE_MAIN_FRAME,
+        ResourceInterceptPolicy::kAllowAll, true, PREVIEWS_OFF, nullptr);
 
     request_->set_method("GET");
     request_->Start();
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index 30006c04..a321041 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -705,18 +705,11 @@
   ~SystemEventRewriter() override = default;
 
  private:
-  ui::EventRewriteStatus RewriteEvent(
+  ui::EventDispatchDetails RewriteEvent(
       const ui::Event& event,
-      std::unique_ptr<ui::Event>* new_event) override {
-    return num_of_scoped_allows_ ? ui::EVENT_REWRITE_CONTINUE
-                                 : ui::EVENT_REWRITE_DISCARD;
-  }
-
-  ui::EventRewriteStatus NextDispatchEvent(
-      const ui::Event& event,
-      std::unique_ptr<ui::Event>* new_event) override {
-    NOTREACHED();
-    return ui::EVENT_REWRITE_CONTINUE;
+      const Continuation continuation) override {
+    return num_of_scoped_allows_ ? SendEvent(continuation, &event)
+                                 : DiscardEvent(continuation);
   }
 
   // Count of ScopedAllow objects. When it is greater than 0, events are allowed
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 4c68f6e..613d5ff1 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -42,7 +42,6 @@
 #include "components/url_formatter/url_formatter.h"
 #include "content/browser/accessibility/accessibility_tree_formatter.h"
 #include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
-#include "content/browser/accessibility/browser_accessibility_state_impl.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/browser_plugin/browser_plugin_embedder.h"
@@ -589,7 +588,8 @@
       force_disable_overscroll_content_(false),
       last_dialog_suppressed_(false),
       accessibility_mode_(
-          BrowserAccessibilityStateImpl::GetInstance()->GetAccessibilityMode()),
+          GetContentClient()->browser()->GetAXModeForBrowserContext(
+              browser_context)),
       audio_stream_monitor_(this),
       bluetooth_connected_device_count_(0),
       media_device_group_id_salt_base_(
diff --git a/content/common/navigation_params.cc b/content/common/navigation_params.cc
index 33f9a63..8d13cbc 100644
--- a/content/common/navigation_params.cc
+++ b/content/common/navigation_params.cc
@@ -35,21 +35,27 @@
 
 InitiatorCSPInfo::~InitiatorCSPInfo() = default;
 
-bool IsNavigationDownloadAllowed(NavigationDownloadPolicy policy) {
+ResourceInterceptPolicy GetResourceInterceptPolicy(
+    NavigationDownloadPolicy policy) {
   switch (policy) {
     case NavigationDownloadPolicy::kDisallowViewSource:
     case NavigationDownloadPolicy::kDisallowInterstitial:
     case NavigationDownloadPolicy::kDisallowSandbox:
-      return false;
+      return ResourceInterceptPolicy::kAllowNone;
     case NavigationDownloadPolicy::kAllow:
     case NavigationDownloadPolicy::kAllowOpener:
     case NavigationDownloadPolicy::kAllowOpenerNoGesture:
     case NavigationDownloadPolicy::kAllowOpenerCrossOrigin:
     case NavigationDownloadPolicy::kAllowOpenerCrossOriginNoGesture:
-      return true;
+      return ResourceInterceptPolicy::kAllowAll;
   }
 }
 
+bool IsNavigationDownloadAllowed(NavigationDownloadPolicy policy) {
+  return GetResourceInterceptPolicy(policy) ==
+         ResourceInterceptPolicy::kAllowAll;
+}
+
 CommonNavigationParams::CommonNavigationParams() = default;
 
 CommonNavigationParams::CommonNavigationParams(
diff --git a/content/common/navigation_params.h b/content/common/navigation_params.h
index 7317f21..c2d76c9 100644
--- a/content/common/navigation_params.h
+++ b/content/common/navigation_params.h
@@ -22,6 +22,7 @@
 #include "content/public/common/page_state.h"
 #include "content/public/common/previews_state.h"
 #include "content/public/common/referrer.h"
+#include "content/public/common/resource_intercept_policy.h"
 #include "content/public/common/was_activated_option.h"
 #include "net/url_request/redirect_info.h"
 #include "services/network/public/cpp/resource_request_body.h"
@@ -113,9 +114,9 @@
   kMaxValue = kDisallowSandbox
 };
 
-// Returns whether the given |policy| should allow for a download. This function
-// should be removed when http://crbug.com/632514 is resolved, when callers will
-// just compare with kAllow.
+ResourceInterceptPolicy CONTENT_EXPORT
+GetResourceInterceptPolicy(NavigationDownloadPolicy policy);
+
 bool CONTENT_EXPORT
 IsNavigationDownloadAllowed(NavigationDownloadPolicy policy);
 
diff --git a/content/common/swapped_out_messages.cc b/content/common/swapped_out_messages.cc
index 85828fb..d03f0565 100644
--- a/content/common/swapped_out_messages.cc
+++ b/content/common/swapped_out_messages.cc
@@ -21,6 +21,7 @@
     case FrameHostMsg_RenderProcessGone::ID:
     case ViewHostMsg_ClosePage_ACK::ID:
     case ViewHostMsg_Focus::ID:
+    case ViewHostMsg_OpenDateTimeDialog::ID:
     case ViewHostMsg_ShowFullscreenWidget::ID:
     case ViewHostMsg_ShowWidget::ID:
     case ViewHostMsg_UpdateTargetURL::ID:
diff --git a/content/public/android/java/src/org/chromium/content/browser/MediaSessionImpl.java b/content/public/android/java/src/org/chromium/content/browser/MediaSessionImpl.java
index 6a9bc14..19647fd 100644
--- a/content/public/android/java/src/org/chromium/content/browser/MediaSessionImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/MediaSessionImpl.java
@@ -10,9 +10,12 @@
 import org.chromium.content_public.browser.MediaSession;
 import org.chromium.content_public.browser.MediaSessionObserver;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.services.media_session.MediaImage;
 import org.chromium.services.media_session.MediaMetadata;
 
+import java.util.Arrays;
 import java.util.HashSet;
+import java.util.List;
 
 /**
  * The MediaSessionImpl Java wrapper to allow communicating with the native MediaSessionImpl object.
@@ -116,6 +119,15 @@
     }
 
     @CalledByNative
+    private void mediaSessionArtworkChanged(MediaImage[] images) {
+        List<MediaImage> imagesList = Arrays.asList(images);
+
+        for (mObserversIterator.rewind(); mObserversIterator.hasNext();) {
+            mObserversIterator.next().mediaSessionArtworkChanged(imagesList);
+        }
+    }
+
+    @CalledByNative
     private static MediaSessionImpl create(long nativeMediaSession) {
         return new MediaSessionImpl(nativeMediaSession);
     }
diff --git a/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
index 700dcf1c..51442f62 100644
--- a/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
@@ -246,6 +246,12 @@
         nativeSetEntryExtraData(mNativeNavigationControllerAndroid, index, key, value);
     }
 
+    @Override
+    public boolean isEntryMarkedToBeSkipped(int index) {
+        if (mNativeNavigationControllerAndroid == 0) return false;
+        return nativeIsEntryMarkedToBeSkipped(mNativeNavigationControllerAndroid, index);
+    }
+
     @CalledByNative
     private static void addToNavigationHistory(Object history, Object navigationEntry) {
         ((NavigationHistory) history).addEntry((NavigationEntry) navigationEntry);
@@ -302,4 +308,6 @@
             long nativeNavigationControllerAndroid, int index, String key);
     private native void nativeSetEntryExtraData(
             long nativeNavigationControllerAndroid, int index, String key, String value);
+    private native boolean nativeIsEntryMarkedToBeSkipped(
+            long nativeNavigationControllerAndroid, int index);
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java
index 753477a9..174e4e3 100644
--- a/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java
@@ -1380,12 +1380,17 @@
         return mContext;
     }
 
+    @VisibleForTesting
     @CalledByNative
-    private void onSelectionChanged(String text) {
-        if (text.length() == 0 && hasSelection() && mSelectionMetricsLogger != null) {
-            mSelectionMetricsLogger.logSelectionAction(mLastSelectedText, mLastSelectionOffset,
-                    SmartSelectionMetricsLogger.ActionType.ABANDON,
-                    /* SelectionClient.Result = */ null);
+    /* package */ void onSelectionChanged(String text) {
+        final boolean unSelected = TextUtils.isEmpty(text) && hasSelection();
+        if (unSelected) {
+            if (mSelectionMetricsLogger != null) {
+                mSelectionMetricsLogger.logSelectionAction(mLastSelectedText, mLastSelectionOffset,
+                        SmartSelectionMetricsLogger.ActionType.ABANDON,
+                        /* SelectionClient.Result = */ null);
+            }
+            destroyActionModeAndKeepSelection();
         }
         mLastSelectedText = text;
         if (mSelectionClient != null) {
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/MediaSessionObserver.java b/content/public/android/java/src/org/chromium/content_public/browser/MediaSessionObserver.java
index 39af3803..e749a58 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/MediaSessionObserver.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/MediaSessionObserver.java
@@ -7,8 +7,10 @@
 import android.support.annotation.Nullable;
 
 import org.chromium.content.browser.MediaSessionImpl;
+import org.chromium.services.media_session.MediaImage;
 import org.chromium.services.media_session.MediaMetadata;
 
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -71,6 +73,12 @@
     public void mediaSessionActionsChanged(Set<Integer> actions) {}
 
     /**
+     * Called when the observed {@link MediaSession} artwork has changed.
+     * @param images The list of artwork images after the changed.
+     */
+    public void mediaSessionArtworkChanged(List<MediaImage> images) {}
+
+    /**
      * Stop observing the media session. Users must explicitly call this before dereferencing the
      * observer.
      */
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/NavigationController.java b/content/public/android/java/src/org/chromium/content_public/browser/NavigationController.java
index b81aad1..d45a4f6 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/NavigationController.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/NavigationController.java
@@ -179,4 +179,10 @@
      * @param value The data value.
      */
     void setEntryExtraData(int index, String key, String value);
+
+    /**
+     * @param index The index of the navigation entry.
+     * @return true if the entry at |index| is marked to be skipped on back/forward UI.
+     */
+    public boolean isEntryMarkedToBeSkipped(int index);
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentTextSelectionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentTextSelectionTest.java
index 1e4f382..2626d50f 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentTextSelectionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentTextSelectionTest.java
@@ -542,7 +542,7 @@
         Assert.assertTrue(mSelectionPopupController.isActionModeValid());
         selectActionBarCut();
         waitForSelectActionBarVisible(false);
-        Assert.assertFalse(mSelectionPopupController.hasSelection());
+        Assert.assertEquals(mSelectionPopupController.getSelectedText(), "");
         waitForClipboardContents("SampleInputText");
         Assert.assertEquals(mSelectionPopupController.getSelectedText(), "");
     }
@@ -575,7 +575,7 @@
         Assert.assertTrue(mSelectionPopupController.isActionModeValid());
         selectActionBarCut();
         waitForSelectActionBarVisible(false);
-        Assert.assertFalse(mSelectionPopupController.hasSelection());
+        Assert.assertEquals(mSelectionPopupController.getSelectedText(), "");
         waitForClipboardContents("SampleTextArea");
         Assert.assertEquals(mSelectionPopupController.getSelectedText(), "");
     }
@@ -700,7 +700,7 @@
         Assert.assertTrue(mSelectionPopupController.isActionModeValid());
         selectActionBarPaste();
         waitForSelectActionBarVisible(false);
-        Assert.assertFalse(mSelectionPopupController.hasSelection());
+        Assert.assertEquals(mSelectionPopupController.getSelectedText(), "");
 
         // Ensure the new text matches the pasted text.
         DOMUtils.longPressNode(mWebContents, "input_text");
@@ -727,7 +727,7 @@
         Assert.assertTrue(mSelectionPopupController.isActionModeValid());
         selectActionBarPaste();
         waitForSelectActionBarVisible(false);
-        Assert.assertFalse(mSelectionPopupController.hasSelection());
+        Assert.assertEquals(mSelectionPopupController.getSelectedText(), "");
 
         // Ensure the new text matches the pasted text. Note that we can't
         // actually compare strings as password field selections only provide
diff --git a/content/public/android/junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java b/content/public/android/junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java
index 11ce70c..fd57440 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java
@@ -580,6 +580,43 @@
         Mockito.verify(spyController, times(2)).performHapticFeedback();
     }
 
+    @Test
+    @Feature({"TextInput"})
+    public void testSelectionWhenUnselectAndFocusedNodeChanged() {
+        SelectionPopupControllerImpl spyController = Mockito.spy(mController);
+
+        when(mView.startActionMode(any(FloatingActionModeCallback.class), anyInt()))
+                .thenReturn(mActionMode);
+
+        // Long press triggered showSelectionMenu() call.
+        spyController.showSelectionMenu(0, 0, 0, 0, 0, /* isEditable = */ true,
+                /* isPasswordType = */ false, AMPHITHEATRE_FULL, /* selectionOffset = */ 0,
+                /* canSelectAll = */ true,
+                /* canRichlyEdit = */ true, /* shouldSuggest = */ true,
+                MenuSourceType.MENU_SOURCE_LONG_PRESS);
+
+        Mockito.verify(mView).startActionMode(
+                isA(FloatingActionModeCallback.class), eq(ActionMode.TYPE_FLOATING));
+        // showSelectionMenu() will invoke the first call to finishActionMode() in the
+        // showActionModeOrClearOnFailure().
+        Mockito.verify(spyController, times(1)).finishActionMode();
+        assertTrue(spyController.isSelectActionBarShowing());
+
+        // Clear the selected text.
+        spyController.onSelectionChanged("");
+        // Changed the focused node attribute to non-editable and non-password.
+        spyController.updateSelectionState(false, false);
+
+        // finishActionMode will be called twice for unselect.
+        Mockito.verify(spyController, times(2)).finishActionMode();
+
+        // SELECTION_HANDLES_CLEARED happens.
+        spyController.onSelectionEvent(SelectionEventType.SELECTION_HANDLES_CLEARED, 0, 0, 0, 0);
+
+        assertFalse(spyController.isSelectActionBarShowing());
+        Mockito.verify(spyController, times(3)).finishActionMode();
+    }
+
     // Result generated by long press "Amphitheatre" in "1600 Amphitheatre Parkway".
     private SelectionClient.Result resultForAmphitheatre() {
         SelectionClient.Result result = new SelectionClient.Result();
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index ff27bb1..2fff2ecd 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -13,6 +13,7 @@
 #include "base/no_destructor.h"
 #include "build/build_config.h"
 #include "content/public/browser/authenticator_request_client_delegate.h"
+#include "content/public/browser/browser_accessibility_state.h"
 #include "content/public/browser/client_certificate_delegate.h"
 #include "content/public/browser/login_delegate.h"
 #include "content/public/browser/navigation_ui_data.h"
@@ -945,4 +946,9 @@
   return false;
 }
 
+ui::AXMode ContentBrowserClient::GetAXModeForBrowserContext(
+    BrowserContext* browser_context) {
+  return BrowserAccessibilityState::GetInstance()->GetAccessibilityMode();
+}
+
 }  // namespace content
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 1b49a64..a013031 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -56,6 +56,7 @@
 #include "third_party/blink/public/mojom/renderer_preference_watcher.mojom-forward.h"
 #include "third_party/blink/public/platform/web_feature.mojom-forward.h"
 #include "third_party/blink/public/web/window_features.mojom-forward.h"
+#include "ui/accessibility/ax_mode.h"
 #include "ui/base/page_transition_types.h"
 #include "ui/base/window_open_disposition.h"
 
@@ -1476,6 +1477,10 @@
   // blacklist policies are applied there.
   virtual bool IsRendererDebugURLBlacklisted(const GURL& url,
                                              BrowserContext* context);
+
+  // Returns the default accessibility mode for the given browser context.
+  virtual ui::AXMode GetAXModeForBrowserContext(
+      BrowserContext* browser_context);
 };
 
 }  // namespace content
diff --git a/content/public/browser/devtools_agent_host_client.cc b/content/public/browser/devtools_agent_host_client.cc
index 9fba2f5e..6c4a715 100644
--- a/content/public/browser/devtools_agent_host_client.cc
+++ b/content/public/browser/devtools_agent_host_client.cc
@@ -20,4 +20,8 @@
   return true;
 }
 
+bool DevToolsAgentHostClient::UsesBinaryProtocol() {
+  return false;
+}
+
 }  // namespace content
diff --git a/content/public/browser/devtools_agent_host_client.h b/content/public/browser/devtools_agent_host_client.h
index bda18aa8..a3e7dec 100644
--- a/content/public/browser/devtools_agent_host_client.h
+++ b/content/public/browser/devtools_agent_host_client.h
@@ -40,6 +40,9 @@
   // Returns true if the client is allowed to affect local files over the
   // protocol. Example would be manipulating a deault downloads path.
   virtual bool MayAffectLocalFiles();
+
+  // Determines protocol message format.
+  virtual bool UsesBinaryProtocol();
 };
 
 }  // namespace content
diff --git a/content/public/browser/overlay_window.h b/content/public/browser/overlay_window.h
index 2c33071..64eadcaf 100644
--- a/content/public/browser/overlay_window.h
+++ b/content/public/browser/overlay_window.h
@@ -60,6 +60,7 @@
       const std::vector<blink::PictureInPictureControlInfo>& controls) = 0;
   virtual void SetAlwaysHidePlayPauseButton(bool is_visible) = 0;
   virtual void SetSkipAdButtonVisibility(bool is_visible) = 0;
+  virtual void SetNextTrackButtonVisibility(bool is_visible) = 0;
 
   // Retrieves the ui::Layers corresponding to the window and video.
   virtual ui::Layer* GetWindowBackgroundLayer() = 0;
diff --git a/content/public/browser/picture_in_picture_window_controller.h b/content/public/browser/picture_in_picture_window_controller.h
index 979086f7..bd1595e 100644
--- a/content/public/browser/picture_in_picture_window_controller.h
+++ b/content/public/browser/picture_in_picture_window_controller.h
@@ -70,6 +70,9 @@
   // Called when the user interacts with the "Skip Ad" control.
   virtual void SkipAd() = 0;
 
+  // Called when the user interacts with the "Next Track" control.
+  virtual void NextTrack() = 0;
+
   // Commands.
   // Returns true if the player is active (i.e. currently playing) after this
   // call.
diff --git a/content/public/browser/resource_request_info.h b/content/public/browser/resource_request_info.h
index 1a052fa8..7402264 100644
--- a/content/public/browser/resource_request_info.h
+++ b/content/public/browser/resource_request_info.h
@@ -11,6 +11,7 @@
 #include "content/public/browser/global_request_id.h"
 #include "content/public/browser/navigation_ui_data.h"
 #include "content/public/common/previews_state.h"
+#include "content/public/common/resource_intercept_policy.h"
 #include "content/public/common/resource_type.h"
 #include "services/network/public/mojom/referrer_policy.mojom-forward.h"
 #include "third_party/blink/public/platform/resource_request_blocked_reason.h"
@@ -51,7 +52,7 @@
       int render_view_id,
       int render_frame_id,
       bool is_main_frame,
-      bool allow_download,
+      ResourceInterceptPolicy resource_intercept_policy,
       bool is_async,
       PreviewsState previews_state,
       std::unique_ptr<NavigationUIData> navigation_ui_data);
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn
index 550eb1f7..1e89170e 100644
--- a/content/public/common/BUILD.gn
+++ b/content/public/common/BUILD.gn
@@ -186,6 +186,7 @@
     "referrer_type_converters.h",
     "renderer_preferences_util.cc",
     "renderer_preferences_util.h",
+    "resource_intercept_policy.h",
     "resource_request_body_android.cc",
     "resource_request_body_android.h",
     "resource_type.cc",
diff --git a/content/public/common/resource_intercept_policy.h b/content/public/common/resource_intercept_policy.h
new file mode 100644
index 0000000..6f5af52
--- /dev/null
+++ b/content/public/common/resource_intercept_policy.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 CONTENT_PUBLIC_COMMON_RESOURCE_INTERCEPT_POLICY_H_
+#define CONTENT_PUBLIC_COMMON_RESOURCE_INTERCEPT_POLICY_H_
+
+namespace content {
+
+// The ResourceInterceptPolicy enum controls whether a resource request is
+// allowed to be handled by plugin (intercept as a stream) or to turn into a
+// download (intercept as a download).
+//
+// Note: For a restriction that only intends to prevent download, if it's also
+// guaranteed that the resource won't be handled by plugin (e.g. in sandboxed
+// iframe), then it's safe and also recommended to choose the more restricted
+// policy |kAllowNone|.
+enum class ResourceInterceptPolicy {
+  // Allow all type of interceptions.
+  kAllowAll = 0,
+
+  // Disallow any type of interceptions.
+  //
+  // TODO(crbug/930951): the current implementation doesn't completely honor
+  // this description. When the resource type is |RESOURCE_TYPE_OBJECT|, mime
+  // sniffing would still check the existence of plugins and may intercept it as
+  // a stream.
+  kAllowNone = 1,
+
+  // Only allow intercepting as stream.
+  kAllowPluginOnly = 2,
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_COMMON_RESOURCE_INTERCEPT_POLICY_H_
diff --git a/content/renderer/android/renderer_date_time_picker.cc b/content/renderer/android/renderer_date_time_picker.cc
index 52092de08..d5371437 100644
--- a/content/renderer/android/renderer_date_time_picker.cc
+++ b/content/renderer/android/renderer_date_time_picker.cc
@@ -83,8 +83,7 @@
     message.suggestions.push_back(
         ToDateTimeSuggestion(chooser_params_.suggestions[i]));
   }
-  Send(new ViewHostMsg_OpenDateTimeDialog(routing_id(), message));
-  return true;
+  return Send(new ViewHostMsg_OpenDateTimeDialog(routing_id(), message));
 }
 
 bool RendererDateTimePicker::OnMessageReceived(
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
index 5369328..8d756195 100644
--- a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
@@ -9,6 +9,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <set>
 #include <string>
 #include <utility>
 #include <vector>
@@ -120,9 +121,9 @@
   event->Signal();
 }
 
-void RunSynchronousClosure(const base::Closure& closure,
-                           const char* trace_event_name,
-                           base::WaitableEvent* event) {
+void RunSynchronousRepeatingClosure(const base::RepeatingClosure& closure,
+                                    const char* trace_event_name,
+                                    base::WaitableEvent* event) {
   {
     TRACE_EVENT0("webrtc", trace_event_name);
     closure.Run();
@@ -392,7 +393,7 @@
       StatsReport::Values::const_iterator end_;
     };
 
-    Report(const StatsReport* report)
+    explicit Report(const StatsReport* report)
         : id_(report->id()->ToString()),
           type_(report->type()),
           type_name_(report->TypeToString()),
@@ -1099,7 +1100,7 @@
 
   TransceiverStateSurfacer transceiver_state_surfacer(task_runner_,
                                                       signaling_thread());
-  RunSynchronousClosureOnSignalingThread(
+  RunSynchronousRepeatingClosureOnSignalingThread(
       base::BindRepeating(
           &RTCPeerConnectionHandler::CreateOfferOnSignalingThread,
           base::Unretained(this), base::Unretained(description_request.get()),
@@ -1559,7 +1560,7 @@
                                                       signaling_thread());
   webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>>
       error_or_transceiver;
-  RunSynchronousClosureOnSignalingThread(
+  RunSynchronousRepeatingClosureOnSignalingThread(
       base::BindRepeating(
           &RTCPeerConnectionHandler::AddTransceiverWithTrackOnSignalingThread,
           base::Unretained(this), base::RetainedRef(track_ref->webrtc_track()),
@@ -1611,7 +1612,7 @@
                                                       signaling_thread());
   webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpTransceiverInterface>>
       error_or_transceiver;
-  RunSynchronousClosureOnSignalingThread(
+  RunSynchronousRepeatingClosureOnSignalingThread(
       base::BindRepeating(&RTCPeerConnectionHandler::
                               AddTransceiverWithMediaTypeOnSignalingThread,
                           base::Unretained(this), base::ConstRef(media_type),
@@ -1668,7 +1669,7 @@
                                                       signaling_thread());
   webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpSenderInterface>>
       error_or_sender;
-  RunSynchronousClosureOnSignalingThread(
+  RunSynchronousRepeatingClosureOnSignalingThread(
       base::BindRepeating(
           &RTCPeerConnectionHandler::AddTrackOnSignalingThread,
           base::Unretained(this), base::RetainedRef(track_ref->webrtc_track()),
@@ -1819,7 +1820,7 @@
   TransceiverStateSurfacer transceiver_state_surfacer(task_runner_,
                                                       signaling_thread());
   bool result;
-  RunSynchronousClosureOnSignalingThread(
+  RunSynchronousRepeatingClosureOnSignalingThread(
       base::BindRepeating(
           &RTCPeerConnectionHandler::RemoveTrackUnifiedPlanOnSignalingThread,
           base::Unretained(this), base::RetainedRef(webrtc_sender),
@@ -1963,6 +1964,45 @@
   return native_peer_connection();
 }
 
+void RTCPeerConnectionHandler::RunSynchronousOnceClosureOnSignalingThread(
+    base::OnceClosure closure,
+    const char* trace_event_name) {
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  scoped_refptr<base::SingleThreadTaskRunner> thread(signaling_thread());
+  if (!thread.get() || thread->BelongsToCurrentThread()) {
+    TRACE_EVENT0("webrtc", trace_event_name);
+    std::move(closure).Run();
+  } else {
+    base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+                              base::WaitableEvent::InitialState::NOT_SIGNALED);
+    thread->PostTask(
+        FROM_HERE,
+        base::BindOnce(&RunSynchronousOnceClosure, std::move(closure),
+                       base::Unretained(trace_event_name),
+                       base::Unretained(&event)));
+    event.Wait();
+  }
+}
+
+void RTCPeerConnectionHandler::RunSynchronousRepeatingClosureOnSignalingThread(
+    const base::RepeatingClosure& closure,
+    const char* trace_event_name) {
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  scoped_refptr<base::SingleThreadTaskRunner> thread(signaling_thread());
+  if (!thread.get() || thread->BelongsToCurrentThread()) {
+    TRACE_EVENT0("webrtc", trace_event_name);
+    closure.Run();
+  } else {
+    base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+                              base::WaitableEvent::InitialState::NOT_SIGNALED);
+    thread->PostTask(FROM_HERE,
+                     base::BindOnce(&RunSynchronousRepeatingClosure, closure,
+                                    base::Unretained(trace_event_name),
+                                    base::Unretained(&event)));
+    event.Wait();
+  }
+}
+
 void RTCPeerConnectionHandler::OnSignalingChange(
     webrtc::PeerConnectionInterface::SignalingState new_state) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
@@ -2364,46 +2404,6 @@
   return dependency_factory_->GetWebRtcSignalingThread();
 }
 
-void RTCPeerConnectionHandler::RunSynchronousOnceClosureOnSignalingThread(
-    base::OnceClosure closure,
-    const char* trace_event_name) {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  scoped_refptr<base::SingleThreadTaskRunner> thread(signaling_thread());
-  if (!thread.get() || thread->BelongsToCurrentThread()) {
-    TRACE_EVENT0("webrtc", trace_event_name);
-    std::move(closure).Run();
-  } else {
-    base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
-                              base::WaitableEvent::InitialState::NOT_SIGNALED);
-    thread->PostTask(
-        FROM_HERE,
-        base::BindOnce(&RunSynchronousOnceClosure, std::move(closure),
-                       base::Unretained(trace_event_name),
-                       base::Unretained(&event)));
-    event.Wait();
-  }
-}
-
-// Deprecated version - uses a RepeatingCosure (aka old-style Closure)
-void RTCPeerConnectionHandler::RunSynchronousClosureOnSignalingThread(
-    const base::RepeatingClosure& closure,
-    const char* trace_event_name) {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  scoped_refptr<base::SingleThreadTaskRunner> thread(signaling_thread());
-  if (!thread.get() || thread->BelongsToCurrentThread()) {
-    TRACE_EVENT0("webrtc", trace_event_name);
-    closure.Run();
-  } else {
-    base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
-                              base::WaitableEvent::InitialState::NOT_SIGNALED);
-    thread->PostTask(FROM_HERE,
-                     base::BindOnce(&RunSynchronousClosure, closure,
-                                    base::Unretained(trace_event_name),
-                                    base::Unretained(&event)));
-    event.Wait();
-  }
-}
-
 blink::WebRTCSessionDescription
 RTCPeerConnectionHandler::GetWebRTCSessionDescriptionOnSignalingThread(
     base::OnceCallback<const webrtc::SessionDescriptionInterface*()>
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.h b/content/renderer/media/webrtc/rtc_peer_connection_handler.h
index 608e0d7..a30be92 100644
--- a/content/renderer/media/webrtc/rtc_peer_connection_handler.h
+++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.h
@@ -172,6 +172,12 @@
   void Stop() override;
   blink::WebString Id() const override;
   webrtc::PeerConnectionInterface* NativePeerConnection() override;
+  void RunSynchronousOnceClosureOnSignalingThread(
+      base::OnceClosure closure,
+      const char* trace_event_name) override;
+  void RunSynchronousRepeatingClosureOnSignalingThread(
+      const base::RepeatingClosure& closure,
+      const char* trace_event_name) override;
 
   // Delegate functions to allow for mocking of WebKit interfaces.
   // getStats takes ownership of request parameter.
@@ -234,7 +240,8 @@
   // Record info about the first SessionDescription from the local and
   // remote side to record UMA stats once both are set.
   struct FirstSessionDescription {
-    FirstSessionDescription(const webrtc::SessionDescriptionInterface* desc);
+    explicit FirstSessionDescription(
+        const webrtc::SessionDescriptionInterface* desc);
 
     bool audio = false;
     bool video = false;
@@ -316,11 +323,6 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> signaling_thread() const;
 
-  void RunSynchronousClosureOnSignalingThread(const base::Closure& closure,
-                                              const char* trace_event_name);
-  void RunSynchronousOnceClosureOnSignalingThread(base::OnceClosure closure,
-                                                  const char* trace_event_name);
-
   // Corresponds to the experimental RTCPeerConnection.id read-only attribute.
   const std::string id_;
 
diff --git a/content/renderer/media/webrtc/rtc_video_encoder_unittest.cc b/content/renderer/media/webrtc/rtc_video_encoder_unittest.cc
index 5273c6d..e91672d 100644
--- a/content/renderer/media/webrtc/rtc_video_encoder_unittest.cc
+++ b/content/renderer/media/webrtc/rtc_video_encoder_unittest.cc
@@ -53,7 +53,7 @@
       const webrtc::RTPFragmentationHeader* fragmentation) override {
     encoded_callback_.Run(encoded_image, codec_specific_info, fragmentation);
     return Result(Result::OK);
-  };
+  }
 
  private:
   EncodedCallback encoded_callback_;
diff --git a/content/shell/browser/web_test/web_test_content_browser_client.cc b/content/shell/browser/web_test/web_test_content_browser_client.cc
index fa9a354..2c52e0e4 100644
--- a/content/shell/browser/web_test/web_test_content_browser_client.cc
+++ b/content/shell/browser/web_test/web_test_content_browser_client.cc
@@ -78,6 +78,7 @@
   void SetPlaybackState(PlaybackState playback_state) override {}
   void SetAlwaysHidePlayPauseButton(bool is_visible) override {}
   void SetSkipAdButtonVisibility(bool is_visible) override {}
+  void SetNextTrackButtonVisibility(bool is_visible) override {}
   ui::Layer* GetWindowBackgroundLayer() override { return nullptr; }
   ui::Layer* GetVideoLayer() override { return nullptr; }
   gfx::Rect GetVideoBounds() override { return gfx::Rect(); }
diff --git a/content/shell/test_runner/event_sender.cc b/content/shell/test_runner/event_sender.cc
index 00490b1..b38e956 100644
--- a/content/shell/test_runner/event_sender.cc
+++ b/content/shell/test_runner/event_sender.cc
@@ -6,6 +6,8 @@
 
 #include <stddef.h>
 
+#include <algorithm>
+#include <limits>
 #include <memory>
 
 #include "base/bind.h"
@@ -619,6 +621,8 @@
   void LeapForward(int milliseconds);
   double LastEventTimestamp();
   void BeginDragWithFiles(const std::vector<std::string>& files);
+  void BeginDragWithStringData(const std::string& data,
+                               const std::string& mime_type);
   void AddTouchPoint(double x, double y, gin::Arguments* args);
   void GestureScrollBegin(gin::Arguments* args);
   void GestureScrollEnd(gin::Arguments* args);
@@ -742,6 +746,8 @@
       .SetMethod("leapForward", &EventSenderBindings::LeapForward)
       .SetMethod("lastEventTimestamp", &EventSenderBindings::LastEventTimestamp)
       .SetMethod("beginDragWithFiles", &EventSenderBindings::BeginDragWithFiles)
+      .SetMethod("beginDragWithStringData",
+                 &EventSenderBindings::BeginDragWithStringData)
       .SetMethod("addTouchPoint", &EventSenderBindings::AddTouchPoint)
       .SetMethod("gestureScrollBegin", &EventSenderBindings::GestureScrollBegin)
       .SetMethod("gestureScrollEnd", &EventSenderBindings::GestureScrollEnd)
@@ -950,6 +956,13 @@
     sender_->BeginDragWithFiles(files);
 }
 
+void EventSenderBindings::BeginDragWithStringData(
+    const std::string& data,
+    const std::string& mime_type) {
+  if (sender_)
+    sender_->BeginDragWithStringData(data, mime_type);
+}
+
 void EventSenderBindings::AddTouchPoint(double x,
                                         double y,
                                         gin::Arguments* args) {
@@ -2035,27 +2048,30 @@
   }
 }
 
-void EventSender::BeginDragWithFiles(const std::vector<std::string>& files) {
+void EventSender::BeginDragWithItems(
+    const WebVector<WebDragData::Item>& items) {
   if (!current_drag_data_.IsNull()) {
     // Nested dragging not supported, fuzzer code a likely culprit.
     // Cancel the current drag operation and throw an error.
     KeyDown("Escape", 0, DOMKeyLocationStandard);
     v8::Isolate* isolate = blink::MainThreadIsolate();
     isolate->ThrowException(v8::Exception::Error(gin::StringToV8(
-        isolate, "Nested beginDragWithFiles() not supported.")));
+        isolate,
+        "Nested beginDragWithFiles/beginDragWithStringData() not supported.")));
     return;
   }
+
   current_drag_data_.Initialize();
-  WebVector<WebString> absolute_filenames(files.size());
-  for (size_t i = 0; i < files.size(); ++i) {
-    WebDragData::Item item;
-    item.storage_type = WebDragData::Item::kStorageTypeFilename;
-    item.filename_data = delegate()->GetAbsoluteWebStringFromUTF8Path(files[i]);
-    current_drag_data_.AddItem(item);
-    absolute_filenames[i] = item.filename_data;
+  WebVector<WebString> absolute_filenames;
+  for (size_t i = 0; i < items.size(); ++i) {
+    current_drag_data_.AddItem(items[i]);
+    if (items[i].storage_type == WebDragData::Item::kStorageTypeFilename)
+      absolute_filenames.emplace_back(items[i].filename_data);
   }
-  current_drag_data_.SetFilesystemId(
-      delegate()->RegisterIsolatedFileSystem(absolute_filenames));
+  if (!absolute_filenames.empty()) {
+    current_drag_data_.SetFilesystemId(
+        delegate()->RegisterIsolatedFileSystem(absolute_filenames));
+  }
   current_drag_effects_allowed_ = blink::kWebDragOperationCopy;
 
   const WebPoint& last_pos =
@@ -2079,6 +2095,30 @@
           current_pointer_state_[kRawMousePointerId].pressed_button_);
 }
 
+void EventSender::BeginDragWithFiles(const std::vector<std::string>& files) {
+  WebVector<WebDragData::Item> items;
+  for (size_t i = 0; i < files.size(); ++i) {
+    WebDragData::Item item;
+    item.storage_type = WebDragData::Item::kStorageTypeFilename;
+    item.filename_data = delegate()->GetAbsoluteWebStringFromUTF8Path(files[i]);
+    items.emplace_back(item);
+  }
+
+  BeginDragWithItems(items);
+}
+
+void EventSender::BeginDragWithStringData(const std::string& data,
+                                          const std::string& mime_type) {
+  WebVector<WebDragData::Item> items;
+  WebDragData::Item item;
+  item.storage_type = WebDragData::Item::kStorageTypeString;
+  item.string_data = WebString::FromUTF8(data);
+  item.string_type = WebString::FromUTF8(mime_type);
+  items.emplace_back(item);
+
+  BeginDragWithItems(items);
+}
+
 void EventSender::AddTouchPoint(float x, float y, gin::Arguments* args) {
   if (touch_points_.size() == WebTouchEvent::kTouchesLengthCap) {
     args->ThrowError();
diff --git a/content/shell/test_runner/event_sender.h b/content/shell/test_runner/event_sender.h
index 56a8923..800a89ca 100644
--- a/content/shell/test_runner/event_sender.h
+++ b/content/shell/test_runner/event_sender.h
@@ -148,7 +148,11 @@
 
   void LeapForward(int milliseconds);
 
+  void BeginDragWithItems(
+      const blink::WebVector<blink::WebDragData::Item>& items);
   void BeginDragWithFiles(const std::vector<std::string>& files);
+  void BeginDragWithStringData(const std::string& data,
+                               const std::string& mime_type);
 
   void AddTouchPoint(float x, float y, gin::Arguments* args);
 
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index e1457f4..1dcf2482 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -908,8 +908,7 @@
         ['linux', 'no_passthrough', 'nvidia'], bug=832238)
 
     # Linux NVIDIA Quadro P400
-    self.Skip('conformance2/rendering/blitframebuffer-size-overflow.html',
-        ['linux', ('nvidia', 0x1cb3)], bug=830046)
+
     # Observed flaky on Swarmed bots. Some of these were directly
     # observed, some not. We can't afford any flakes on the tryservers
     # so mark them all flaky.
@@ -1357,8 +1356,6 @@
         ['android', 'nvidia'], bug=874620)
     self.Fail('conformance2/glsl3/vector-dynamic-indexing-nv-driver-bug.html',
         ['android', 'nvidia'], bug=905006)
-    self.Fail('conformance2/rendering/blitframebuffer-size-overflow.html',
-        ['android', 'nvidia'], bug=830046)
 
     # Conflicting expectations to test that the
     # "Expectations have no collisions" unittest works.
diff --git a/content/test/test_render_view_host.cc b/content/test/test_render_view_host.cc
index 9f7187b..ae30b63 100644
--- a/content/test/test_render_view_host.cc
+++ b/content/test/test_render_view_host.cc
@@ -15,6 +15,7 @@
 #include "content/browser/dom_storage/dom_storage_context_wrapper.h"
 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/common/dom_storage/dom_storage_types.h"
@@ -220,6 +221,12 @@
   OnFrameTokenChangedForView(frame_token);
 }
 
+std::unique_ptr<SyntheticGestureTarget>
+TestRenderWidgetHostView::CreateSyntheticGestureTarget() {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
 void TestRenderWidgetHostView::UpdateBackgroundColor() {}
 
 TestRenderViewHost::TestRenderViewHost(
diff --git a/content/test/test_render_view_host.h b/content/test/test_render_view_host.h
index e47b2a3..0eb84db 100644
--- a/content/test/test_render_view_host.h
+++ b/content/test/test_render_view_host.h
@@ -123,6 +123,8 @@
   const viz::LocalSurfaceIdAllocation& GetLocalSurfaceIdAllocation()
       const override;
   viz::SurfaceId GetCurrentSurfaceId() const override;
+  std::unique_ptr<SyntheticGestureTarget> CreateSyntheticGestureTarget()
+      override;
 
   bool is_showing() const { return is_showing_; }
   bool is_occluded() const { return is_occluded_; }
diff --git a/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc
index d907ff23..2352201 100644
--- a/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc
+++ b/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc
@@ -170,7 +170,7 @@
     properties2->connected.ReplaceValue(true);
 
     return adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kDualAddress);
-  };
+  }
 
   void BatteryServiceShouldBeComplete(BluetoothDevice* device) {
     ASSERT_TRUE(device);
diff --git a/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc b/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
index 2a7d79e..742ad02 100644
--- a/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
+++ b/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
@@ -114,7 +114,7 @@
       -1,     // render_view_id
       -1,     // render_frame_id
       false,  // is_main_frame
-      true,   // allow_download
+      content::ResourceInterceptPolicy::kAllowAll,
       false,  // is_async
       content::PREVIEWS_OFF,
       nullptr);  // navigation_ui_data
@@ -127,12 +127,12 @@
       TRAFFIC_ANNOTATION_FOR_TESTS));
   content::ResourceRequestInfo::AllocateForTesting(
       url_request_fail.get(), content::RESOURCE_TYPE_MAIN_FRAME,
-      NULL,   // context
-      -1,     // render_process_id
-      -1,     // render_view_id
-      -1,     // render_frame_id
-      true,   // is_main_frame
-      true,   // allow_download
+      NULL,  // context
+      -1,    // render_process_id
+      -1,    // render_view_id
+      -1,    // render_frame_id
+      true,  // is_main_frame
+      content::ResourceInterceptPolicy::kAllowAll,
       false,  // is_async
       content::PREVIEWS_OFF,
       nullptr);  // navigation_ui_data
diff --git a/extensions/browser/api/declarative_webrequest/webrequest_condition_unittest.cc b/extensions/browser/api/declarative_webrequest/webrequest_condition_unittest.cc
index 1fef163c..193f15d 100644
--- a/extensions/browser/api/declarative_webrequest/webrequest_condition_unittest.cc
+++ b/extensions/browser/api/declarative_webrequest/webrequest_condition_unittest.cc
@@ -86,12 +86,12 @@
       http_url, net::DEFAULT_PRIORITY, nullptr, TRAFFIC_ANNOTATION_FOR_TESTS));
   content::ResourceRequestInfo::AllocateForTesting(
       match_request.get(), content::RESOURCE_TYPE_MAIN_FRAME,
-      NULL,   // context
-      -1,     // render_process_id
-      -1,     // render_view_id
-      -1,     // render_frame_id
-      true,   // is_main_frame
-      true,   // allow_download
+      NULL,  // context
+      -1,    // render_process_id
+      -1,    // render_view_id
+      -1,    // render_frame_id
+      true,  // is_main_frame
+      content::ResourceInterceptPolicy::kAllowAll,
       false,  // is_async
       content::PREVIEWS_OFF,
       nullptr);  // navigation_ui_data
@@ -112,7 +112,7 @@
       -1,     // render_view_id
       -1,     // render_frame_id
       false,  // is_main_frame
-      true,   // allow_download
+      content::ResourceInterceptPolicy::kAllowAll,
       false,  // is_async
       content::PREVIEWS_OFF,
       nullptr);  // navigation_ui_data
@@ -162,12 +162,12 @@
   EXPECT_EQ(1u, request_data.first_party_url_match_ids.size());
   content::ResourceRequestInfo::AllocateForTesting(
       match_request.get(), content::RESOURCE_TYPE_MAIN_FRAME,
-      NULL,   // context
-      -1,     // render_process_id
-      -1,     // render_view_id
-      -1,     // render_frame_id
-      true,   // is_main_frame
-      true,   // allow_download
+      NULL,  // context
+      -1,    // render_process_id
+      -1,    // render_view_id
+      -1,    // render_frame_id
+      true,  // is_main_frame
+      content::ResourceInterceptPolicy::kAllowAll,
       false,  // is_async
       content::PREVIEWS_OFF,
       nullptr);  // navigation_ui_data
diff --git a/extensions/browser/content_verifier_unittest.cc b/extensions/browser/content_verifier_unittest.cc
index b1c2849..7067f27 100644
--- a/extensions/browser/content_verifier_unittest.cc
+++ b/extensions/browser/content_verifier_unittest.cc
@@ -208,7 +208,7 @@
   }
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     All,
     ContentVerifierTest,
     testing::Values(BackgroundManifestType::kNone,
diff --git a/extensions/browser/content_verify_job_unittest.cc b/extensions/browser/content_verify_job_unittest.cc
index 2162fda..8b10d8f 100644
--- a/extensions/browser/content_verify_job_unittest.cc
+++ b/extensions/browser/content_verify_job_unittest.cc
@@ -365,11 +365,11 @@
   DISALLOW_COPY_AND_ASSIGN(ContentMismatchUnittest);
 };
 
-INSTANTIATE_TEST_CASE_P(ContentVerifyJobUnittest,
-                        ContentMismatchUnittest,
-                        testing::Values(kNone,
-                                        kContentReadBeforeHashesReady,
-                                        kHashesReadyBeforeContentRead));
+INSTANTIATE_TEST_SUITE_P(ContentVerifyJobUnittest,
+                         ContentMismatchUnittest,
+                         testing::Values(kNone,
+                                         kContentReadBeforeHashesReady,
+                                         kHashesReadyBeforeContentRead));
 
 // Tests that content modification causes content verification failure.
 TEST_P(ContentMismatchUnittest, ContentMismatch) {
diff --git a/extensions/browser/extension_pref_value_map_unittest.cc b/extensions/browser/extension_pref_value_map_unittest.cc
index ad9b31ab..0f4cd7a 100644
--- a/extensions/browser/extension_pref_value_map_unittest.cc
+++ b/extensions/browser/extension_pref_value_map_unittest.cc
@@ -400,7 +400,7 @@
   epvm_.UnregisterExtension(kExt2);
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     ExtensionPrefValueMapTestIncognitoTestsInstance,
     ExtensionPrefValueMapTestIncognitoTests,
     testing::Values(
@@ -409,37 +409,36 @@
         // "val7"
         // --> the winning regular value is "val1", the winning incognito
         //     value is "val7".
-        OverrideIncognitoTestCase(true, true, 1, 0, 0, 0,  0, 0, 0, 0,  1, 1),
-        OverrideIncognitoTestCase(true, true, 1, 2, 0, 0,  0, 0, 0, 0,  2, 1),
-        OverrideIncognitoTestCase(true, true, 1, 0, 3, 0,  0, 0, 0, 0,  1, 3),
-        OverrideIncognitoTestCase(true, true, 1, 0, 0, 4,  0, 0, 0, 0,  1, 4),
-        OverrideIncognitoTestCase(true, true, 1, 0, 3, 4,  0, 0, 0, 0,  1, 4),
-        OverrideIncognitoTestCase(true, true, 1, 2, 3, 0,  0, 0, 0, 0,  2, 3),
-        OverrideIncognitoTestCase(true, true, 1, 0, 0, 0,  5, 0, 0, 0,  5, 5),
-        OverrideIncognitoTestCase(true, true, 1, 2, 3, 0,  5, 0, 0, 0,  5, 5),
-        OverrideIncognitoTestCase(true, true, 1, 0, 0, 0,  0, 6, 0, 0,  6, 1),
-        OverrideIncognitoTestCase(true, true, 1, 0, 3, 0,  5, 6, 0, 0,  6, 5),
-        OverrideIncognitoTestCase(true, true, 1, 0, 0, 4,  5, 6, 0, 0,  6, 5),
-        OverrideIncognitoTestCase(true, true, 1, 0, 0, 0,  0, 0, 7, 0,  1, 7),
-        OverrideIncognitoTestCase(true, true, 1, 2, 0, 0,  5, 0, 7, 0,  5, 7),
-        OverrideIncognitoTestCase(true, true, 1, 2, 0, 0,  5, 0, 0, 8,  5, 8),
-        OverrideIncognitoTestCase(true, true, 1, 2, 0, 0,  5, 0, 7, 8,  5, 8),
-        OverrideIncognitoTestCase(true, true, 1, 2, 3, 0,  0, 6, 7, 0,  6, 7),
+        OverrideIncognitoTestCase(true, true, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1),
+        OverrideIncognitoTestCase(true, true, 1, 2, 0, 0, 0, 0, 0, 0, 2, 1),
+        OverrideIncognitoTestCase(true, true, 1, 0, 3, 0, 0, 0, 0, 0, 1, 3),
+        OverrideIncognitoTestCase(true, true, 1, 0, 0, 4, 0, 0, 0, 0, 1, 4),
+        OverrideIncognitoTestCase(true, true, 1, 0, 3, 4, 0, 0, 0, 0, 1, 4),
+        OverrideIncognitoTestCase(true, true, 1, 2, 3, 0, 0, 0, 0, 0, 2, 3),
+        OverrideIncognitoTestCase(true, true, 1, 0, 0, 0, 5, 0, 0, 0, 5, 5),
+        OverrideIncognitoTestCase(true, true, 1, 2, 3, 0, 5, 0, 0, 0, 5, 5),
+        OverrideIncognitoTestCase(true, true, 1, 0, 0, 0, 0, 6, 0, 0, 6, 1),
+        OverrideIncognitoTestCase(true, true, 1, 0, 3, 0, 5, 6, 0, 0, 6, 5),
+        OverrideIncognitoTestCase(true, true, 1, 0, 0, 4, 5, 6, 0, 0, 6, 5),
+        OverrideIncognitoTestCase(true, true, 1, 0, 0, 0, 0, 0, 7, 0, 1, 7),
+        OverrideIncognitoTestCase(true, true, 1, 2, 0, 0, 5, 0, 7, 0, 5, 7),
+        OverrideIncognitoTestCase(true, true, 1, 2, 0, 0, 5, 0, 0, 8, 5, 8),
+        OverrideIncognitoTestCase(true, true, 1, 2, 0, 0, 5, 0, 7, 8, 5, 8),
+        OverrideIncognitoTestCase(true, true, 1, 2, 3, 0, 0, 6, 7, 0, 6, 7),
         // Same tests as above but w/o incognito permission.
-        OverrideIncognitoTestCase(false, false, 1, 0, 0, 0,  0, 0, 0, 0,  1, 0),
-        OverrideIncognitoTestCase(false, false, 1, 2, 0, 0,  0, 0, 0, 0,  2, 0),
-        OverrideIncognitoTestCase(false, false, 1, 0, 3, 0,  0, 0, 0, 0,  1, 0),
-        OverrideIncognitoTestCase(false, false, 1, 0, 0, 4,  0, 0, 0, 0,  1, 0),
-        OverrideIncognitoTestCase(false, false, 1, 0, 3, 4,  0, 0, 0, 0,  1, 0),
-        OverrideIncognitoTestCase(false, false, 1, 2, 3, 0,  0, 0, 0, 0,  2, 0),
-        OverrideIncognitoTestCase(false, false, 1, 0, 0, 0,  5, 0, 0, 0,  5, 0),
-        OverrideIncognitoTestCase(false, false, 1, 2, 3, 0,  5, 0, 0, 0,  5, 0),
-        OverrideIncognitoTestCase(false, false, 1, 0, 0, 0,  0, 6, 0, 0,  6, 0),
-        OverrideIncognitoTestCase(false, false, 1, 0, 3, 0,  5, 6, 0, 0,  6, 0),
-        OverrideIncognitoTestCase(false, false, 1, 0, 0, 4,  5, 6, 0, 0,  6, 0),
-        OverrideIncognitoTestCase(false, false, 1, 0, 0, 0,  0, 0, 7, 0,  1, 0),
-        OverrideIncognitoTestCase(false, false, 1, 2, 0, 0,  5, 0, 7, 0,  5, 0),
-        OverrideIncognitoTestCase(false, false, 1, 2, 0, 0,  5, 0, 0, 8,  5, 0),
-        OverrideIncognitoTestCase(false, false, 1, 2, 0, 0,  5, 0, 7, 8,  5, 0),
-        OverrideIncognitoTestCase(false, false, 1, 2, 3, 0,  0, 6, 7, 0,  6, 0)
-        ));
+        OverrideIncognitoTestCase(false, false, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0),
+        OverrideIncognitoTestCase(false, false, 1, 2, 0, 0, 0, 0, 0, 0, 2, 0),
+        OverrideIncognitoTestCase(false, false, 1, 0, 3, 0, 0, 0, 0, 0, 1, 0),
+        OverrideIncognitoTestCase(false, false, 1, 0, 0, 4, 0, 0, 0, 0, 1, 0),
+        OverrideIncognitoTestCase(false, false, 1, 0, 3, 4, 0, 0, 0, 0, 1, 0),
+        OverrideIncognitoTestCase(false, false, 1, 2, 3, 0, 0, 0, 0, 0, 2, 0),
+        OverrideIncognitoTestCase(false, false, 1, 0, 0, 0, 5, 0, 0, 0, 5, 0),
+        OverrideIncognitoTestCase(false, false, 1, 2, 3, 0, 5, 0, 0, 0, 5, 0),
+        OverrideIncognitoTestCase(false, false, 1, 0, 0, 0, 0, 6, 0, 0, 6, 0),
+        OverrideIncognitoTestCase(false, false, 1, 0, 3, 0, 5, 6, 0, 0, 6, 0),
+        OverrideIncognitoTestCase(false, false, 1, 0, 0, 4, 5, 6, 0, 0, 6, 0),
+        OverrideIncognitoTestCase(false, false, 1, 0, 0, 0, 0, 0, 7, 0, 1, 0),
+        OverrideIncognitoTestCase(false, false, 1, 2, 0, 0, 5, 0, 7, 0, 5, 0),
+        OverrideIncognitoTestCase(false, false, 1, 2, 0, 0, 5, 0, 0, 8, 5, 0),
+        OverrideIncognitoTestCase(false, false, 1, 2, 0, 0, 5, 0, 7, 8, 5, 0),
+        OverrideIncognitoTestCase(false, false, 1, 2, 3, 0, 0, 6, 7, 0, 6, 0)));
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
index abbac459..fb3ea07 100644
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_browsertest.cc
@@ -176,9 +176,9 @@
   DISALLOW_COPY_AND_ASSIGN(MimeHandlerViewCrossProcessTest);
 };
 
-INSTANTIATE_TEST_CASE_P(/* no prefix */,
-                        MimeHandlerViewCrossProcessTest,
-                        ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(/* no prefix */,
+                         MimeHandlerViewCrossProcessTest,
+                         ::testing::Bool());
 
 IN_PROC_BROWSER_TEST_P(MimeHandlerViewCrossProcessTest, Embedded) {
   RunTest("test_embedded.html");
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_interactive_uitest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_interactive_uitest.cc
index 168f346..33a204f 100644
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_interactive_uitest.cc
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_interactive_uitest.cc
@@ -129,9 +129,9 @@
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-INSTANTIATE_TEST_CASE_P(MimeHandlerViewTests,
-                        MimeHandlerViewTest,
-                        testing::Bool());
+INSTANTIATE_TEST_SUITE_P(MimeHandlerViewTests,
+                         MimeHandlerViewTest,
+                         testing::Bool());
 
 // Test is flaky on Linux.  https://crbug.com/877627
 #if defined(OS_LINUX)
diff --git a/extensions/browser/updater/update_service_unittest.cc b/extensions/browser/updater/update_service_unittest.cc
index dfdbfe64..63958a8d 100644
--- a/extensions/browser/updater/update_service_unittest.cc
+++ b/extensions/browser/updater/update_service_unittest.cc
@@ -1037,13 +1037,14 @@
   EXPECT_FALSE(update_service()->CanUpdate(""));
 }
 
-INSTANTIATE_TEST_CASE_P(CanUpdateTest,
-                        UpdateServiceCanUpdateTest,
-                        ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(CanUpdateTest,
+                         UpdateServiceCanUpdateTest,
+                         ::testing::Bool());
 
-INSTANTIATE_TEST_CASE_P(CanUpdateTest,
-                        UpdateServiceCanUpdateFeatureEnabledNonDefaultUpdateUrl,
-                        ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(
+    CanUpdateTest,
+    UpdateServiceCanUpdateFeatureEnabledNonDefaultUpdateUrl,
+    ::testing::Bool());
 
 }  // namespace
 
diff --git a/extensions/browser/value_store/BUILD.gn b/extensions/browser/value_store/BUILD.gn
index 3048a6ee..5eda724 100644
--- a/extensions/browser/value_store/BUILD.gn
+++ b/extensions/browser/value_store/BUILD.gn
@@ -29,6 +29,7 @@
   ]
 
   deps = [
+    "//base",
     "//third_party/leveldatabase",
   ]
 }
diff --git a/extensions/browser/value_store/leveldb_value_store_unittest.cc b/extensions/browser/value_store/leveldb_value_store_unittest.cc
index 71f3f3d..c8cd2fc 100644
--- a/extensions/browser/value_store/leveldb_value_store_unittest.cc
+++ b/extensions/browser/value_store/leveldb_value_store_unittest.cc
@@ -27,10 +27,9 @@
 
 }  // namespace
 
-INSTANTIATE_TEST_CASE_P(
-    LeveldbValueStore,
-    ValueStoreTest,
-    testing::Values(&Param));
+INSTANTIATE_TEST_SUITE_P(LeveldbValueStore,
+                         ValueStoreTest,
+                         testing::Values(&Param));
 
 class LeveldbValueStoreUnitTest : public testing::Test {
  public:
diff --git a/extensions/browser/value_store/testing_value_store_unittest.cc b/extensions/browser/value_store/testing_value_store_unittest.cc
index 487512c..7d3397b 100644
--- a/extensions/browser/value_store/testing_value_store_unittest.cc
+++ b/extensions/browser/value_store/testing_value_store_unittest.cc
@@ -16,9 +16,8 @@
 
 }  // namespace
 
-INSTANTIATE_TEST_CASE_P(
-    TestingValueStore,
-    ValueStoreTest,
-    testing::Values(&Param));
+INSTANTIATE_TEST_SUITE_P(TestingValueStore,
+                         ValueStoreTest,
+                         testing::Values(&Param));
 
 }  // namespace extensions
diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor_unittest.cc b/extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor_unittest.cc
index 47a8876..7221429 100644
--- a/extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor_unittest.cc
+++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor_unittest.cc
@@ -128,7 +128,7 @@
   EXPECT_EQ(number_of_channels_, descriptor.number_of_channels());
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     WiFiDisplayElementaryStreamDescriptorTests,
     LPCMAudioStreamDescriptorTest,
     testing::Values(testing::make_tuple(
diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_media_packetizer_unittest.cc b/extensions/renderer/api/display_source/wifi_display/wifi_display_media_packetizer_unittest.cc
index d243ca0f..94b57051 100644
--- a/extensions/renderer/api/display_source/wifi_display/wifi_display_media_packetizer_unittest.cc
+++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_media_packetizer_unittest.cc
@@ -732,7 +732,7 @@
   }
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     WiFiDisplayElementaryStreamUnitPacketizationTests,
     WiFiDisplayElementaryStreamUnitPacketizationTest,
     testing::Combine(testing::Values(123u, 180u, 0x10000u),
diff --git a/extensions/renderer/gc_callback_unittest.cc b/extensions/renderer/gc_callback_unittest.cc
index 451be81..f92c7e6e 100644
--- a/extensions/renderer/gc_callback_unittest.cc
+++ b/extensions/renderer/gc_callback_unittest.cc
@@ -202,16 +202,16 @@
   EXPECT_EQ(has_fallback(), fallback_invoked);
 }
 
-INSTANTIATE_TEST_CASE_P(NativeCallback,
-                        GCCallbackTest,
-                        ::testing::Values(NATIVE));
-INSTANTIATE_TEST_CASE_P(JSCallback, GCCallbackTest, ::testing::Values(JS));
-INSTANTIATE_TEST_CASE_P(NativeCallbackWithNoFallback,
-                        GCCallbackTest,
-                        ::testing::Values(NATIVE_WITH_NO_FALLBACK));
-INSTANTIATE_TEST_CASE_P(JSCallbackWithNoFallback,
-                        GCCallbackTest,
-                        ::testing::Values(JS_WITH_NO_FALLBACK));
+INSTANTIATE_TEST_SUITE_P(NativeCallback,
+                         GCCallbackTest,
+                         ::testing::Values(NATIVE));
+INSTANTIATE_TEST_SUITE_P(JSCallback, GCCallbackTest, ::testing::Values(JS));
+INSTANTIATE_TEST_SUITE_P(NativeCallbackWithNoFallback,
+                         GCCallbackTest,
+                         ::testing::Values(NATIVE_WITH_NO_FALLBACK));
+INSTANTIATE_TEST_SUITE_P(JSCallbackWithNoFallback,
+                         GCCallbackTest,
+                         ::testing::Values(JS_WITH_NO_FALLBACK));
 
 }  // namespace
 }  // namespace extensions
diff --git a/extensions/renderer/native_extension_bindings_system_unittest.cc b/extensions/renderer/native_extension_bindings_system_unittest.cc
index e2cf4ae..b541b8e 100644
--- a/extensions/renderer/native_extension_bindings_system_unittest.cc
+++ b/extensions/renderer/native_extension_bindings_system_unittest.cc
@@ -1239,8 +1239,9 @@
   }
 }
 
-INSTANTIATE_TEST_CASE_P(,
-                        ResponseValidationNativeExtensionBindingsSystemUnittest,
-                        testing::Bool());
+INSTANTIATE_TEST_SUITE_P(
+    ,
+    ResponseValidationNativeExtensionBindingsSystemUnittest,
+    testing::Bool());
 
 }  // namespace extensions
diff --git a/fuchsia/base/BUILD.gn b/fuchsia/base/BUILD.gn
index 131f3c34..36231384 100644
--- a/fuchsia/base/BUILD.gn
+++ b/fuchsia/base/BUILD.gn
@@ -38,12 +38,15 @@
 
 source_set("test_support") {
   testonly = true
-  public = [
+  sources = [
+    "fake_component_context.cc",
+    "fake_component_context.h",
     "fit_adapter.h",
     "result_receiver.h",
   ]
   public_deps = [
     "//base",
+    "//third_party/fuchsia-sdk/sdk:modular",
   ]
 }
 
diff --git a/fuchsia/base/fake_component_context.cc b/fuchsia/base/fake_component_context.cc
new file mode 100644
index 0000000..4b7cc9c
--- /dev/null
+++ b/fuchsia/base/fake_component_context.cc
@@ -0,0 +1,31 @@
+// 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 "fuchsia/base/fake_component_context.h"
+
+#include <fuchsia/base/agent_impl.h>
+#include <memory>
+#include <string>
+#include <utility>
+
+namespace cr_fuchsia {
+
+FakeComponentContext::FakeComponentContext(
+    AgentImpl::CreateComponentStateCallback create_component_state_callback,
+    base::fuchsia::ServiceDirectory* service_directory,
+    std::string component_url)
+    : agent_impl_(service_directory,
+                  std::move(create_component_state_callback)),
+      component_url_(component_url) {}
+
+void FakeComponentContext::ConnectToAgent(
+    std::string agent_url,
+    fidl::InterfaceRequest<::fuchsia::sys::ServiceProvider> services,
+    fidl::InterfaceRequest<fuchsia::modular::AgentController> controller) {
+  agent_impl_.Connect(component_url_, std::move(services));
+}
+
+FakeComponentContext::~FakeComponentContext() = default;
+
+}  // namespace cr_fuchsia
diff --git a/fuchsia/base/fake_component_context.h b/fuchsia/base/fake_component_context.h
new file mode 100644
index 0000000..749ec3d
--- /dev/null
+++ b/fuchsia/base/fake_component_context.h
@@ -0,0 +1,47 @@
+// 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 FUCHSIA_BASE_FAKE_COMPONENT_CONTEXT_H_
+#define FUCHSIA_BASE_FAKE_COMPONENT_CONTEXT_H_
+
+#include <fuchsia/base/agent_impl.h>
+#include <fuchsia/modular/cpp/fidl_test_base.h>
+#include <memory>
+#include <string>
+#include <utility>
+
+namespace cr_fuchsia {
+
+// Used to test interactions with an Agent in unit-tests for a component.
+// |create_component_state_callback| can be used with a test-specific
+// ComponentStateBase to serve fake services to the component.
+// |service_directory| specifies the directory into which the ComponentContext
+// should be published, alongside any other services the test wishes to provide
+// to the component's default service namespace. |component_url| specifies the
+// component identity that should be reported to the Agent
+class FakeComponentContext
+    : public fuchsia::modular::testing::ComponentContext_TestBase {
+ public:
+  explicit FakeComponentContext(
+      AgentImpl::CreateComponentStateCallback create_component_state_callback,
+      base::fuchsia::ServiceDirectory* service_directory,
+      std::string component_url);
+  ~FakeComponentContext() override;
+
+  // fuchsia::modular::ComponentContext implementation.
+  void ConnectToAgent(
+      std::string agent_url,
+      fidl::InterfaceRequest<::fuchsia::sys::ServiceProvider> services,
+      fidl::InterfaceRequest<fuchsia::modular::AgentController> controller)
+      override;
+
+ private:
+  AgentImpl agent_impl_;
+  const std::string component_url_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeComponentContext);
+};
+
+}  // namespace cr_fuchsia
+#endif  // FUCHSIA_BASE_FAKE_COMPONENT_CONTEXT_H_
diff --git a/fuchsia/runners/cast/sandbox_policy b/fuchsia/runners/cast/sandbox_policy
index cc9f03e..1b71af62 100644
--- a/fuchsia/runners/cast/sandbox_policy
+++ b/fuchsia/runners/cast/sandbox_policy
@@ -10,6 +10,7 @@
       "fuchsia.ui.input.ImeService",
       "fuchsia.ui.input.ImeVisibilityService",
       "fuchsia.ui.scenic.Scenic",
+      "fuchsia.ui.viewsv1.ViewManager",
       "fuchsia.vulkan.loader.Loader"
   ]
 }
diff --git a/fuchsia/runners/web/sandbox_policy b/fuchsia/runners/web/sandbox_policy
index 0d084f2..4038e53 100644
--- a/fuchsia/runners/web/sandbox_policy
+++ b/fuchsia/runners/web/sandbox_policy
@@ -11,6 +11,7 @@
       "fuchsia.ui.input.ImeService",
       "fuchsia.ui.input.ImeVisibilityService",
       "fuchsia.ui.scenic.Scenic",
+      "fuchsia.ui.viewsv1.ViewManager",
       "fuchsia.vulkan.loader.Loader"
   ]
 }
diff --git a/google_apis/google_api_keys.cc b/google_apis/google_api_keys.cc
index d05b9ef..8f0ea9e8 100644
--- a/google_apis/google_api_keys.cc
+++ b/google_apis/google_api_keys.cc
@@ -73,6 +73,10 @@
 #define GOOGLE_API_KEY_PHYSICAL_WEB_TEST DUMMY_API_TOKEN
 #endif
 
+#if !defined(GOOGLE_API_KEY_REMOTING_FTL)
+#define GOOGLE_API_KEY_REMOTING_FTL DUMMY_API_TOKEN
+#endif
+
 // These are used as shortcuts for developers and users providing
 // OAuth credentials via preprocessor defines or environment
 // variables.  If set, they will be used to replace any of the client
@@ -111,6 +115,11 @@
     api_key_non_stable_ = api_key_;
 #endif
 
+    api_key_remoting_ftl_ =
+        CalculateKeyValue(GOOGLE_API_KEY_REMOTING_FTL,
+                          STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_REMOTING_FTL),
+                          NULL, std::string(), environment.get(), command_line);
+
     std::string default_client_id =
         CalculateKeyValue(GOOGLE_DEFAULT_CLIENT_ID,
                           STRINGIZE_NO_EXPANSION(GOOGLE_DEFAULT_CLIENT_ID),
@@ -198,6 +207,7 @@
   void set_api_key(const std::string& api_key) { api_key_ = api_key; }
 #endif
   std::string api_key_non_stable() const { return api_key_non_stable_; }
+  std::string api_key_remoting_ftl() const { return api_key_remoting_ftl_; }
 
   std::string GetClientID(OAuth2Client client) const {
     DCHECK_LT(client, CLIENT_NUM_ITEMS);
@@ -293,6 +303,7 @@
 
   std::string api_key_;
   std::string api_key_non_stable_;
+  std::string api_key_remoting_ftl_;
   std::string client_ids_[CLIENT_NUM_ITEMS];
   std::string client_secrets_[CLIENT_NUM_ITEMS];
 };
@@ -312,6 +323,10 @@
   return g_api_key_cache.Get().api_key_non_stable();
 }
 
+std::string GetRemotingFtlAPIKey() {
+  return g_api_key_cache.Get().api_key_remoting_ftl();
+}
+
 #if defined(OS_IOS)
 void SetAPIKey(const std::string& api_key) {
   g_api_key_cache.Get().set_api_key(api_key);
diff --git a/google_apis/google_api_keys.h b/google_apis/google_api_keys.h
index d4979fe9..6f13643d 100644
--- a/google_apis/google_api_keys.h
+++ b/google_apis/google_api_keys.h
@@ -73,6 +73,10 @@
 // Non-stable channels may have a different Google API key.
 std::string GetNonStableAPIKey();
 
+// Retrieves the Chrome Remote Desktop FTL API key to be used during the
+// signaling process.
+std::string GetRemotingFtlAPIKey();
+
 #if defined(OS_IOS)
 // Sets the API key. This should be called as early as possible before this
 // API key is even accessed.
diff --git a/gpu/command_buffer/client/image_decode_accelerator_interface.h b/gpu/command_buffer/client/image_decode_accelerator_interface.h
index a2f8b9c..5e1aa72 100644
--- a/gpu/command_buffer/client/image_decode_accelerator_interface.h
+++ b/gpu/command_buffer/client/image_decode_accelerator_interface.h
@@ -5,6 +5,8 @@
 #ifndef GPU_COMMAND_BUFFER_CLIENT_IMAGE_DECODE_ACCELERATOR_INTERFACE_H_
 #define GPU_COMMAND_BUFFER_CLIENT_IMAGE_DECODE_ACCELERATOR_INTERFACE_H_
 
+#include <stdint.h>
+
 #include "base/containers/span.h"
 #include "gpu/command_buffer/common/command_buffer_id.h"
 #include "gpu/command_buffer/common/sync_token.h"
@@ -29,10 +31,11 @@
       uint32_t transfer_cache_entry_id,
       int32_t discardable_handle_shm_id,
       uint32_t discardable_handle_shm_offset,
+      uint64_t discardable_handle_release_count,
       const gfx::ColorSpace& target_color_space,
       bool needs_mips) = 0;
 };
 
 }  // namespace gpu
 
-#endif  // GPU_COMMAND_BUFFER_CLIENT_IMAGE_DECODE_ACCELERATOR_INTERFACE_H_
\ No newline at end of file
+#endif  // GPU_COMMAND_BUFFER_CLIENT_IMAGE_DECODE_ACCELERATOR_INTERFACE_H_
diff --git a/gpu/command_buffer/client/raster_implementation.cc b/gpu/command_buffer/client/raster_implementation.cc
index 2a8d0603..b7c4039 100644
--- a/gpu/command_buffer/client/raster_implementation.cc
+++ b/gpu/command_buffer/client/raster_implementation.cc
@@ -1177,11 +1177,15 @@
   DCHECK(image_decode_accelerator_);
   DCHECK(handle.IsValid());
 
+  // Insert a sync token to signal that |handle|'s buffer has been registered.
+  SyncToken sync_token;
+  GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
+
   // Send the decode request to the service.
   *decode_sync_token = image_decode_accelerator_->ScheduleImageDecode(
       encoded_data, output_size, gpu_control_->GetCommandBufferID(),
       transfer_cache_entry_id, handle.shm_id(), handle.byte_offset(),
-      target_color_space, needs_mips);
+      sync_token.release_count(), target_color_space, needs_mips);
 }
 
 GLuint RasterImplementation::CreateAndConsumeForGpuRaster(
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 60546d5..9b20f9d 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -982,6 +982,7 @@
   // Get the size (in pixels) of the currently bound frame buffer (either FBO
   // or regular back buffer).
   gfx::Size GetBoundReadFramebufferSize();
+  gfx::Size GetBoundDrawFramebufferSize();
 
   // Get the service side ID for the bound read framebuffer.
   // If it's back buffer, 0 is returned.
@@ -5002,6 +5003,17 @@
   }
 }
 
+gfx::Size GLES2DecoderImpl::GetBoundDrawFramebufferSize() {
+  Framebuffer* framebuffer = GetBoundDrawFramebuffer();
+  if (framebuffer) {
+    return framebuffer->GetFramebufferValidSize();
+  } else if (offscreen_target_frame_buffer_.get()) {
+    return offscreen_size_;
+  } else {
+    return surface_->GetSize();
+  }
+};
+
 GLuint GLES2DecoderImpl::GetBoundReadFramebufferServiceId() {
   Framebuffer* framebuffer = GetBoundReadFramebuffer();
   if (framebuffer) {
@@ -8702,7 +8714,21 @@
   const char* func_name = "glBlitFramebufferCHROMIUM";
   DCHECK(!ShouldDeferReads() && !ShouldDeferDraws());
 
-  if (!CheckBoundFramebufferValid(func_name)) {
+  if (!CheckFramebufferValid(GetBoundDrawFramebuffer(),
+                             GetDrawFramebufferTarget(),
+                             GL_INVALID_FRAMEBUFFER_OPERATION, func_name)) {
+    return;
+  }
+
+  // We need to get this before checking if the read framebuffer is valid.
+  // Checking the read framebuffer may clear attachments which would mark the
+  // draw framebuffer as incomplete. Framebuffer::GetFramebufferValidSize()
+  // requires the framebuffer to be complete.
+  gfx::Size draw_size = GetBoundDrawFramebufferSize();
+
+  if (!CheckFramebufferValid(GetBoundReadFramebuffer(),
+                             GetReadFramebufferTarget(),
+                             GL_INVALID_FRAMEBUFFER_OPERATION, func_name)) {
     return;
   }
 
@@ -8919,52 +8945,161 @@
 
   if (workarounds().adjust_src_dst_region_for_blitframebuffer) {
     gfx::Size read_size = GetBoundReadFramebufferSize();
-    gfx::Rect src_bounds(0, 0, read_size.width(), read_size.height());
     GLint src_x = srcX1 > srcX0 ? srcX0 : srcX1;
     GLint src_y = srcY1 > srcY0 ? srcY0 : srcY1;
-    GLuint src_width = 0, src_height = 0;
-    if (!src_width_temp.Abs().AssignIfValid(&src_width))
-      src_width = 0;
-    if (!src_height_temp.Abs().AssignIfValid(&src_height))
-      src_height = 0;
+    unsigned int src_width = base::checked_cast<unsigned int>(
+        src_width_temp.Abs().ValueOrDefault(0));
+    unsigned int src_height = base::checked_cast<unsigned int>(
+        src_height_temp.Abs().ValueOrDefault(0));
 
+    GLint dst_x = dstX1 > dstX0 ? dstX0 : dstX1;
+    GLint dst_y = dstY1 > dstY0 ? dstY0 : dstY1;
+    unsigned int dst_width = base::checked_cast<unsigned int>(
+        dst_width_temp.Abs().ValueOrDefault(0));
+    unsigned int dst_height = base::checked_cast<unsigned int>(
+        dst_height_temp.Abs().ValueOrDefault(0));
+
+    if (dst_width == 0 || src_width == 0 || dst_height == 0 ||
+        src_height == 0) {
+      return;
+    }
+
+    gfx::Rect src_bounds(0, 0, read_size.width(), read_size.height());
     gfx::Rect src_region(src_x, src_y, src_width, src_height);
-    if (!src_bounds.Contains(src_region) &&
-        (src_width != 0) && (src_height != 0)) {
-      // If pixels lying outside the read framebuffer, adjust src region
-      // and dst region to appropriate in-bounds regions respectively.
-      src_bounds.Intersect(src_region);
-      GLuint src_real_width = src_bounds.width();
-      GLuint src_real_height = src_bounds.height();
-      GLuint xoffset = src_bounds.x() - src_x;
-      GLuint yoffset = src_bounds.y() - src_y;
-      // if X/Y is reversed, use the top/right out-of-bounds region for mapping
-      // to dst region, instead of left/bottom out-of-bounds region for mapping.
-      if (((srcX1 > srcX0) && (dstX1 < dstX0)) ||
-          ((srcX1 < srcX0) && (dstX1 > dstX0))) {
-        xoffset = src_x + src_width - src_bounds.x() - src_bounds.width();
-      }
-      if (((srcY1 > srcY0) && (dstY1 < dstY0)) ||
-          ((srcY1 < srcY0) && (dstY1 > dstY0))) {
-        yoffset = src_y + src_height - src_bounds.y() - src_bounds.height();
+
+    gfx::Rect dst_bounds(0, 0, draw_size.width(), draw_size.height());
+    gfx::Rect dst_region(dst_x, dst_y, dst_width, dst_height);
+
+    if (gfx::IntersectRects(dst_bounds, dst_region).IsEmpty()) {
+      return;
+    }
+
+    bool x_flipped = ((srcX1 > srcX0) && (dstX1 < dstX0)) ||
+                     ((srcX1 < srcX0) && (dstX1 > dstX0));
+    bool y_flipped = ((srcY1 > srcY0) && (dstY1 < dstY0)) ||
+                     ((srcY1 < srcY0) && (dstY1 > dstY0));
+
+    if (!dst_bounds.Contains(dst_region)) {
+      // dst_region is not within dst_bounds. We want to adjust it to a
+      // reasonable size. This is done by halving the dst_region until it is at
+      // most twice the size of the framebuffer. We cut it in half instead
+      // of arbitrarily shrinking it to fit so that we don't end up with
+      // non-power-of-two scale factors which could mess up pixel interpolation.
+      // Naively clipping the dst rect and then proportionally sizing the
+      // src rect yields incorrect results.
+
+      unsigned int dst_x_halvings = 0;
+      unsigned int dst_y_halvings = 0;
+      int dst_origin_x = dst_x;
+      int dst_origin_y = dst_y;
+
+      int dst_clipped_width = dst_region.width();
+      while (dst_clipped_width > 2 * dst_bounds.width()) {
+        dst_clipped_width = dst_clipped_width >> 1;
+        dst_x_halvings++;
       }
 
-      GLint dst_x = dstX1 > dstX0 ? dstX0 : dstX1;
-      GLint dst_y = dstY1 > dstY0 ? dstY0 : dstY1;
-      base::CheckedNumeric<GLint> dst_width_temp = dstX1;
-      dst_width_temp -= dstX0;
-      base::CheckedNumeric<GLint> dst_height_temp = dstY1;
-      dst_height_temp -= dstY0;
-      GLuint dst_width = 0, dst_height = 0;
-      if (!dst_width_temp.IsValid() || !dst_height_temp.IsValid()) {
-        LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name,
-                           "the width or height of dst region overflow");
+      int dst_clipped_height = dst_region.height();
+      while (dst_clipped_height > 2 * dst_bounds.height()) {
+        dst_clipped_height = dst_clipped_height >> 1;
+        dst_y_halvings++;
+      }
+
+      // Before this block, we check that the two rectangles intersect.
+      // Now, compute the location of a new region origin such that we use the
+      // scaled dimensions but the new region has the same intersection as the
+      // original region.
+
+      int left = dst_region.x();
+      int right = dst_region.right();
+      int top = dst_region.y();
+      int bottom = dst_region.bottom();
+
+      if (left >= 0 && left < dst_bounds.width()) {
+        // Left edge is in-bounds
+        dst_origin_x = dst_x;
+      } else if (right > 0 && right <= dst_bounds.width()) {
+        // Right edge is in-bounds
+        dst_origin_x = right - dst_clipped_width;
+      } else {
+        // Region completely spans bounds
+        dst_origin_x = dst_x;
+      }
+
+      if (top >= 0 && top < dst_bounds.height()) {
+        // Top edge is in-bounds
+        dst_origin_y = dst_y;
+      } else if (bottom > 0 && bottom <= dst_bounds.height()) {
+        // Bottom edge is in-bounds
+        dst_origin_y = bottom - dst_clipped_height;
+      } else {
+        // Region completely spans bounds
+        dst_origin_y = dst_y;
+      }
+
+      dst_region.SetRect(dst_origin_x, dst_origin_y, dst_clipped_width,
+                         dst_clipped_height);
+
+      // Offsets from the bottom left corner of the original region to
+      // the bottom left corner of the clipped region.
+      // This value (after it is scaled) is the respective offset we will apply
+      // to the src origin.
+      base::CheckedNumeric<unsigned int> checked_xoffset(dst_region.x() -
+                                                         dst_x);
+      base::CheckedNumeric<unsigned int> checked_yoffset(dst_region.y() -
+                                                         dst_y);
+
+      // if X/Y is reversed, use the top/right out-of-bounds region to compute
+      // the origin offset instead of the left/bottom out-of-bounds region
+      if (x_flipped) {
+        checked_xoffset = (dst_x + dst_width - dst_region.right());
+      }
+      if (y_flipped) {
+        checked_yoffset = (dst_y + dst_height - dst_region.bottom());
+      }
+
+      // These offsets should never overflow.
+      unsigned int xoffset, yoffset;
+      if (!checked_xoffset.AssignIfValid(&xoffset) ||
+          !checked_yoffset.AssignIfValid(&yoffset)) {
+        NOTREACHED();
+        LOCAL_SET_GL_ERROR(
+            GL_INVALID_VALUE, func_name,
+            "the width or height of src or dst region overflowed");
         return;
       }
-      if (!dst_width_temp.Abs().AssignIfValid(&dst_width))
-        dst_width = 0;
-      if (!dst_height_temp.Abs().AssignIfValid(&dst_height))
-        dst_height = 0;
+
+      // Adjust the src region by the same factor
+      src_region.SetRect(src_x + (xoffset >> dst_x_halvings),
+                         src_y + (yoffset >> dst_y_halvings),
+                         src_region.width() >> dst_x_halvings,
+                         src_region.height() >> dst_y_halvings);
+
+      // If the src was scaled to 0, set it to 1 so the src is non-empty.
+      if (src_region.width() == 0) {
+        src_region.set_width(1);
+      }
+      if (src_region.height() == 0) {
+        src_region.set_height(1);
+      }
+    }
+
+    if (!src_bounds.Contains(src_region)) {
+      // If pixels lying outside the read framebuffer, adjust src region
+      // and dst region to appropriate in-bounds regions respectively.
+      src_region.Intersect(src_bounds);
+      GLuint src_real_width = src_region.width();
+      GLuint src_real_height = src_region.height();
+      GLuint xoffset = src_region.x() - src_x;
+      GLuint yoffset = src_region.y() - src_y;
+      // if X/Y is reversed, use the top/right out-of-bounds region for mapping
+      // to dst region, instead of left/bottom out-of-bounds region for mapping.
+      if (x_flipped) {
+        xoffset = src_x + src_width - src_region.x() - src_region.width();
+      }
+      if (y_flipped) {
+        yoffset = src_y + src_height - src_region.y() - src_region.height();
+      }
 
       GLfloat dst_mapping_width =
           static_cast<GLfloat>(src_real_width) * dst_width / src_width;
@@ -8985,21 +9120,22 @@
       GLuint dst_mapping_y1 =
           std::round(dst_y + dst_mapping_yoffset + dst_mapping_height);
 
-      // adjust the src region and dst region to fit the read framebuffer
-      srcX0 = srcX0 < srcX1 ?
-          src_bounds.x() : src_bounds.x() + src_bounds.width();
-      srcY0 = srcY0 < srcY1 ?
-          src_bounds.y() : src_bounds.y() + src_bounds.height();
-      srcX1 = srcX0 < srcX1 ?
-          src_bounds.x() + src_bounds.width() : src_bounds.x();
-      srcY1 = srcY0 < srcY1 ?
-          src_bounds.y() + src_bounds.height() : src_bounds.y();
-
-      dstX0 = dstX0 < dstX1 ? dst_mapping_x0 : dst_mapping_x1;
-      dstY0 = dstY0 < dstY1 ? dst_mapping_y0 : dst_mapping_y1;
-      dstX1 = dstX0 < dstX1 ? dst_mapping_x1 : dst_mapping_x0;
-      dstY1 = dstY0 < dstY1 ? dst_mapping_y1 : dst_mapping_y0;
+      dst_region.SetRect(dst_mapping_x0, dst_mapping_y0,
+                         dst_mapping_x1 - dst_mapping_x0,
+                         dst_mapping_y1 - dst_mapping_y0);
     }
+
+    // Set the src and dst endpoints. If they were previously flipped,
+    // set them as flipped.
+    srcX0 = srcX0 < srcX1 ? src_region.x() : src_region.right();
+    srcY0 = srcY0 < srcY1 ? src_region.y() : src_region.bottom();
+    srcX1 = srcX0 < srcX1 ? src_region.right() : src_region.x();
+    srcY1 = srcY0 < srcY1 ? src_region.bottom() : src_region.y();
+
+    dstX0 = dstX0 < dstX1 ? dst_region.x() : dst_region.right();
+    dstY0 = dstY0 < dstY1 ? dst_region.y() : dst_region.bottom();
+    dstX1 = dstX0 < dstX1 ? dst_region.right() : dst_region.x();
+    dstY1 = dstY0 < dstY1 ? dst_region.bottom() : dst_region.y();
   }
 
   bool enable_srgb =
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json
index e08d93ff..c44e749 100644
--- a/gpu/config/gpu_driver_bug_list.json
+++ b/gpu/config/gpu_driver_bug_list.json
@@ -1953,7 +1953,7 @@
     },
     {
       "id": 197,
-      "description": "adjust src/dst region if blitting pixels outside read framebuffer on Mac",
+      "description": "adjust src/dst region if blitting pixels outside framebuffer on Mac",
       "cr_bugs": [644740],
       "os": {
         "type": "macosx"
@@ -1964,7 +1964,7 @@
     },
     {
       "id": 198,
-      "description": "adjust src/dst region if blitting pixels outside read framebuffer on Linux Intel",
+      "description": "adjust src/dst region if blitting pixels outside framebuffer on Linux Intel",
       "cr_bugs": [664740],
       "os": {
         "type": "linux"
@@ -1976,7 +1976,7 @@
     },
     {
       "id": 199,
-      "description": "adjust src/dst region if blitting pixels outside read framebuffer on Linux AMD",
+      "description": "adjust src/dst region if blitting pixels outside framebuffer on Linux AMD",
       "cr_bugs": [664740],
       "os": {
         "type": "linux"
@@ -3123,6 +3123,30 @@
       "features": [
         "round_down_uniform_bind_buffer_range_size"
       ]
+    },
+    {
+      "id": 291,
+      "description": "adjust src/dst region if blitting pixels outside framebuffer on Linux NVIDIA",
+      "cr_bugs": [830046],
+      "os": {
+        "type": "linux"
+      },
+      "vendor_id": "0x10de",
+      "features": [
+        "adjust_src_dst_region_for_blitframebuffer"
+      ]
+    },
+    {
+      "id": 292,
+      "description": "adjust src/dst region if blitting pixels outside framebuffer on Android NVIDIA",
+      "cr_bugs": [830046],
+      "os": {
+        "type": "android"
+      },
+      "gl_vendor": "NVIDIA.*",
+      "features": [
+        "adjust_src_dst_region_for_blitframebuffer"
+      ]
     }
   ]
 }
diff --git a/gpu/ipc/client/image_decode_accelerator_proxy.cc b/gpu/ipc/client/image_decode_accelerator_proxy.cc
index f0b167f..4691684 100644
--- a/gpu/ipc/client/image_decode_accelerator_proxy.cc
+++ b/gpu/ipc/client/image_decode_accelerator_proxy.cc
@@ -4,6 +4,7 @@
 
 #include "gpu/ipc/client/image_decode_accelerator_proxy.h"
 
+#include <utility>
 #include <vector>
 
 #include "gpu/command_buffer/common/constants.h"
@@ -28,6 +29,7 @@
     uint32_t transfer_cache_entry_id,
     int32_t discardable_handle_shm_id,
     uint32_t discardable_handle_shm_offset,
+    uint64_t discardable_handle_release_count,
     const gfx::ColorSpace& target_color_space,
     bool needs_mips) {
   DCHECK(host_);
@@ -43,13 +45,18 @@
   params.transfer_cache_entry_id = transfer_cache_entry_id;
   params.discardable_handle_shm_id = discardable_handle_shm_id;
   params.discardable_handle_shm_offset = discardable_handle_shm_offset;
+  params.discardable_handle_release_count = discardable_handle_release_count;
   params.target_color_space = target_color_space;
   params.needs_mips = needs_mips;
 
   base::AutoLock lock(lock_);
-  uint64_t release_count = ++next_release_count_;
+  const uint64_t release_count = ++next_release_count_;
   // Note: we send the message under the lock to guarantee monotonicity of the
   // release counts as seen by the service.
+  // The EnsureFlush() call makes sure that the sync token corresponding to
+  // |discardable_handle_release_count| is visible to the service before
+  // processing the image decode request.
+  host_->EnsureFlush(UINT32_MAX);
   host_->Send(new GpuChannelMsg_ScheduleImageDecode(
       route_id_, std::move(params), release_count));
   return SyncToken(
diff --git a/gpu/ipc/client/image_decode_accelerator_proxy.h b/gpu/ipc/client/image_decode_accelerator_proxy.h
index 4b183b9e..5ad7bec 100644
--- a/gpu/ipc/client/image_decode_accelerator_proxy.h
+++ b/gpu/ipc/client/image_decode_accelerator_proxy.h
@@ -29,13 +29,18 @@
 // (1) Create a locked ClientImageTransferCacheEntry without a backing
 //     SkPixmap. This entry should not be serialized over the command buffer.
 //
-// (2) Call ScheduleImageDecode().
+// (2) Insert a sync token in the command buffer that is released after the
+//     discardable handle's buffer corresponding to the transfer cache entry has
+//     been registered.
 //
-// (3) Issue a server wait on the sync token returned in step (2).
+// (3) Call ScheduleImageDecode(). The release count of the sync token from the
+//     previous step is passed for the |discardable_handle_release_count|
+//     parameter.
+//
+// (4) Issue a server wait on the sync token returned in step (3).
 //
 // When the service is done with the decode, a ServiceImageTransferCacheEntry
-// will be created/locked with the decoded data and the sync token is
-// released.
+// will be created/locked with the decoded data and the sync token is released.
 //
 // Objects of this class are thread-safe.
 //
@@ -46,13 +51,18 @@
   ~ImageDecodeAcceleratorProxy() override;
 
   // Schedules a hardware-accelerated image decode on the GPU process. The image
-  // in |encoded_data| is decoded and scaled to |output_size|. Upon completion,
-  // a service-side transfer cache entry will be created with the decoded data
-  // using |transfer_cache_entry_id|, |discardable_handle_shm_id|, and
+  // in |encoded_data| is decoded and scaled to |output_size|. Upon completion
+  // and after the sync token corresponding to
+  // |discardable_handle_release_count| has been released, a service-side
+  // transfer cache entry will be created with the decoded data using
+  // |transfer_cache_entry_id|, |discardable_handle_shm_id|, and
   // |discardable_handle_shm_offset|. The |raster_decoder_command_buffer_id| is
   // used to look up the appropriate command buffer and create the transfer
-  // cache entry correctly. Returns a sync token that will be released after the
-  // decode is done and the service-side transfer cache entry is created.
+  // cache entry correctly. Note that it is assumed that
+  // |discardable_handle_release_count| is associated to
+  // |raster_decoder_command_buffer_id|. Returns a sync token that will be
+  // released after the decode is done and the service-side transfer cache entry
+  // is created.
   SyncToken ScheduleImageDecode(
       base::span<const uint8_t> encoded_data,
       const gfx::Size& output_size,
@@ -60,6 +70,7 @@
       uint32_t transfer_cache_entry_id,
       int32_t discardable_handle_shm_id,
       uint32_t discardable_handle_shm_offset,
+      uint64_t discardable_handle_release_count,
       const gfx::ColorSpace& target_color_space,
       bool needs_mips) override;
 
diff --git a/gpu/ipc/common/gpu_messages.h b/gpu/ipc/common/gpu_messages.h
index 4d8771b..ce761b73 100644
--- a/gpu/ipc/common/gpu_messages.h
+++ b/gpu/ipc/common/gpu_messages.h
@@ -112,6 +112,7 @@
   IPC_STRUCT_MEMBER(uint32_t, transfer_cache_entry_id)
   IPC_STRUCT_MEMBER(int32_t, discardable_handle_shm_id)
   IPC_STRUCT_MEMBER(uint32_t, discardable_handle_shm_offset)
+  IPC_STRUCT_MEMBER(uint64_t, discardable_handle_release_count)
   IPC_STRUCT_MEMBER(gfx::ColorSpace, target_color_space)
   IPC_STRUCT_MEMBER(bool, needs_mips)
 IPC_STRUCT_END()
@@ -165,7 +166,7 @@
 IPC_MESSAGE_ROUTED2(
     GpuChannelMsg_ScheduleImageDecode,
     GpuChannelMsg_ScheduleImageDecode_Params /* decode_params */,
-    uint64_t /* release_count */)
+    uint64_t /* decode_release_count */)
 
 // Crash the GPU process in similar way to how chrome://gpucrash does.
 // This is only supported in testing environments, and is otherwise ignored.
diff --git a/gpu/ipc/service/gpu_channel_test_common.h b/gpu/ipc/service/gpu_channel_test_common.h
index a8575a39..fc54ec0 100644
--- a/gpu/ipc/service/gpu_channel_test_common.h
+++ b/gpu/ipc/service/gpu_channel_test_common.h
@@ -37,6 +37,7 @@
   ~GpuChannelTestCommon() override;
 
  protected:
+  Scheduler* scheduler() const { return scheduler_.get(); }
   GpuChannelManager* channel_manager() const { return channel_manager_.get(); }
   base::TestSimpleTaskRunner* task_runner() const { return task_runner_.get(); }
   base::TestSimpleTaskRunner* io_task_runner() const {
diff --git a/gpu/ipc/service/image_decode_accelerator_stub.cc b/gpu/ipc/service/image_decode_accelerator_stub.cc
index eee16ead..add3911 100644
--- a/gpu/ipc/service/image_decode_accelerator_stub.cc
+++ b/gpu/ipc/service/image_decode_accelerator_stub.cc
@@ -119,12 +119,17 @@
 
   // Schedule a task to eventually release the decode sync token. Note that this
   // task won't run until the sequence is re-enabled when a decode completes.
+  const SyncToken discardable_handle_sync_token = SyncToken(
+      CommandBufferNamespace::GPU_IO,
+      CommandBufferIdFromChannelAndRoute(channel_->client_id(),
+                                         decode_params.raster_decoder_route_id),
+      decode_params.discardable_handle_release_count);
   channel_->scheduler()->ScheduleTask(Scheduler::Task(
       sequence_,
       base::BindOnce(&ImageDecodeAcceleratorStub::ProcessCompletedDecode,
                      base::WrapRefCounted(this), std::move(decode_params),
                      release_count),
-      std::vector<SyncToken>()));
+      {discardable_handle_sync_token} /* sync_token_fences */));
 }
 
 void ImageDecodeAcceleratorStub::ProcessCompletedDecode(
diff --git a/gpu/ipc/service/image_decode_accelerator_stub_unittest.cc b/gpu/ipc/service/image_decode_accelerator_stub_unittest.cc
index 292fb5f..52a79daf 100644
--- a/gpu/ipc/service/image_decode_accelerator_stub_unittest.cc
+++ b/gpu/ipc/service/image_decode_accelerator_stub_unittest.cc
@@ -6,12 +6,15 @@
 #include <stdint.h>
 
 #include <utility>
+#include <vector>
 
 #include "base/atomicops.h"
 #include "base/bind.h"
 #include "base/containers/queue.h"
+#include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/numerics/checked_math.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_simple_task_runner.h"
@@ -22,11 +25,14 @@
 #include "gpu/command_buffer/common/constants.h"
 #include "gpu/command_buffer/common/context_creation_attribs.h"
 #include "gpu/command_buffer/common/context_result.h"
+#include "gpu/command_buffer/common/discardable_handle.h"
 #include "gpu/command_buffer/common/scheduling_priority.h"
 #include "gpu/command_buffer/common/sync_token.h"
 #include "gpu/command_buffer/service/context_group.h"
 #include "gpu/command_buffer/service/decoder_context.h"
 #include "gpu/command_buffer/service/mocks.h"
+#include "gpu/command_buffer/service/scheduler.h"
+#include "gpu/command_buffer/service/sequence_id.h"
 #include "gpu/command_buffer/service/service_transfer_cache.h"
 #include "gpu/command_buffer/service/shared_context_state.h"
 #include "gpu/command_buffer/service/sync_point_manager.h"
@@ -130,7 +136,8 @@
 class ImageDecodeAcceleratorStubTest : public GpuChannelTestCommon {
  public:
   ImageDecodeAcceleratorStubTest()
-      : GpuChannelTestCommon(false /* use_stub_bindings */) {}
+      : GpuChannelTestCommon(false /* use_stub_bindings */),
+        weak_ptr_factory_(this) {}
   ~ImageDecodeAcceleratorStubTest() override = default;
 
   SyncPointManager* sync_point_manager() const {
@@ -217,9 +224,60 @@
     channel_manager()->DestroyAllChannels();
   }
 
+  // Intended to run as a task in the GPU scheduler (in the raster sequence):
+  // registers |buffer| in the TransferBufferManager and releases the sync token
+  // corresponding to |handle_release_count|.
+  void RegisterDiscardableHandleBuffer(int32_t shm_id,
+                                       scoped_refptr<Buffer> buffer,
+                                       uint64_t handle_release_count) {
+    GpuChannel* channel = channel_manager()->LookupChannel(kChannelId);
+    CHECK(channel);
+    CommandBufferStub* command_buffer =
+        channel->LookupCommandBuffer(kCommandBufferRouteId);
+    CHECK(command_buffer);
+    command_buffer->RegisterTransferBufferForTest(shm_id, std::move(buffer));
+    command_buffer->OnFenceSyncRelease(handle_release_count);
+  }
+
+  // Creates a discardable handle and schedules a task in the GPU scheduler (in
+  // the raster sequence) to register the handle's buffer and release the sync
+  // token corresponding to |handle_release_count| (see the
+  // RegisterDiscardableHandleBuffer() method). Returns an invalid handle if the
+  // GPU channel or the command buffer doesn't exist.
+  ClientDiscardableHandle CreateDiscardableHandle(
+      uint64_t handle_release_count) {
+    GpuChannel* channel = channel_manager()->LookupChannel(kChannelId);
+    if (!channel)
+      return ClientDiscardableHandle();
+    CommandBufferStub* command_buffer =
+        channel->LookupCommandBuffer(kCommandBufferRouteId);
+    if (!command_buffer)
+      return ClientDiscardableHandle();
+    ClientDiscardableHandle handle(MakeBufferForTesting() /* buffer */,
+                                   0u /* byte_offset */,
+                                   GetNextBufferId() /* shm_id */);
+    scheduler()->ScheduleTask(Scheduler::Task(
+        command_buffer->sequence_id(),
+        base::BindOnce(
+            &ImageDecodeAcceleratorStubTest::RegisterDiscardableHandleBuffer,
+            weak_ptr_factory_.GetWeakPtr(), handle.shm_id(),
+            handle.BufferForTesting(), handle_release_count) /* closure */,
+        std::vector<SyncToken>() /* sync_token_fences */));
+    return handle;
+  }
+
+  // Sends a decode request IPC and returns a sync token that is expected to be
+  // released upon the completion of the decode. The caller is responsible for
+  // keeping track of the release count for the decode sync token
+  // (|decode_release_count|), the transfer cache entry ID
+  // (|transfer_cache_entry_id|), and the release count of the sync token that
+  // is signaled after the discardable handle's buffer has been registered in
+  // the TransferBufferManager. If the channel does not exist or the discardable
+  // handle can't be created, this function returns an empty sync token.
   SyncToken SendDecodeRequest(const gfx::Size& output_size,
-                              uint64_t release_count,
-                              uint32_t transfer_cache_entry_id) {
+                              uint64_t decode_release_count,
+                              uint32_t transfer_cache_entry_id,
+                              uint64_t handle_release_count) {
     GpuChannel* channel = channel_manager()->LookupChannel(kChannelId);
     if (!channel) {
       // It's possible that the channel was destroyed as part of an earlier
@@ -236,28 +294,23 @@
         CommandBufferIdFromChannelAndRoute(
             kChannelId, static_cast<int32_t>(
                             GpuChannelReservedRoutes::kImageDecodeAccelerator)),
-        release_count);
+        decode_release_count);
 
-    // We need a buffer to make sure that the ImageDecodeAcceleratorStub can
-    // create a ServiceDiscardableHandle.
-    CommandBufferStub* command_buffer =
-        channel->LookupCommandBuffer(kCommandBufferRouteId);
-    if (!command_buffer)
+    // Create a discardable handle and schedule its buffer's registration.
+    ClientDiscardableHandle handle =
+        CreateDiscardableHandle(handle_release_count);
+    if (!handle.IsValid())
       return SyncToken();
 
-    int32_t buffer_shm_id = GetNextBufferId();
-    scoped_refptr<Buffer> handle_buffer = MakeBufferForTesting();
-    command_buffer->RegisterTransferBufferForTest(buffer_shm_id,
-                                                  std::move(handle_buffer));
-
     // Send the IPC decode request.
     GpuChannelMsg_ScheduleImageDecode_Params decode_params;
     decode_params.encoded_data = std::vector<uint8_t>();
     decode_params.output_size = output_size;
     decode_params.raster_decoder_route_id = kCommandBufferRouteId;
     decode_params.transfer_cache_entry_id = transfer_cache_entry_id;
-    decode_params.discardable_handle_shm_id = buffer_shm_id;
-    decode_params.discardable_handle_shm_offset = 0u;
+    decode_params.discardable_handle_shm_id = handle.shm_id();
+    decode_params.discardable_handle_shm_offset = handle.byte_offset();
+    decode_params.discardable_handle_release_count = handle_release_count;
     decode_params.target_color_space = gfx::ColorSpace();
     decode_params.needs_mips = false;
 
@@ -312,6 +365,7 @@
 
  private:
   base::test::ScopedFeatureList feature_list_;
+  base::WeakPtrFactory<ImageDecodeAcceleratorStubTest> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ImageDecodeAcceleratorStubTest);
 };
@@ -330,11 +384,13 @@
         .Times(1);
   }
   const SyncToken decode1_sync_token = SendDecodeRequest(
-      gfx::Size(100, 100) /* output_size */, 1u /* release_count */,
-      1u /* transfer_cache_entry_id */);
+      gfx::Size(100, 100) /* output_size */, 1u /* decode_release_count */,
+      1u /* transfer_cache_entry_id */, 1u /* handle_release_count */);
+  ASSERT_TRUE(decode1_sync_token.HasData());
   const SyncToken decode2_sync_token = SendDecodeRequest(
-      gfx::Size(200, 200) /* output_size */, 2u /* release_count */,
-      2u /* transfer_cache_entry_id */);
+      gfx::Size(200, 200) /* output_size */, 2u /* decode_release_count */,
+      2u /* transfer_cache_entry_id */, 2u /* handle_release_count */);
+  ASSERT_TRUE(decode2_sync_token.HasData());
 
   // A decode sync token should not be released before a decode is finished.
   RunTasksUntilIdle();
@@ -378,14 +434,17 @@
         .Times(1);
   }
   const SyncToken decode1_sync_token = SendDecodeRequest(
-      gfx::Size(100, 100) /* output_size */, 1u /* release_count */,
-      1u /* transfer_cache_entry_id */);
+      gfx::Size(100, 100) /* output_size */, 1u /* decode_release_count */,
+      1u /* transfer_cache_entry_id */, 1u /* handle_release_count */);
+  ASSERT_TRUE(decode1_sync_token.HasData());
   const SyncToken decode2_sync_token = SendDecodeRequest(
-      gfx::Size(200, 200) /* output_size */, 2u /* release_count */,
-      2u /* transfer_cache_entry_id */);
+      gfx::Size(200, 200) /* output_size */, 2u /* decode_release_count */,
+      2u /* transfer_cache_entry_id */, 2u /* handle_release_count */);
+  ASSERT_TRUE(decode2_sync_token.HasData());
   const SyncToken decode3_sync_token = SendDecodeRequest(
-      gfx::Size(300, 300) /* output_size */, 3u /* release_count */,
-      3u /* transfer_cache_entry_id */);
+      gfx::Size(300, 300) /* output_size */, 3u /* decode_release_count */,
+      3u /* transfer_cache_entry_id */, 3u /* handle_release_count */);
+  ASSERT_TRUE(decode3_sync_token.HasData());
 
   // A decode sync token should not be released before a decode is finished.
   RunTasksUntilIdle();
@@ -425,14 +484,17 @@
         .Times(1);
   }
   const SyncToken decode1_sync_token = SendDecodeRequest(
-      gfx::Size(100, 100) /* output_size */, 1u /* release_count */,
-      1u /* transfer_cache_entry_id */);
+      gfx::Size(100, 100) /* output_size */, 1u /* decode_release_count */,
+      1u /* transfer_cache_entry_id */, 1u /* handle_release_count */);
+  ASSERT_TRUE(decode1_sync_token.HasData());
   const SyncToken decode2_sync_token = SendDecodeRequest(
-      gfx::Size(200, 200) /* output_size */, 2u /* release_count */,
-      2u /* transfer_cache_entry_id */);
+      gfx::Size(200, 200) /* output_size */, 2u /* decode_release_count */,
+      2u /* transfer_cache_entry_id */, 2u /* handle_release_count */);
+  ASSERT_TRUE(decode2_sync_token.HasData());
   const SyncToken decode3_sync_token = SendDecodeRequest(
-      gfx::Size(300, 300) /* output_size */, 3u /* release_count */,
-      3u /* transfer_cache_entry_id */);
+      gfx::Size(300, 300) /* output_size */, 3u /* decode_release_count */,
+      3u /* transfer_cache_entry_id */, 3u /* handle_release_count */);
+  ASSERT_TRUE(decode3_sync_token.HasData());
 
   // A decode sync token should not be released before a decode is finished.
   RunTasksUntilIdle();
@@ -455,15 +517,18 @@
   CheckTransferCacheEntries({});
 }
 
-TEST_F(ImageDecodeAcceleratorStubTest, OutOfOrderSyncTokens) {
+TEST_F(ImageDecodeAcceleratorStubTest, OutOfOrderDecodeSyncTokens) {
   EXPECT_CALL(image_decode_accelerator_worker_, DoDecode(gfx::Size(100, 100)))
       .Times(1);
   const SyncToken decode1_sync_token = SendDecodeRequest(
-      gfx::Size(100, 100) /* output_size */, 2u /* release_count */,
-      1u /* transfer_cache_entry_id */);
+      gfx::Size(100, 100) /* output_size */, 2u /* decode_release_count */,
+      1u /* transfer_cache_entry_id */, 1u /* handle_release_count */);
+  ASSERT_TRUE(decode1_sync_token.HasData());
+
   const SyncToken decode2_sync_token = SendDecodeRequest(
-      gfx::Size(200, 200) /* output_size */, 1u /* release_count */,
-      2u /* transfer_cache_entry_id */);
+      gfx::Size(200, 200) /* output_size */, 1u /* decode_release_count */,
+      2u /* transfer_cache_entry_id */, 2u /* handle_release_count */);
+  ASSERT_TRUE(decode2_sync_token.HasData());
 
   // We expect the destruction of the ImageDecodeAcceleratorStub, which also
   // implies that all decode sync tokens should be released.
@@ -476,10 +541,11 @@
   CheckTransferCacheEntries({});
 }
 
-TEST_F(ImageDecodeAcceleratorStubTest, ZeroReleaseCountSyncToken) {
+TEST_F(ImageDecodeAcceleratorStubTest, ZeroReleaseCountDecodeSyncToken) {
   const SyncToken decode_sync_token = SendDecodeRequest(
-      gfx::Size(100, 100) /* output_size */, 0u /* release_count */,
-      1u /* transfer_cache_entry_id */);
+      gfx::Size(100, 100) /* output_size */, 0u /* decode_release_count */,
+      1u /* transfer_cache_entry_id */, 1u /* handle_release_count */);
+  ASSERT_TRUE(decode_sync_token.HasData());
 
   // We expect the destruction of the ImageDecodeAcceleratorStub, which also
   // implies that all decode sync tokens should be released.
@@ -493,8 +559,9 @@
 
 TEST_F(ImageDecodeAcceleratorStubTest, ZeroWidthOutputSize) {
   const SyncToken decode_sync_token = SendDecodeRequest(
-      gfx::Size(0, 100) /* output_size */, 1u /* release_count */,
-      1u /* transfer_cache_entry_id */);
+      gfx::Size(0, 100) /* output_size */, 1u /* decode_release_count */,
+      1u /* transfer_cache_entry_id */, 1u /* handle_release_count */);
+  ASSERT_TRUE(decode_sync_token.HasData());
 
   // We expect the destruction of the ImageDecodeAcceleratorStub, which also
   // implies that all decode sync tokens should be released.
@@ -508,8 +575,9 @@
 
 TEST_F(ImageDecodeAcceleratorStubTest, ZeroHeightOutputSize) {
   const SyncToken decode_sync_token = SendDecodeRequest(
-      gfx::Size(100, 0) /* output_size */, 1u /* release_count */,
-      1u /* transfer_cache_entry_id */);
+      gfx::Size(100, 0) /* output_size */, 1u /* decode_release_count */,
+      1u /* transfer_cache_entry_id */, 1u /* handle_release_count */);
+  ASSERT_TRUE(decode_sync_token.HasData());
 
   // We expect the destruction of the ImageDecodeAcceleratorStub, which also
   // implies that all decode sync tokens should be released.
@@ -521,4 +589,60 @@
   CheckTransferCacheEntries({});
 }
 
+// Tests that we wait for a discardable handle's buffer to be registered before
+// we attempt to process the corresponding completed decode.
+TEST_F(ImageDecodeAcceleratorStubTest, WaitForDiscardableHandleRegistration) {
+  EXPECT_CALL(image_decode_accelerator_worker_, DoDecode(gfx::Size(100, 100)))
+      .Times(1);
+
+  // First, we disable the raster sequence so that we can control when to
+  // register the discardable handle's buffer by re-enabling the sequence.
+  GpuChannel* channel = channel_manager()->LookupChannel(kChannelId);
+  ASSERT_TRUE(channel);
+  const CommandBufferStub* command_buffer =
+      channel->LookupCommandBuffer(kCommandBufferRouteId);
+  ASSERT_TRUE(command_buffer);
+  const SequenceId raster_sequence_id = command_buffer->sequence_id();
+  scheduler()->DisableSequence(raster_sequence_id);
+
+  // Now we can send the decode request. This schedules the registration of the
+  // discardable handle, but it won't actually be registered until we re-enable
+  // the raster sequence later on.
+  const SyncToken decode_sync_token = SendDecodeRequest(
+      gfx::Size(100, 100) /* output_size */, 1u /* decode_release_count */,
+      1u /* transfer_cache_entry_id */, 1u /* handle_release_count */);
+  ASSERT_TRUE(decode_sync_token.HasData());
+
+  // A decode sync token should not be released before a decode is finished.
+  RunTasksUntilIdle();
+  EXPECT_FALSE(sync_point_manager()->IsSyncTokenReleased(decode_sync_token));
+
+  // Even when a decode is finished, the decode sync token shouldn't be released
+  // before the discardable handle's buffer is registered.
+  image_decode_accelerator_worker_.FinishOneDecode(true);
+  RunTasksUntilIdle();
+  EXPECT_FALSE(sync_point_manager()->IsSyncTokenReleased(decode_sync_token));
+
+  // Let's make sure that the channel and the command buffer are still alive
+  // because if we didn't wait for the discardable handle's buffer to be
+  // registered, we could have caused a channel teardown.
+  ASSERT_TRUE(channel_manager()->LookupChannel(kChannelId));
+  ASSERT_TRUE(channel_manager()
+                  ->LookupChannel(kChannelId)
+                  ->LookupCommandBuffer(kCommandBufferRouteId));
+
+  // Now let's register the discardable handle's buffer by re-enabling the
+  // raster sequence. This should trigger the processing of the completed decode
+  // and the subsequent release of the decode sync token.
+  scheduler()->EnableSequence(raster_sequence_id);
+  RunTasksUntilIdle();
+  EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode_sync_token));
+
+  // The channel should still exist at the end.
+  EXPECT_TRUE(channel_manager()->LookupChannel(kChannelId));
+
+  // Check that the decoded images are in the transfer cache.
+  CheckTransferCacheEntries({SkISize::Make(100, 100)});
+}
+
 }  // namespace gpu
diff --git a/headless/lib/browser/protocol/headless_devtools_session.cc b/headless/lib/browser/protocol/headless_devtools_session.cc
index 1fcf62a..c5ec413 100644
--- a/headless/lib/browser/protocol/headless_devtools_session.cc
+++ b/headless/lib/browser/protocol/headless_devtools_session.cc
@@ -52,7 +52,8 @@
   int call_id;
   std::string unused;
   std::unique_ptr<protocol::DictionaryValue> value =
-      protocol::DictionaryValue::cast(protocol::StringUtil::parseJSON(message));
+      protocol::DictionaryValue::cast(protocol::StringUtil::parseMessage(
+          message, client_->UsesBinaryProtocol()));
   if (!dispatcher_->parseCommand(value.get(), &call_id, &unused))
     return;
   pending_commands_[call_id] = std::move(callback);
@@ -69,7 +70,8 @@
     int call_id,
     std::unique_ptr<Serializable> message) {
   pending_commands_.erase(call_id);
-  client_->DispatchProtocolMessage(agent_host_, message->serialize());
+  bool binary = client_->UsesBinaryProtocol();
+  client_->DispatchProtocolMessage(agent_host_, message->serialize(binary));
 }
 
 void HeadlessDevToolsSession::fallThrough(int call_id,
@@ -82,7 +84,8 @@
 
 void HeadlessDevToolsSession::sendProtocolNotification(
     std::unique_ptr<Serializable> message) {
-  client_->DispatchProtocolMessage(agent_host_, message->serialize());
+  bool binary = client_->UsesBinaryProtocol();
+  client_->DispatchProtocolMessage(agent_host_, message->serialize(binary));
 }
 
 void HeadlessDevToolsSession::flushProtocolNotifications() {}
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index ead3911..dceacd65 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -3407,6 +3407,8 @@
     builders {
       mixins: "win-try"
       mixins: "goma-j150"
+      dimensions: "cores:32"
+
       name: "win-asan"
     }
     builders { mixins: "win-try" name: "win-jumbo-rel" }
diff --git a/ios/chrome/app/application_delegate/user_activity_handler_unittest.mm b/ios/chrome/app/application_delegate/user_activity_handler_unittest.mm
index bbab256..d5dd59d 100644
--- a/ios/chrome/app/application_delegate/user_activity_handler_unittest.mm
+++ b/ios/chrome/app/application_delegate/user_activity_handler_unittest.mm
@@ -705,7 +705,7 @@
   EXPECT_FALSE(getHandleStartupParametersHasBeenCalled());
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     ProgrammaticUserActivityHandlerTest,
     UserActivityHandlerTest,
     ::testing::Values(ExternalFilesLoadedInWebStateFeature::Enabled,
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc b/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc
index c64c504..0064f15 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc
@@ -226,7 +226,7 @@
 
   identity::IdentityManager* identity_manager =
       IdentityManagerFactory::GetForBrowserState(browser_state);
-  AccountInfo account_info = identity_manager->GetPrimaryAccountInfo();
+  CoreAccountInfo account_info = identity_manager->GetPrimaryAccountInfo();
   base::string16 username = base::UTF8ToUTF16(account_info.email);
 
   size_t browser_state_index =
diff --git a/ios/chrome/browser/signin/signin_browser_state_info_updater.mm b/ios/chrome/browser/signin/signin_browser_state_info_updater.mm
index 9f9e165..d9fc2c7 100644
--- a/ios/chrome/browser/signin/signin_browser_state_info_updater.mm
+++ b/ios/chrome/browser/signin/signin_browser_state_info_updater.mm
@@ -58,7 +58,7 @@
     return;
 
   if (identity_manager_->HasPrimaryAccount()) {
-    AccountInfo account_info = identity_manager_->GetPrimaryAccountInfo();
+    CoreAccountInfo account_info = identity_manager_->GetPrimaryAccountInfo();
     cache->SetAuthInfoOfBrowserStateAtIndex(
         index, account_info.gaia, base::UTF8ToUTF16(account_info.email));
   } else {
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller_unittest.mm b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller_unittest.mm
index 18f0a367..b8a9010d 100644
--- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller_unittest.mm
@@ -376,9 +376,9 @@
   FakeChromeSigninViewControllerDelegate* vc_delegate_;
 };
 
-INSTANTIATE_TEST_CASE_P(,
-                        ChromeSigninViewControllerTest,
-                        ::testing::ValuesIn(kUnifiedConsentParam));
+INSTANTIATE_TEST_SUITE_P(,
+                         ChromeSigninViewControllerTest,
+                         ::testing::ValuesIn(kUnifiedConsentParam));
 
 // Tests that all strings on the screen are either part of the consent string
 // list defined in FakeConsentAuditor::ExpectedConsentStringIds()), or are part
diff --git a/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller_unittest.mm b/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller_unittest.mm
index 80871a41..480c3b8 100644
--- a/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/toolbar_container/toolbar_container_view_controller_unittest.mm
@@ -300,7 +300,7 @@
   }
 }
 
-INSTANTIATE_TEST_CASE_P(,
-                        ToolbarContainerViewControllerTest,
-                        ::testing::Range(kEmptyConfig,
-                                         kToolbarContainerConfigMax));
+INSTANTIATE_TEST_SUITE_P(,
+                         ToolbarContainerViewControllerTest,
+                         ::testing::Range(kEmptyConfig,
+                                          kToolbarContainerConfigMax));
diff --git a/ios/chrome/browser/voice/voice_search_navigations_tab_helper_unittest.mm b/ios/chrome/browser/voice/voice_search_navigations_tab_helper_unittest.mm
index d390f68..ba88429 100644
--- a/ios/chrome/browser/voice/voice_search_navigations_tab_helper_unittest.mm
+++ b/ios/chrome/browser/voice/voice_search_navigations_tab_helper_unittest.mm
@@ -57,7 +57,7 @@
   EXPECT_FALSE(navigations()->IsExpectingVoiceSearch());
 }
 
-INSTANTIATE_TEST_CASE_P(ProgrammaticVoiceSearchNavigationsTest,
-                        VoiceSearchNavigationsTest,
-                        ::testing::Values(NavigationManagerChoice::LEGACY,
-                                          NavigationManagerChoice::WK_BASED));
+INSTANTIATE_TEST_SUITE_P(ProgrammaticVoiceSearchNavigationsTest,
+                         VoiceSearchNavigationsTest,
+                         ::testing::Values(NavigationManagerChoice::LEGACY,
+                                           NavigationManagerChoice::WK_BASED));
diff --git a/ios/net/cookies/OWNERS b/ios/net/cookies/OWNERS
new file mode 100644
index 0000000..7ca3582
--- /dev/null
+++ b/ios/net/cookies/OWNERS
@@ -0,0 +1,4 @@
+mrefaat@chromium.org
+
+# TEAM: ios-directory-owners@chromium.org
+# OS: iOS
diff --git a/ios/net/cookies/cookie_store_ios.h b/ios/net/cookies/cookie_store_ios.h
index ed06499..e7bb38f 100644
--- a/ios/net/cookies/cookie_store_ios.h
+++ b/ios/net/cookies/cookie_store_ios.h
@@ -95,9 +95,6 @@
                                      const net::CookieOptions& options,
                                      GetCookieListCallback callback) override;
   void GetAllCookiesAsync(GetCookieListCallback callback) override;
-  void DeleteCookieAsync(const GURL& url,
-                         const std::string& cookie_name,
-                         base::OnceClosure callback) override;
   void DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
                                   DeleteCallback callback) override;
   void DeleteAllCreatedInTimeRangeAsync(
diff --git a/ios/net/cookies/cookie_store_ios.mm b/ios/net/cookies/cookie_store_ios.mm
index 821c1a05..3cbabb6 100644
--- a/ios/net/cookies/cookie_store_ios.mm
+++ b/ios/net/cookies/cookie_store_ios.mm
@@ -385,33 +385,6 @@
                      weak_factory_.GetWeakPtr(), base::Passed(&callback)));
 }
 
-void CookieStoreIOS::DeleteCookieAsync(const GURL& url,
-                                       const std::string& cookie_name,
-                                       base::OnceClosure callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  // If cookies are not allowed, a CookieStoreIOS subclass should be used
-  // instead.
-  DCHECK(SystemCookiesAllowed());
-
-  __block base::OnceClosure shared_callback = std::move(callback);
-  base::WeakPtr<SystemCookieStore> weak_system_store =
-      system_store_->GetWeakPtr();
-  system_store_->GetCookiesForURLAsync(
-      url, base::BindOnce(^(NSArray<NSHTTPCookie*>* cookies) {
-        for (NSHTTPCookie* cookie in cookies) {
-          if ([cookie.name
-                  isEqualToString:base::SysUTF8ToNSString(cookie_name)] &&
-              weak_system_store) {
-            weak_system_store->DeleteCookieAsync(
-                cookie, SystemCookieStore::SystemCookieCallback());
-          }
-        }
-        if (!shared_callback.is_null())
-          std::move(shared_callback).Run();
-      }));
-}
-
 void CookieStoreIOS::DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
                                                 DeleteCallback callback) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
diff --git a/ios/net/cookies/cookie_store_ios_persistent.h b/ios/net/cookies/cookie_store_ios_persistent.h
index 617b951..46b5fef 100644
--- a/ios/net/cookies/cookie_store_ios_persistent.h
+++ b/ios/net/cookies/cookie_store_ios_persistent.h
@@ -54,9 +54,6 @@
                                      const net::CookieOptions& options,
                                      GetCookieListCallback callback) override;
   void GetAllCookiesAsync(GetCookieListCallback callback) override;
-  void DeleteCookieAsync(const GURL& url,
-                         const std::string& cookie_name,
-                         base::OnceClosure callback) override;
   void DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
                                   DeleteCallback callback) override;
   void DeleteAllCreatedInTimeRangeAsync(
diff --git a/ios/net/cookies/cookie_store_ios_persistent.mm b/ios/net/cookies/cookie_store_ios_persistent.mm
index 00e9fa7..d779f89 100644
--- a/ios/net/cookies/cookie_store_ios_persistent.mm
+++ b/ios/net/cookies/cookie_store_ios_persistent.mm
@@ -98,14 +98,6 @@
   cookie_monster()->GetAllCookiesAsync(std::move(callback));
 }
 
-void CookieStoreIOSPersistent::DeleteCookieAsync(const GURL& url,
-                                                 const std::string& cookie_name,
-                                                 base::OnceClosure callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  cookie_monster()->DeleteCookieAsync(url, cookie_name,
-                                      WrapClosure(std::move(callback)));
-}
-
 void CookieStoreIOSPersistent::DeleteCanonicalCookieAsync(
     const CanonicalCookie& cookie,
     DeleteCallback callback) {
diff --git a/ios/net/cookies/cookie_store_ios_persistent_unittest.mm b/ios/net/cookies/cookie_store_ios_persistent_unittest.mm
index e2bc911..ad12e14ac 100644
--- a/ios/net/cookies/cookie_store_ios_persistent_unittest.mm
+++ b/ios/net/cookies/cookie_store_ios_persistent_unittest.mm
@@ -56,18 +56,18 @@
   base::MessageLoop loop_;
 };
 
-INSTANTIATE_TYPED_TEST_CASE_P(PersistentCookieStoreIOS,
-                              CookieStoreTest,
-                              PersistentCookieStoreIOSTestTraits);
-INSTANTIATE_TYPED_TEST_CASE_P(PersistentCookieStoreIOS,
-                              CookieStoreChangeGlobalTest,
-                              PersistentCookieStoreIOSTestTraits);
-INSTANTIATE_TYPED_TEST_CASE_P(PersistentCookieStoreIOS,
-                              CookieStoreChangeUrlTest,
-                              PersistentCookieStoreIOSTestTraits);
-INSTANTIATE_TYPED_TEST_CASE_P(PersistentCookieStoreIOS,
-                              CookieStoreChangeNamedTest,
-                              PersistentCookieStoreIOSTestTraits);
+INSTANTIATE_TYPED_TEST_SUITE_P(PersistentCookieStoreIOS,
+                               CookieStoreTest,
+                               PersistentCookieStoreIOSTestTraits);
+INSTANTIATE_TYPED_TEST_SUITE_P(PersistentCookieStoreIOS,
+                               CookieStoreChangeGlobalTest,
+                               PersistentCookieStoreIOSTestTraits);
+INSTANTIATE_TYPED_TEST_SUITE_P(PersistentCookieStoreIOS,
+                               CookieStoreChangeUrlTest,
+                               PersistentCookieStoreIOSTestTraits);
+INSTANTIATE_TYPED_TEST_SUITE_P(PersistentCookieStoreIOS,
+                               CookieStoreChangeNamedTest,
+                               PersistentCookieStoreIOSTestTraits);
 
 namespace {
 
diff --git a/ios/net/cookies/cookie_store_ios_unittest.mm b/ios/net/cookies/cookie_store_ios_unittest.mm
index 819ef6e..bd9cfc42 100644
--- a/ios/net/cookies/cookie_store_ios_unittest.mm
+++ b/ios/net/cookies/cookie_store_ios_unittest.mm
@@ -71,18 +71,18 @@
   base::MessageLoop loop_;
 };
 
-INSTANTIATE_TYPED_TEST_CASE_P(CookieStoreIOS,
-                              CookieStoreTest,
-                              CookieStoreIOSTestTraits);
-INSTANTIATE_TYPED_TEST_CASE_P(CookieStoreIOS,
-                              CookieStoreChangeGlobalTest,
-                              CookieStoreIOSTestTraits);
-INSTANTIATE_TYPED_TEST_CASE_P(CookieStoreIOS,
-                              CookieStoreChangeUrlTest,
-                              CookieStoreIOSTestTraits);
-INSTANTIATE_TYPED_TEST_CASE_P(CookieStoreIOS,
-                              CookieStoreChangeNamedTest,
-                              CookieStoreIOSTestTraits);
+INSTANTIATE_TYPED_TEST_SUITE_P(CookieStoreIOS,
+                               CookieStoreTest,
+                               CookieStoreIOSTestTraits);
+INSTANTIATE_TYPED_TEST_SUITE_P(CookieStoreIOS,
+                               CookieStoreChangeGlobalTest,
+                               CookieStoreIOSTestTraits);
+INSTANTIATE_TYPED_TEST_SUITE_P(CookieStoreIOS,
+                               CookieStoreChangeUrlTest,
+                               CookieStoreIOSTestTraits);
+INSTANTIATE_TYPED_TEST_SUITE_P(CookieStoreIOS,
+                               CookieStoreChangeNamedTest,
+                               CookieStoreIOSTestTraits);
 
 namespace {
 
@@ -109,9 +109,6 @@
   net::CookieList cookie_list_;
 };
 
-void IgnoreBoolean(bool ignored) {
-}
-
 void IgnoreList(const net::CookieList& ignored,
                 const net::CookieStatusList& excluded_cookies) {}
 
@@ -295,12 +292,25 @@
   GetCookies(base::BindOnce(&IgnoreList));
   ClearCookies();
   SetCookie("abc=def");
-  EXPECT_EQ(1U, cookies_changed_.size());
-  EXPECT_EQ(1U, cookies_removed_.size());
-  store_->DeleteCookieAsync(kTestCookieURLFooBar, "abc",
-                            base::Bind(&IgnoreBoolean, false));
+  ASSERT_EQ(1U, cookies_changed_.size());
+  ASSERT_EQ(1U, cookies_removed_.size());
+  EXPECT_EQ("abc", cookies_changed_[0].Name());
+  EXPECT_EQ("def", cookies_changed_[0].Value());
+  EXPECT_FALSE(cookies_removed_[0]);
+
+  base::RunLoop run_loop;
+  store_->DeleteAllAsync(base::BindLambdaForTesting([&](uint32_t num_deleted) {
+    EXPECT_EQ(1U, num_deleted);
+    run_loop.Quit();
+  }));
+  run_loop.Run();
   CookieStoreIOS::NotifySystemCookiesChanged();
   base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(2U, cookies_changed_.size());
+  ASSERT_EQ(2U, cookies_removed_.size());
+  EXPECT_EQ("abc", cookies_changed_[1].Name());
+  EXPECT_EQ("def", cookies_changed_[1].Value());
+  EXPECT_TRUE(cookies_removed_[1]);
 }
 
 TEST_F(CookieStoreIOSTest, SameValueDoesNotCallHook) {
diff --git a/ios/net/cookies/ns_http_system_cookie_store_unittest.mm b/ios/net/cookies/ns_http_system_cookie_store_unittest.mm
index 2bf3a118..fc2a25e4 100644
--- a/ios/net/cookies/ns_http_system_cookie_store_unittest.mm
+++ b/ios/net/cookies/ns_http_system_cookie_store_unittest.mm
@@ -63,8 +63,8 @@
   std::unique_ptr<net::NSHTTPSystemCookieStore> store_;
 };
 
-INSTANTIATE_TYPED_TEST_CASE_P(NSHTTPSystemCookieStore,
-                              SystemCookieStoreTest,
-                              NSHTTPSystemCookieStoreTestDelegate);
+INSTANTIATE_TYPED_TEST_SUITE_P(NSHTTPSystemCookieStore,
+                               SystemCookieStoreTest,
+                               NSHTTPSystemCookieStoreTestDelegate);
 
 }  // namespace net
diff --git a/ios/net/cookies/system_cookie_store_unittest_template.h b/ios/net/cookies/system_cookie_store_unittest_template.h
index d0df77a..b0bc65a 100644
--- a/ios/net/cookies/system_cookie_store_unittest_template.h
+++ b/ios/net/cookies/system_cookie_store_unittest_template.h
@@ -159,7 +159,7 @@
   SystemCookieStoreTestDelegate delegate_;
 };
 
-TYPED_TEST_CASE_P(SystemCookieStoreTest);
+TYPED_TEST_SUITE_P(SystemCookieStoreTest);
 
 TYPED_TEST_P(SystemCookieStoreTest, SetCookieAsync) {
   if (!this->IsTestEnabled())
@@ -295,12 +295,12 @@
             cookie_store->GetCookieAcceptPolicy());
 }
 
-REGISTER_TYPED_TEST_CASE_P(SystemCookieStoreTest,
-                           SetCookieAsync,
-                           GetCookiesAsync,
-                           DeleteCookiesAsync,
-                           ClearCookiesAsync,
-                           GetCookieAcceptPolicy);
+REGISTER_TYPED_TEST_SUITE_P(SystemCookieStoreTest,
+                            SetCookieAsync,
+                            GetCookiesAsync,
+                            DeleteCookiesAsync,
+                            ClearCookiesAsync,
+                            GetCookieAcceptPolicy);
 
 }  // namespace net
 
diff --git a/ios/web/net/cookies/OWNERS b/ios/web/net/cookies/OWNERS
new file mode 100644
index 0000000..7ca3582
--- /dev/null
+++ b/ios/web/net/cookies/OWNERS
@@ -0,0 +1,4 @@
+mrefaat@chromium.org
+
+# TEAM: ios-directory-owners@chromium.org
+# OS: iOS
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index b379c95..068c83b 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -135,8 +135,8 @@
 };
 
 // Macro to simplify instantiation of parameterized tests.
-#define INSTANTIATE_TEST_CASES(cls)                      \
-  INSTANTIATE_TEST_CASE_P(                               \
+#define INSTANTIATE_TEST_SUITES(cls)                     \
+  INSTANTIATE_TEST_SUITE_P(                              \
       Programmatic##cls, cls,                            \
       ::testing::Values(NavigationManagerChoice::LEGACY, \
                         NavigationManagerChoice::WK_BASED));
@@ -329,7 +329,7 @@
   }
 }
 
-INSTANTIATE_TEST_CASES(CRWWebControllerTest);
+INSTANTIATE_TEST_SUITES(CRWWebControllerTest);
 
 // Test fixture to test JavaScriptDialogPresenter.
 class JavaScriptDialogPresenterTest : public ProgrammaticWebTestWithWebState {
@@ -421,7 +421,7 @@
   EXPECT_NSEQ(@"No", dialog.default_prompt_text);
 }
 
-INSTANTIATE_TEST_CASES(JavaScriptDialogPresenterTest);
+INSTANTIATE_TEST_SUITES(JavaScriptDialogPresenterTest);
 
 // Test fixture for testing visible security state.
 typedef ProgrammaticWebTestWithWebState CRWWebStateSecurityStateTest;
@@ -439,7 +439,7 @@
             observer.did_change_visible_security_state_info()->web_state);
 }
 
-INSTANTIATE_TEST_CASES(CRWWebStateSecurityStateTest);
+INSTANTIATE_TEST_SUITES(CRWWebStateSecurityStateTest);
 
 // Real WKWebView is required for CRWWebControllerInvalidUrlTest.
 typedef ProgrammaticWebTestWithWebState CRWWebControllerInvalidUrlTest;
@@ -455,7 +455,7 @@
   EXPECT_EQ(url, web_state()->GetLastCommittedURL());
 }
 
-INSTANTIATE_TEST_CASES(CRWWebControllerInvalidUrlTest);
+INSTANTIATE_TEST_SUITES(CRWWebControllerInvalidUrlTest);
 
 // Real WKWebView is required for CRWWebControllerMessageFromIFrame.
 typedef ProgrammaticWebTestWithWebState CRWWebControllerMessageFromIFrame;
@@ -473,7 +473,7 @@
        "frames['f'].__gCrWeb.message.invokeOnHost(bad_message);");
 }
 
-INSTANTIATE_TEST_CASES(CRWWebControllerMessageFromIFrame);
+INSTANTIATE_TEST_SUITES(CRWWebControllerMessageFromIFrame);
 
 // Real WKWebView is required for CRWWebControllerJSExecutionTest.
 typedef ProgrammaticWebTestWithWebController CRWWebControllerJSExecutionTest;
@@ -500,7 +500,7 @@
   EXPECT_FALSE(ExecuteJavaScript(@"window.test2"));
 }
 
-INSTANTIATE_TEST_CASES(CRWWebControllerJSExecutionTest);
+INSTANTIATE_TEST_SUITES(CRWWebControllerJSExecutionTest);
 
 // Test fixture to test decidePolicyForNavigationResponse:decisionHandler:
 // delegate method.
@@ -748,7 +748,7 @@
   EXPECT_EQ(kAbsolute, trust_level);
 }
 
-INSTANTIATE_TEST_CASES(CRWWebControllerResponseTest);
+INSTANTIATE_TEST_SUITES(CRWWebControllerResponseTest);
 
 // Test fixture to test decidePolicyForNavigationAction:decisionHandler:
 // decisionHandler's callback result.
@@ -819,7 +819,7 @@
       blob_url_request, WKNavigationActionPolicyAllow));
 }
 
-INSTANTIATE_TEST_CASES(CRWWebControllerPolicyDeciderTest);
+INSTANTIATE_TEST_SUITES(CRWWebControllerPolicyDeciderTest);
 
 // Test fixture for testing CRWWebController presenting native content.
 class CRWWebControllerNativeContentTest
@@ -899,7 +899,7 @@
             virtual_url);
 }
 
-INSTANTIATE_TEST_CASES(CRWWebControllerNativeContentTest);
+INSTANTIATE_TEST_SUITES(CRWWebControllerNativeContentTest);
 
 // Test fixture for window.open tests.
 class WindowOpenByDomTest : public ProgrammaticWebTestWithWebController {
@@ -989,7 +989,7 @@
   EXPECT_TRUE(delegate_.popups().empty());
 }
 
-INSTANTIATE_TEST_CASES(WindowOpenByDomTest);
+INSTANTIATE_TEST_SUITES(WindowOpenByDomTest);
 
 // Tests page title changes.
 typedef ProgrammaticWebTestWithWebState CRWWebControllerTitleTest;
@@ -1040,7 +1040,7 @@
   EXPECT_EQ("Title1", base::UTF16ToUTF8(web_state()->GetTitle()));
 }
 
-INSTANTIATE_TEST_CASES(CRWWebControllerTitleTest);
+INSTANTIATE_TEST_SUITES(CRWWebControllerTitleTest);
 
 // Test fixture for JavaScript execution.
 class ScriptExecutionTest : public ProgrammaticWebTestWithWebController {
@@ -1104,7 +1104,7 @@
   EXPECT_FALSE(ExecuteJavaScript(@"window.w"));
 };
 
-INSTANTIATE_TEST_CASES(ScriptExecutionTest);
+INSTANTIATE_TEST_SUITES(ScriptExecutionTest);
 
 // Fixture class to test WKWebView crashes.
 class CRWWebControllerWebProcessTest
@@ -1160,8 +1160,8 @@
   EXPECT_TRUE(web_state()->IsEvicted());
 };
 
-INSTANTIATE_TEST_CASES(CRWWebControllerWebProcessTest);
+INSTANTIATE_TEST_SUITES(CRWWebControllerWebProcessTest);
 
-#undef INSTANTIATE_TEST_CASES
+#undef INSTANTIATE_TEST_SUITES
 
 }  // namespace web
diff --git a/jingle/BUILD.gn b/jingle/BUILD.gn
index e878671..f08ce64 100644
--- a/jingle/BUILD.gn
+++ b/jingle/BUILD.gn
@@ -19,6 +19,7 @@
     "glue/utils.h",
   ]
   public_deps = [
+    "//services/network/public/mojom",
     "//third_party/webrtc_overrides",
   ]
   deps = [
@@ -26,7 +27,6 @@
     "//base",
     "//base/third_party/dynamic_annotations",
     "//net",
-    "//services/network/public/mojom",
     "//third_party/libjingle_xmpp:rtc_task_runner",
   ]
 
@@ -37,7 +37,7 @@
       "glue/network_service_async_socket.cc",
       "glue/network_service_config.cc",
     ]
-    deps -= [ "//services/network/public/mojom" ]
+    public_deps -= [ "//services/network/public/mojom" ]
   }
 }
 
diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc
index 3f16872..f7efeff6 100644
--- a/media/audio/win/audio_manager_win.cc
+++ b/media/audio/win/audio_manager_win.cc
@@ -19,7 +19,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
-#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/win/windows_version.h"
 #include "media/audio/audio_device_description.h"
@@ -80,6 +80,71 @@
   return 3;
 }
 
+static bool IsSupported(HRESULT hr) {
+  return hr != S_FALSE && SUCCEEDED(hr);
+}
+
+// Records bitstream output support to histograms. Follows information from:
+// https://docs.microsoft.com/en-us/windows/desktop/coreaudio/representing-formats-for-iec-61937-transmissions
+static void LogBitstreamOutputSupport() {
+  auto client = CoreAudioUtil::CreateClient(
+      AudioDeviceDescription::kDefaultDeviceId, eRender, eConsole);
+
+  // Happens if no audio output devices are available.
+  if (!client)
+    return;
+
+  WAVEFORMATEXTENSIBLE wfext;
+  memset(&wfext, 0, sizeof(wfext));
+
+  // See link in function comment for where each value comes from.
+  wfext.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+  wfext.Format.nChannels = 2;
+  wfext.Format.nSamplesPerSec = 192000;
+  wfext.Format.nAvgBytesPerSec = 768000;
+  wfext.Format.nBlockAlign = 4;
+  wfext.Format.wBitsPerSample = 16;
+  wfext.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
+  wfext.Samples.wValidBitsPerSample = 16;
+  wfext.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
+
+  // Test Dolby Digital+ / Atmos support. For whatever reason Atmos doesn't use
+  // the KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS_ATMOS SubFormat.
+  wfext.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS;
+
+  HRESULT hr = client->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,
+                                         &wfext.Format, nullptr);
+  base::UmaHistogramBoolean("Media.Audio.Bitstream.EAC3", IsSupported(hr));
+
+  // Test Dolby TrueHD.
+  wfext.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP;
+  hr = client->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfext.Format,
+                                 nullptr);
+  base::UmaHistogramBoolean("Media.Audio.Bitstream.TrueHD", IsSupported(hr));
+
+  // Test DTS-HD.
+  wfext.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD;
+  hr = client->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfext.Format,
+                                 nullptr);
+  base::UmaHistogramBoolean("Media.Audio.Bitstream.DTS-HD", IsSupported(hr));
+
+  // Older bitstream formats run at lower sampling rates.
+  wfext.Format.nSamplesPerSec = 48000;
+  wfext.Format.nAvgBytesPerSec = 192000;
+
+  // Test AC3.
+  wfext.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL;
+  hr = client->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfext.Format,
+                                 nullptr);
+  base::UmaHistogramBoolean("Media.Audio.Bitstream.AC3", IsSupported(hr));
+
+  // Test DTS.
+  wfext.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS;
+  hr = client->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfext.Format,
+                                 nullptr);
+  base::UmaHistogramBoolean("Media.Audio.Bitstream.DTS", IsSupported(hr));
+}
+
 AudioManagerWin::AudioManagerWin(std::unique_ptr<AudioThread> audio_thread,
                                  AudioLogFactory* audio_log_factory)
     : AudioManagerBase(std::move(audio_thread), audio_log_factory) {
@@ -131,6 +196,11 @@
 void AudioManagerWin::InitializeOnAudioThread() {
   DCHECK(GetTaskRunner()->BelongsToCurrentThread());
 
+  // Delay metrics recording to avoid any issues at startup.
+  GetTaskRunner()->PostDelayedTask(FROM_HERE,
+                                   base::BindOnce(&LogBitstreamOutputSupport),
+                                   base::TimeDelta::FromSeconds(15));
+
   // AudioDeviceListenerWin must be initialized on a COM thread.
   output_device_listener_.reset(new AudioDeviceListenerWin(BindToCurrentLoop(
       base::Bind(&AudioManagerWin::NotifyAllOutputDeviceChangeListeners,
diff --git a/media/gpu/android/image_reader_gl_owner.cc b/media/gpu/android/image_reader_gl_owner.cc
index 2971cd5eaf..5bb536c0 100644
--- a/media/gpu/android/image_reader_gl_owner.cc
+++ b/media/gpu/android/image_reader_gl_owner.cc
@@ -89,7 +89,7 @@
   // Set the width, height and format to some default value. This parameters
   // are/maybe overriden by the producer sending buffers to this imageReader's
   // Surface.
-  int32_t width = 1, height = 1, max_images = 3;
+  int32_t width = 1, height = 1, max_images = 4;
   AIMAGE_FORMATS format = secure_mode == SecureMode::kSecure
                               ? AIMAGE_FORMAT_PRIVATE
                               : AIMAGE_FORMAT_YUV_420_888;
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 29ba2544..6f11dfe 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -962,6 +962,7 @@
       "proxy_resolution/proxy_list.h",
       "proxy_resolution/proxy_resolution_service.cc",
       "proxy_resolution/proxy_resolution_service.h",
+      "proxy_resolution/proxy_resolve_dns_operation.h",
       "proxy_resolution/proxy_resolver.h",
       "proxy_resolution/proxy_resolver_error_observer.h",
       "proxy_resolution/proxy_resolver_factory.cc",
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index cbec3f9..5adbe4a 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -110,11 +110,6 @@
     std::move(callback).Run();
 }
 
-void MaybeRunCookieCallback(base::OnceClosure callback) {
-  if (callback)
-    std::move(callback).Run();
-}
-
 template <typename T>
 void MaybeRunCookieCallback(base::OnceCallback<void(const T&)> callback,
                             const T& result) {
@@ -496,19 +491,6 @@
       std::move(callback)));
 }
 
-void CookieMonster::DeleteCookieAsync(const GURL& url,
-                                      const std::string& cookie_name,
-                                      base::OnceClosure callback) {
-  DoCookieCallbackForURL(
-      base::BindOnce(
-          // base::Unretained is safe as DoCookieCallbackForURL stores
-          // the callback on |*this|, so the callback will not outlive
-          // the object.
-          &CookieMonster::DeleteCookie, base::Unretained(this), url,
-          cookie_name, std::move(callback)),
-      url);
-}
-
 void CookieMonster::DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
                                                DeleteCallback callback) {
   DoCookieCallback(base::BindOnce(
@@ -761,53 +743,6 @@
                      !options.exclude_httponly(), std::move(callback));
 }
 
-void CookieMonster::DeleteCookie(const GURL& url,
-                                 const std::string& cookie_name,
-                                 base::OnceClosure callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  if (!HasCookieableScheme(url)) {
-    // TODO(rdsmith): Would be good to provide a failure indication here.
-    MaybeRunCookieCallback(std::move(callback));
-    return;
-  }
-
-  CookieOptions options;
-  options.set_include_httponly();
-  options.set_same_site_cookie_mode(
-      CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
-  // Get the cookies for this host and its domain(s).
-  std::vector<CanonicalCookie*> cookie_ptrs;
-  std::vector<CanonicalCookie*> included_cookie_ptrs;
-  FindCookiesForRegistryControlledHost(url, &cookie_ptrs);
-  FilterCookiesWithOptions(url, options, &cookie_ptrs, &included_cookie_ptrs,
-                           nullptr);
-  std::set<CanonicalCookie*> matching_cookies;
-
-  for (auto* cookie : included_cookie_ptrs) {
-    DCHECK(cookie->IsOnPath(url.path()));
-    DCHECK(cookie->IsDomainMatch(url.host()));
-    if (cookie->Name() != cookie_name)
-      continue;
-    matching_cookies.insert(cookie);
-  }
-
-  for (auto it = cookies_.begin(); it != cookies_.end();) {
-    auto curit = it;
-    ++it;
-    if (matching_cookies.find(curit->second.get()) != matching_cookies.end()) {
-      InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPLICIT);
-    }
-  }
-
-  FlushStore(base::BindOnce(&MaybeRunDeleteCallback,
-                            weak_ptr_factory_.GetWeakPtr(),
-                            // No callback null check needed as BindOnce
-                            // is not being called and MaybeRunDeleteCallback
-                            // has its own check.
-                            std::move(callback)));
-}
-
 void CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie,
                                           DeleteCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index 071d7ff..151511f 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -168,9 +168,6 @@
                                      const CookieOptions& options,
                                      GetCookieListCallback callback) override;
   void GetAllCookiesAsync(GetCookieListCallback callback) override;
-  void DeleteCookieAsync(const GURL& url,
-                         const std::string& cookie_name,
-                         base::OnceClosure callback) override;
   void DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
                                   DeleteCallback callback) override;
   void DeleteAllCreatedInTimeRangeAsync(
@@ -389,10 +386,6 @@
                             const CookieOptions& options,
                             SetCookiesCallback callback);
 
-  void DeleteCookie(const GURL& url,
-                    const std::string& cookie_name,
-                    base::OnceClosure callback);
-
   void DeleteCanonicalCookie(const CanonicalCookie& cookie,
                              DeleteCallback callback);
 
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 956d65b..e149d79 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -900,9 +900,6 @@
 
 // TODO(erikwright): When the synchronous helpers 'GetCookies' etc. are removed,
 // rename these, removing the 'Action' suffix.
-ACTION_P4(DeleteCookieAction, cookie_monster, url, name, callback) {
-  cookie_monster->DeleteCookieAsync(url, name, callback->Get());
-}
 ACTION_P4(SetCookieAction, cookie_monster, url, cookie_line, callback) {
   cookie_monster->SetCookieWithOptionsAsync(url, cookie_line, CookieOptions(),
                                             callback->Get());
@@ -1136,26 +1133,6 @@
   loop.Run();
 }
 
-TEST_F(DeferredCookieTaskTest, DeferredDeleteCookie) {
-  MockClosure delete_cookie_callback;
-
-  BeginWithForDomainKey(
-      http_www_foo_.domain(),
-      DeleteCookieAction(&cookie_monster(), http_www_foo_.url(), "A",
-                         &delete_cookie_callback));
-
-  WaitForLoadCall();
-
-  EXPECT_CALL(delete_cookie_callback, Run())
-      .WillOnce(DeleteCookieAction(&cookie_monster(), http_www_foo_.url(), "X",
-                                   &delete_cookie_callback));
-  base::RunLoop loop;
-  EXPECT_CALL(delete_cookie_callback, Run()).WillOnce(QuitRunLoop(&loop));
-
-  CompleteLoading();
-  loop.Run();
-}
-
 TEST_F(DeferredCookieTaskTest, DeferredGetAllCookies) {
   DeclareLoadedCookie(http_www_foo_.url(),
                       "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT",
@@ -1870,30 +1847,6 @@
   EXPECT_EQ(1u, cookies.size());
 }
 
-TEST_F(CookieMonsterTest, DeleteCookieByName) {
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, &net_log_));
-
-  EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=A1; path=/"));
-  EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=A2; path=/foo"));
-  EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=A3; path=/bar"));
-  EXPECT_TRUE(SetCookie(cm.get(), http_bar_foo_.url(), "A=A4; path=/foo"));
-  EXPECT_TRUE(SetCookie(cm.get(), http_www_bar_.url(), "A=A5; path=/foo"));
-  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"));
-  EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "B=B3; path=/bar"));
-
-  DeleteCookie(cm.get(), http_www_foo_.AppendPath("foo/bar"), "A");
-
-  CookieList cookies = GetAllCookies(cm.get());
-  size_t expected_size = 6;
-  EXPECT_EQ(expected_size, cookies.size());
-  for (auto it = cookies.begin(); it != cookies.end(); ++it) {
-    EXPECT_NE("A1", it->Value());
-    EXPECT_NE("A2", it->Value());
-  }
-}
-
 // Tests importing from a persistent cookie store that contains duplicate
 // equivalent cookies. This situation should be handled by removing the
 // duplicate cookie (both from the in-memory cache, and from the backing store).
@@ -2100,10 +2053,10 @@
               cookie.http_only, cookie.same_site, cookie.priority),
           cookie.url.SchemeIsCryptographic(), true /*modify_httponly*/));
     }
-    GURL del_url(input_info[INPUT_DELETE]
-                     .url.Resolve(input_info[INPUT_DELETE].path)
-                     .spec());
-    DeleteCookie(cmout.get(), del_url, input_info[INPUT_DELETE].name);
+
+    EXPECT_TRUE(FindAndDeleteCookie(cmout.get(),
+                                    input_info[INPUT_DELETE].domain,
+                                    input_info[INPUT_DELETE].name));
   }
 
   // Create a new cookie monster and make sure that everything is correct
@@ -2731,10 +2684,11 @@
   EXPECT_EQ("A", store->commands()[2].cookie.Name());
   EXPECT_EQ("C", store->commands()[2].cookie.Value());
 
-  // Delete the cookie.
-  DeleteCookie(cm.get(), http_www_foo_.url(), "A");
+  // Delete the cookie. Using .host() here since it's a host and not domain
+  // cookie.
+  EXPECT_TRUE(FindAndDeleteCookie(cm.get(), http_www_foo_.host(), "A"));
   EXPECT_EQ("", GetCookies(cm.get(), http_www_foo_.url()));
-  EXPECT_EQ(4u, store->commands().size());
+  ASSERT_EQ(4u, store->commands().size());
   EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[3].type);
   EXPECT_EQ("A", store->commands()[3].cookie.Name());
   EXPECT_EQ("C", store->commands()[3].cookie.Value());
diff --git a/net/cookies/cookie_store.h b/net/cookies/cookie_store.h
index 7815dd18..b4b4ce4f 100644
--- a/net/cookies/cookie_store.h
+++ b/net/cookies/cookie_store.h
@@ -96,11 +96,6 @@
   // longest path, then by earliest creation date.
   virtual void GetAllCookiesAsync(GetCookieListCallback callback) = 0;
 
-  // Deletes all cookies that might apply to |url| that have |cookie_name|.
-  virtual void DeleteCookieAsync(const GURL& url,
-                                 const std::string& cookie_name,
-                                 base::OnceClosure callback) = 0;
-
   // Deletes one specific cookie. |cookie| must have been returned by a previous
   // query on this CookieStore. Invokes |callback| with 1 if a cookie was
   // deleted, 0 otherwise.
diff --git a/net/cookies/cookie_store_test_helpers.cc b/net/cookies/cookie_store_test_helpers.cc
index bc1593c..7261c7c 100644
--- a/net/cookies/cookie_store_test_helpers.cc
+++ b/net/cookies/cookie_store_test_helpers.cc
@@ -162,17 +162,6 @@
   return false;
 }
 
-void DelayedCookieMonster::DeleteCookie(const GURL& url,
-                                        const std::string& cookie_name) {
-  ADD_FAILURE();
-}
-
-void DelayedCookieMonster::DeleteCookieAsync(const GURL& url,
-                                             const std::string& cookie_name,
-                                             base::OnceClosure callback) {
-  ADD_FAILURE();
-}
-
 void DelayedCookieMonster::DeleteCanonicalCookieAsync(
     const CanonicalCookie& cookie,
     DeleteCallback callback) {
diff --git a/net/cookies/cookie_store_test_helpers.h b/net/cookies/cookie_store_test_helpers.h
index 2456814..293425e3 100644
--- a/net/cookies/cookie_store_test_helpers.h
+++ b/net/cookies/cookie_store_test_helpers.h
@@ -72,13 +72,6 @@
                                     const std::string& cookie_line,
                                     const CookieOptions& options);
 
-  virtual void DeleteCookie(const GURL& url,
-                            const std::string& cookie_name);
-
-  void DeleteCookieAsync(const GURL& url,
-                         const std::string& cookie_name,
-                         base::OnceClosure callback) override;
-
   void DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
                                   DeleteCallback callback) override;
 
diff --git a/net/cookies/cookie_store_unittest.h b/net/cookies/cookie_store_unittest.h
index 5c5fb91..e067abf 100644
--- a/net/cookies/cookie_store_unittest.h
+++ b/net/cookies/cookie_store_unittest.h
@@ -243,17 +243,6 @@
     return SetCookieWithOptions(cs, url, cookie_line, options);
   }
 
-  void DeleteCookie(CookieStore* cs,
-                    const GURL& url,
-                    const std::string& cookie_name) {
-    DCHECK(cs);
-    NoResultCookieCallback callback;
-    cs->DeleteCookieAsync(
-        url, cookie_name,
-        base::Bind(&NoResultCookieCallback::Run, base::Unretained(&callback)));
-    callback.WaitUntilDone();
-  }
-
   uint32_t DeleteCanonicalCookie(CookieStore* cs,
                                  const CanonicalCookie& cookie) {
     DCHECK(cs);
@@ -1602,31 +1591,6 @@
   ASSERT_TRUE(++it == cookies.end());
 }
 
-TYPED_TEST_P(CookieStoreTest, DeleteCookieAsync) {
-  CookieStore* cs = this->GetCookieStore();
-
-  EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "A=A1; path=/"));
-  EXPECT_TRUE(
-      this->SetCookie(cs, this->http_www_foo_.url(), "A=A2; path=/foo"));
-  EXPECT_TRUE(
-      this->SetCookie(cs, this->http_www_foo_.url(), "A=A3; path=/bar"));
-  EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "B=B1; path=/"));
-  EXPECT_TRUE(
-      this->SetCookie(cs, this->http_www_foo_.url(), "B=B2; path=/foo"));
-  EXPECT_TRUE(
-      this->SetCookie(cs, this->http_www_foo_.url(), "B=B3; path=/bar"));
-
-  this->DeleteCookie(cs, this->http_www_foo_.AppendPath("foo/bar"), "A");
-
-  CookieList cookies = this->GetAllCookies(cs);
-  size_t expected_size = 4;
-  EXPECT_EQ(expected_size, cookies.size());
-  for (const auto& cookie : cookies) {
-    EXPECT_NE("A1", cookie.Value());
-    EXPECT_NE("A2", cookie.Value());
-  }
-}
-
 TYPED_TEST_P(CookieStoreTest, DeleteCanonicalCookieAsync) {
   CookieStore* cs = this->GetCookieStore();
 
@@ -1722,7 +1686,6 @@
                            EmptyName,
                            CookieOrdering,
                            GetAllCookiesAsync,
-                           DeleteCookieAsync,
                            DeleteCanonicalCookieAsync,
                            DeleteSessionCookie);
 
diff --git a/net/dns/BUILD.gn b/net/dns/BUILD.gn
index 741a5b56..6584dac 100644
--- a/net/dns/BUILD.gn
+++ b/net/dns/BUILD.gn
@@ -291,6 +291,7 @@
       "dns_client.h",
       "dns_response.h",
       "dns_transaction.h",
+      "dns_util.h",
       "record_parsed.h",
       "record_rdata.h",
     ]
diff --git a/net/dns/dns_test_util.cc b/net/dns/dns_test_util.cc
index 016ebb7..e6a78a32 100644
--- a/net/dns/dns_test_util.cc
+++ b/net/dns/dns_test_util.cc
@@ -441,7 +441,8 @@
       const std::string& hostname,
       uint16_t qtype,
       DnsTransactionFactory::CallbackType callback,
-      const NetLogWithSource&) override {
+      const NetLogWithSource&,
+      SecureDnsMode) override {
     std::unique_ptr<MockTransaction> transaction =
         std::make_unique<MockTransaction>(rules_, hostname, qtype,
                                           std::move(callback));
diff --git a/net/dns/dns_transaction.cc b/net/dns/dns_transaction.cc
index 91b2fc6..242528e 100644
--- a/net/dns/dns_transaction.cc
+++ b/net/dns/dns_transaction.cc
@@ -794,11 +794,13 @@
                      uint16_t qtype,
                      DnsTransactionFactory::CallbackType callback,
                      const NetLogWithSource& net_log,
-                     const OptRecordRdata* opt_rdata)
+                     const OptRecordRdata* opt_rdata,
+                     SecureDnsMode secure_dns_mode)
       : session_(session),
         hostname_(hostname),
         qtype_(qtype),
         opt_rdata_(opt_rdata),
+        secure_dns_mode_(secure_dns_mode),
         callback_(std::move(callback)),
         net_log_(net_log),
         qnames_initial_size_(0),
@@ -941,12 +943,17 @@
   }
 
   AttemptResult MakeAttempt() {
-    // Make an HTTP attempt unless we have already made more attempts
-    // than we have configured servers. Otherwise make a UDP attempt
-    // as long as we have configured nameservers.
     DnsConfig config = session_->config();
-    if (doh_attempts_ < config.dns_over_https_servers.size())
+    // In AUTOMATIC and SECURE mode, make an HTTP attempt unless we have already
+    // made more attempts than we have configured servers.
+    if (secure_dns_mode_ != SecureDnsMode::OFF &&
+        doh_attempts_ < config.dns_over_https_servers.size()) {
       return MakeHTTPAttempt(config.dns_over_https_servers);
+    }
+    // In AUTOMATIC mode, insecure attempts are allowed after HTTP attempts are
+    // exhausted. In OFF mode, only insecure attempts are allowed. It should
+    // not be possible to reach this point in SECURE mode.
+    DCHECK_NE(secure_dns_mode_, SecureDnsMode::SECURE);
     DCHECK_GT(config.nameservers.size(), 0u);
     return MakeUDPAttempt();
   }
@@ -1134,8 +1141,19 @@
     if (had_tcp_attempt_)
       return false;
     const DnsConfig& config = session_->config();
-    return attempts_.size() < config.attempts * config.nameservers.size() +
-                                  config.dns_over_https_servers.size();
+    unsigned insecure_attempts_possible =
+        config.attempts * config.nameservers.size();
+    unsigned secure_attempts_possible = config.dns_over_https_servers.size();
+
+    switch (secure_dns_mode_) {
+      case SecureDnsMode::SECURE:
+        return attempts_.size() < secure_attempts_possible;
+      case SecureDnsMode::AUTOMATIC:
+        return attempts_.size() <
+               secure_attempts_possible + insecure_attempts_possible;
+      case SecureDnsMode::OFF:
+        return attempts_.size() < insecure_attempts_possible;
+    }
   }
 
   // Resolves the result of a DnsAttempt until a terminal result is reached
@@ -1226,6 +1244,7 @@
   std::string hostname_;
   uint16_t qtype_;
   const OptRecordRdata* opt_rdata_;
+  const SecureDnsMode secure_dns_mode_;
   // Cleared in DoCallback.
   DnsTransactionFactory::CallbackType callback_;
 
@@ -1270,10 +1289,11 @@
       const std::string& hostname,
       uint16_t qtype,
       CallbackType callback,
-      const NetLogWithSource& net_log) override {
-    return std::make_unique<DnsTransactionImpl>(session_.get(), hostname, qtype,
-                                                std::move(callback), net_log,
-                                                opt_rdata_.get());
+      const NetLogWithSource& net_log,
+      SecureDnsMode secure_dns_mode) override {
+    return std::make_unique<DnsTransactionImpl>(
+        session_.get(), hostname, qtype, std::move(callback), net_log,
+        opt_rdata_.get(), secure_dns_mode);
   }
 
   void AddEDNSOption(const OptRecordRdata::Opt& opt) override {
diff --git a/net/dns/dns_transaction.h b/net/dns/dns_transaction.h
index 12fab5e..c9ee1514 100644
--- a/net/dns/dns_transaction.h
+++ b/net/dns/dns_transaction.h
@@ -12,6 +12,7 @@
 
 #include "base/callback.h"
 #include "net/base/request_priority.h"
+#include "net/dns/dns_util.h"
 #include "net/dns/record_rdata.h"
 #include "url/gurl.h"
 
@@ -69,11 +70,18 @@
   //
   // The transaction will run |callback| upon asynchronous completion.
   // The |net_log| is used as the parent log.
+  //
+  // The |secure_dns_mode| specifies the order in which secure and/or insecure
+  // DNS lookups will be performed. In SECURE mode, only secure lookups will be
+  // perfomed. In AUTOMATIC mode, secure lookups will be performed first when
+  // possible, and insecure lookups will be performed as a fallback. In OFF
+  // mode, only insecure lookups will be performed.
   virtual std::unique_ptr<DnsTransaction> CreateTransaction(
       const std::string& hostname,
       uint16_t qtype,
       CallbackType callback,
-      const NetLogWithSource& net_log) WARN_UNUSED_RESULT = 0;
+      const NetLogWithSource& net_log,
+      SecureDnsMode secure_dns_mode) WARN_UNUSED_RESULT = 0;
 
   // The given EDNS0 option will be included in all DNS queries performed by
   // transactions from this factory.
diff --git a/net/dns/dns_transaction_unittest.cc b/net/dns/dns_transaction_unittest.cc
index 5d3c0ea..cfb46e3 100644
--- a/net/dns/dns_transaction_unittest.cc
+++ b/net/dns/dns_transaction_unittest.cc
@@ -246,7 +246,17 @@
     remote_endpoints_.push_back(endpoint);
   }
 
-  std::vector<IPEndPoint> remote_endpoints_;
+  struct RemoteNameserver {
+    RemoteNameserver(IPEndPoint insecure_nameserver)
+        : insecure_nameserver(insecure_nameserver) {}
+    RemoteNameserver(DnsConfig::DnsOverHttpsServerConfig secure_nameserver)
+        : secure_nameserver(secure_nameserver) {}
+
+    base::Optional<IPEndPoint> insecure_nameserver;
+    base::Optional<DnsConfig::DnsOverHttpsServerConfig> secure_nameserver;
+  };
+
+  std::vector<RemoteNameserver> remote_endpoints_;
   bool fail_next_socket_;
 
  private:
@@ -269,6 +279,7 @@
                     int expected_answer_count)
       : hostname_(hostname),
         qtype_(qtype),
+        secure_dns_mode_(SecureDnsMode::AUTOMATIC),
         response_(nullptr),
         expected_answer_count_(expected_answer_count),
         cancel_in_callback_(false),
@@ -277,13 +288,19 @@
   // Mark that the transaction shall be destroyed immediately upon callback.
   void set_cancel_in_callback() { cancel_in_callback_ = true; }
 
+  // Set the secure DNS mode for the transaction.
+  void set_secure_dns_mode(SecureDnsMode secure_dns_mode) {
+    secure_dns_mode_ = secure_dns_mode;
+  }
+
   void StartTransaction(DnsTransactionFactory* factory) {
     EXPECT_EQ(NULL, transaction_.get());
     transaction_ = factory->CreateTransaction(
         hostname_, qtype_,
         base::Bind(&TransactionHelper::OnTransactionComplete,
                    base::Unretained(this)),
-        NetLogWithSource::Make(&net_log_, net::NetLogSourceType::NONE));
+        NetLogWithSource::Make(&net_log_, net::NetLogSourceType::NONE),
+        secure_dns_mode_);
     transaction_->SetRequestContext(&request_context_);
     transaction_->SetRequestPriority(DEFAULT_PRIORITY);
     EXPECT_EQ(hostname_, transaction_->GetHostname());
@@ -360,6 +377,7 @@
  private:
   std::string hostname_;
   uint16_t qtype_;
+  SecureDnsMode secure_dns_mode_;
   std::unique_ptr<DnsTransaction> transaction_;
   const DnsResponse* response_;
   int expected_answer_count_;
@@ -669,9 +687,20 @@
   // |servers|.
   void CheckServerOrder(const unsigned* servers, size_t num_attempts) {
     ASSERT_EQ(num_attempts, socket_factory_->remote_endpoints_.size());
+    auto num_insecure_nameservers = session_->config().nameservers.size();
     for (size_t i = 0; i < num_attempts; ++i) {
-      EXPECT_EQ(socket_factory_->remote_endpoints_[i],
-                session_->config().nameservers[servers[i]]);
+      if (servers[i] < num_insecure_nameservers) {
+        // Check insecure server match.
+        EXPECT_EQ(
+            socket_factory_->remote_endpoints_[i].insecure_nameserver.value(),
+            session_->config().nameservers[servers[i]]);
+      } else {
+        // Check secure server match.
+        EXPECT_EQ(
+            socket_factory_->remote_endpoints_[i].secure_nameserver.value(),
+            session_->config()
+                .dns_over_https_servers[servers[i] - num_insecure_nameservers]);
+      }
     }
   }
 
@@ -762,6 +791,7 @@
       if (server.use_post && request->method() == "POST") {
         if (url_base == request->url().spec()) {
           server_found = true;
+          socket_factory_->remote_endpoints_.push_back(server);
         }
       } else if (!server.use_post && request->method() == "GET") {
         std::string prefix = url_base + "?dns=";
@@ -769,6 +799,7 @@
                                      request->url().spec().begin());
         if (mispair.first == prefix.end()) {
           server_found = true;
+          socket_factory_->remote_endpoints_.push_back(server);
         }
       }
     }
@@ -1552,6 +1583,43 @@
   TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
   SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailStart));
   EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
+  unsigned kOrder0[] = {1, 0};
+  CheckServerOrder(kOrder0, base::size(kOrder0));
+}
+
+TEST_F(DnsTransactionTest, HttpsPostFailNoUDPFallbackInSecureMode) {
+  config_.attempts = 1;
+  ConfigureNumServers(2);
+  ConfigDohServers(false /* clear_udp */, true /* use_post */, 2);
+  AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
+                           SYNCHRONOUS, Transport::HTTPS);
+  AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
+                           SYNCHRONOUS, Transport::HTTPS);
+  TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_FAILED);
+  helper0.set_secure_dns_mode(SecureDnsMode::SECURE);
+  SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailStart));
+  EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
+  unsigned kOrder0[] = {2, 3};
+  CheckServerOrder(kOrder0, base::size(kOrder0));
+}
+
+TEST_F(DnsTransactionTest, NoHttpsAttemptInOffMode) {
+  config_.attempts = 2;
+  ConfigureNumServers(2);
+  ConfigDohServers(false /* clear_udp */, true /* use_post */, 2);
+  AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
+                           SYNCHRONOUS, Transport::UDP);
+  AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
+                           SYNCHRONOUS, Transport::UDP);
+  AddQueryAndErrorResponse(0, kT0HostName, kT0Qtype, ERR_CONNECTION_REFUSED,
+                           SYNCHRONOUS, Transport::UDP);
+  AddQueryAndResponse(0, kT0HostName, kT0Qtype, kT0ResponseDatagram,
+                      base::size(kT0ResponseDatagram), ASYNC, Transport::UDP);
+  TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
+  helper0.set_secure_dns_mode(SecureDnsMode::OFF);
+  EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
+  unsigned kOrder0[] = {0, 1, 0, 1};
+  CheckServerOrder(kOrder0, base::size(kOrder0));
 }
 
 TEST_F(DnsTransactionTest, HttpsPostFailThenUDPFailThenUDPFallback) {
@@ -1575,6 +1643,8 @@
   EXPECT_EQ(session_->NextGoodServerIndex(0), 1u);
   EXPECT_EQ(session_->NextGoodServerIndex(1), 1u);
   EXPECT_EQ(session_->NextGoodServerIndex(2), 2u);
+  unsigned kOrder0[] = {3, 0, 1};
+  CheckServerOrder(kOrder0, base::size(kOrder0));
 }
 
 TEST_F(DnsTransactionTest, HttpsMarkUdpBad) {
@@ -1595,6 +1665,8 @@
   EXPECT_EQ(session_->NextGoodServerIndex(0), 1u);
   EXPECT_EQ(session_->NextGoodServerIndex(1), 1u);
   EXPECT_EQ(session_->NextGoodDnsOverHttpsServerIndex(2), 2u);
+  unsigned kOrder0[] = {2, 0, 1};
+  CheckServerOrder(kOrder0, base::size(kOrder0));
 
   AddQueryAndErrorResponse(1, kT1HostName, kT1Qtype, ERR_CONNECTION_REFUSED,
                            SYNCHRONOUS, Transport::HTTPS);
@@ -1612,6 +1684,11 @@
   EXPECT_EQ(session_->NextGoodServerIndex(0), 0u);
   EXPECT_EQ(session_->NextGoodServerIndex(1), 0u);
   EXPECT_EQ(session_->NextGoodDnsOverHttpsServerIndex(2), 2u);
+  unsigned kOrder1[] = {
+      2, 0, 1, /* transaction0 */
+      2, 1, 0  /* transaction1 */
+  };
+  CheckServerOrder(kOrder1, base::size(kOrder1));
 }
 
 TEST_F(DnsTransactionTest, HttpsMarkHttpsBad) {
@@ -1627,7 +1704,6 @@
                            SYNCHRONOUS, Transport::HTTPS);
   AddQueryAndErrorResponse(1, kT1HostName, kT1Qtype, ERR_CONNECTION_REFUSED,
                            SYNCHRONOUS, Transport::HTTPS);
-
   AddQueryAndResponse(1, kT1HostName, kT1Qtype, kT1ResponseDatagram,
                       base::size(kT1ResponseDatagram), ASYNC, Transport::HTTPS);
   TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
@@ -1640,6 +1716,8 @@
   EXPECT_EQ(session_->NextGoodDnsOverHttpsServerIndex(1), 3u);
   EXPECT_EQ(session_->NextGoodDnsOverHttpsServerIndex(2), 3u);
   EXPECT_EQ(session_->NextGoodDnsOverHttpsServerIndex(3), 3u);
+  unsigned kOrder0[] = {1, 2, 3};
+  CheckServerOrder(kOrder0, base::size(kOrder0));
 
   EXPECT_TRUE(helper1.RunUntilDone(transaction_factory_.get()));
   // Server 0 is still our only UDP server, so will be good by definition.
@@ -1651,6 +1729,11 @@
   EXPECT_EQ(session_->NextGoodDnsOverHttpsServerIndex(1), 2u);
   EXPECT_EQ(session_->NextGoodDnsOverHttpsServerIndex(2), 2u);
   EXPECT_EQ(session_->NextGoodDnsOverHttpsServerIndex(3), 2u);
+  unsigned kOrder1[] = {
+      1, 2, 3, /* transaction0 */
+      3, 1, 2  /* transaction1 */
+  };
+  CheckServerOrder(kOrder1, base::size(kOrder1));
 }
 
 TEST_F(DnsTransactionTest, HttpsPostFailThenHTTPFallback) {
@@ -1662,6 +1745,8 @@
                       Transport::HTTPS);
   TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
   EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
+  unsigned kOrder0[] = {0, 1};
+  CheckServerOrder(kOrder0, base::size(kOrder0));
 }
 
 TEST_F(DnsTransactionTest, HttpsPostFailTwiceThenUDPFallback) {
@@ -1678,6 +1763,8 @@
   TransactionHelper helper0(kT0HostName, kT0Qtype, kT0RecordCount);
   SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailStart));
   EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
+  unsigned kOrder0[] = {1, 2, 0};
+  CheckServerOrder(kOrder0, base::size(kOrder0));
 }
 
 TEST_F(DnsTransactionTest, HttpsPostFailTwice) {
@@ -1692,6 +1779,8 @@
   TransactionHelper helper0(kT0HostName, kT0Qtype, ERR_FAILED);
   SetDohJobMakerCallback(base::BindRepeating(DohJobMakerCallbackFailStart));
   EXPECT_TRUE(helper0.RunUntilDone(transaction_factory_.get()));
+  unsigned kOrder0[] = {0, 1};
+  CheckServerOrder(kOrder0, base::size(kOrder0));
 }
 
 void MakeResponseWithCookie(URLRequest* request, HttpResponseInfo* info) {
diff --git a/net/dns/dns_util.h b/net/dns/dns_util.h
index 6e29748..1aeb949 100644
--- a/net/dns/dns_util.h
+++ b/net/dns/dns_util.h
@@ -93,6 +93,18 @@
 NET_EXPORT DnsQueryType
 AddressFamilyToDnsQueryType(AddressFamily address_family);
 
+// The SecureDnsMode specifies what types of lookups (secure/insecure) should
+// be performed and in what order when resolving a specific query.
+enum SecureDnsMode : int {
+  // In OFF mode, no DoH lookups should be performed.
+  OFF,
+  // In AUTOMATIC mode, DoH lookups should be performed first if DoH is
+  // available, and insecure DNS lookups should be performed as a fallback.
+  AUTOMATIC,
+  // In SECURE mode, only DoH lookups should be performed.
+  SECURE,
+};
+
 }  // namespace net
 
 #endif  // NET_DNS_DNS_UTIL_H_
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index 0cf13d2..e64c46d3 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -1006,7 +1006,7 @@
             base::BindOnce(&DnsTask::OnTransactionComplete,
                            base::Unretained(this), tick_clock_->NowTicks(),
                            dns_query_type),
-            net_log_);
+            net_log_, SecureDnsMode::AUTOMATIC);
     trans->SetRequestContext(delegate_->url_request_context());
     trans->SetRequestPriority(delegate_->priority());
     return trans;
diff --git a/net/dns/host_resolver_impl_fuzzer.cc b/net/dns/host_resolver_impl_fuzzer.cc
index 902c615..a16bebc 100644
--- a/net/dns/host_resolver_impl_fuzzer.cc
+++ b/net/dns/host_resolver_impl_fuzzer.cc
@@ -27,11 +27,6 @@
 const char* kHostNames[] = {"foo", "foo.com",   "a.foo.com",
                             "bar", "localhost", "localhost6"};
 
-net::AddressFamily kAddressFamilies[] = {
-    net::ADDRESS_FAMILY_UNSPECIFIED, net::ADDRESS_FAMILY_IPV4,
-    net::ADDRESS_FAMILY_IPV6,
-};
-
 class DnsRequest {
  public:
   DnsRequest(net::HostResolver* host_resolver,
@@ -133,19 +128,6 @@
 
   // Starts the DNS request, using a fuzzed set of parameters.
   int Start() {
-    // Cache-only resolve still uses old HostResolver API.
-    if (data_provider_->ConsumeBool()) {
-      const char* hostname = data_provider_->PickValueInArray(kHostNames);
-      net::HostResolver::RequestInfo info(net::HostPortPair(hostname, 80));
-      info.set_address_family(
-          data_provider_->PickValueInArray(kAddressFamilies));
-      if (data_provider_->ConsumeBool())
-        info.set_host_resolver_flags(net::HOST_RESOLVER_CANONNAME);
-
-      return host_resolver_->ResolveFromCache(info, &address_list_,
-                                              net::NetLogWithSource());
-    }
-
     net::HostResolver::ResolveHostParameters parameters;
     parameters.dns_query_type =
         data_provider_->PickValueInArray(net::kDnsQueryTypes);
diff --git a/net/dns/mock_host_resolver.cc b/net/dns/mock_host_resolver.cc
index 87a4692..dbb22b3 100644
--- a/net/dns/mock_host_resolver.cc
+++ b/net/dns/mock_host_resolver.cc
@@ -453,6 +453,7 @@
       next_request_id_(1),
       num_resolve_(0),
       num_resolve_from_cache_(0),
+      num_non_local_resolves_(0),
       tick_clock_(base::DefaultTickClock::GetInstance()) {
   rules_map_[HostResolverSource::ANY] = CreateCatchAllHostResolverProc();
   rules_map_[HostResolverSource::SYSTEM] = CreateCatchAllHostResolverProc();
@@ -478,8 +479,10 @@
       request->parameters().cache_usage, &addresses, &stale_info);
   if (rv == OK && !request->parameters().is_speculative)
     request->set_address_results(addresses, std::move(stale_info));
-  if (rv != ERR_DNS_CACHE_MISS)
+  if (rv != ERR_DNS_CACHE_MISS ||
+      request->parameters().source == HostResolverSource::LOCAL_ONLY) {
     return rv;
+  }
 
   // Just like the real resolver, refuse to do anything with invalid
   // hostnames.
@@ -543,7 +546,11 @@
       cache_usage ==
           HostResolver::ResolveHostParameters::CacheUsage::STALE_ALLOWED;
   if (cache_.get() && cache_allowed) {
-    HostCache::Key key(host.host(), dns_query_type, flags, source);
+    // Local-only requests search the cache for non-local-only results.
+    HostResolverSource effective_source =
+        source == HostResolverSource::LOCAL_ONLY ? HostResolverSource::ANY
+                                                 : source;
+    HostCache::Key key(host.host(), dns_query_type, flags, effective_source);
     const HostCache::Entry* entry;
     HostCache::EntryStaleness stale_info = HostCache::kNotStale;
     if (cache_usage ==
@@ -570,6 +577,7 @@
                                       HostResolverSource source,
                                       AddressList* addresses) {
   DCHECK(rules_map_.find(source) != rules_map_.end());
+  ++num_non_local_resolves_;
 
   AddressList addr;
   int rv = rules_map_[source]->Resolve(host.host(), requested_address_family,
diff --git a/net/dns/mock_host_resolver.h b/net/dns/mock_host_resolver.h
index 9baa3f7..79c4dcf 100644
--- a/net/dns/mock_host_resolver.h
+++ b/net/dns/mock_host_resolver.h
@@ -177,6 +177,9 @@
     return num_resolve_from_cache_;
   }
 
+  // The number of times resolve was attempted non-locally.
+  size_t num_non_local_resolves() const { return num_non_local_resolves_; }
+
   // Returns the RequestPriority of the last call to Resolve() (or
   // DEFAULT_PRIORITY if Resolve() hasn't been called yet).
   RequestPriority last_request_priority() const {
@@ -250,6 +253,7 @@
 
   size_t num_resolve_;
   size_t num_resolve_from_cache_;
+  size_t num_non_local_resolves_;
 
   const base::TickClock* tick_clock_;
 
diff --git a/net/http/http_proxy_client_socket_wrapper.cc b/net/http/http_proxy_client_socket_wrapper.cc
index 4b3c9434..648643e0 100644
--- a/net/http/http_proxy_client_socket_wrapper.cc
+++ b/net/http/http_proxy_client_socket_wrapper.cc
@@ -78,7 +78,7 @@
           tunnel ? new HttpAuthController(
                        HttpAuth::AUTH_PROXY,
                        GURL((ssl_params_.get() ? "https://" : "http://") +
-                            GetDestination().host_port_pair().ToString()),
+                            GetDestination().ToString()),
                        http_auth_cache,
                        http_auth_handler_factory)
                  : nullptr),
@@ -531,9 +531,7 @@
 int HttpProxyClientSocketWrapper::DoSSLConnect() {
   DCHECK(ssl_params_);
   if (tunnel_) {
-    SpdySessionKey key(ssl_params_->GetDirectConnectionParams()
-                           ->destination()
-                           .host_port_pair(),
+    SpdySessionKey key(ssl_params_->GetDirectConnectionParams()->destination(),
                        ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
                        SpdySessionKey::IsProxySession::kTrue,
                        common_connect_job_params_.socket_tag);
@@ -631,8 +629,7 @@
   transport_socket_ =
       transport_pool_->client_socket_factory()->CreateProxyClientSocket(
           std::move(transport_socket_handle_), user_agent_, endpoint_,
-          ProxyServer(GetProxyServerScheme(),
-                      GetDestination().host_port_pair()),
+          ProxyServer(GetProxyServerScheme(), GetDestination()),
           http_auth_controller_.get(), tunnel_, using_spdy_,
           negotiated_protocol_, common_connect_job_params_.proxy_delegate,
           ssl_params_.get() != nullptr, traffic_annotation_);
@@ -651,11 +648,10 @@
   DCHECK(using_spdy_);
   DCHECK(tunnel_);
   DCHECK(ssl_params_);
-  SpdySessionKey key(
-      ssl_params_->GetDirectConnectionParams()->destination().host_port_pair(),
-      ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
-      SpdySessionKey::IsProxySession::kTrue,
-      common_connect_job_params_.socket_tag);
+  SpdySessionKey key(ssl_params_->GetDirectConnectionParams()->destination(),
+                     ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
+                     SpdySessionKey::IsProxySession::kTrue,
+                     common_connect_job_params_.socket_tag);
   base::WeakPtr<SpdySession> spdy_session =
       spdy_session_pool_->FindAvailableSession(
           key, /* enable_ip_based_pooling = */ true,
@@ -707,7 +703,7 @@
   DCHECK(tunnel_);
   next_state_ = STATE_QUIC_PROXY_CREATE_STREAM;
   const HostPortPair& proxy_server =
-      ssl_params_->GetDirectConnectionParams()->destination().host_port_pair();
+      ssl_params_->GetDirectConnectionParams()->destination();
   quic_stream_request_ =
       std::make_unique<QuicStreamRequest>(quic_stream_factory_);
   return quic_stream_request_->Request(
@@ -838,8 +834,7 @@
   std::move(callback).Run(ERR_CONNECTION_TIMED_OUT);
 }
 
-const HostResolver::RequestInfo&
-HttpProxyClientSocketWrapper::GetDestination() {
+const HostPortPair& HttpProxyClientSocketWrapper::GetDestination() {
   if (transport_params_) {
     return transport_params_->destination();
   } else {
diff --git a/net/http/http_proxy_client_socket_wrapper.h b/net/http/http_proxy_client_socket_wrapper.h
index 4b83bde..4134514 100644
--- a/net/http/http_proxy_client_socket_wrapper.h
+++ b/net/http/http_proxy_client_socket_wrapper.h
@@ -180,7 +180,7 @@
   void SetConnectTimer(base::TimeDelta duration);
   void ConnectTimeout();
 
-  const HostResolver::RequestInfo& GetDestination();
+  const HostPortPair& GetDestination();
 
   State next_state_;
 
diff --git a/net/http/http_stream_factory_job_controller_unittest.cc b/net/http/http_stream_factory_job_controller_unittest.cc
index c75e593f..48b6a89 100644
--- a/net/http/http_stream_factory_job_controller_unittest.cc
+++ b/net/http/http_stream_factory_job_controller_unittest.cc
@@ -95,21 +95,6 @@
   }
 };
 
-class FailingHostResolver : public MockHostResolverBase {
- public:
-  FailingHostResolver() : MockHostResolverBase(false /*use_caching*/) {}
-  ~FailingHostResolver() override = default;
-
-  int Resolve(const RequestInfo& info,
-              RequestPriority priority,
-              AddressList* addresses,
-              CompletionOnceCallback callback,
-              std::unique_ptr<Request>* out_req,
-              const NetLogWithSource& net_log) override {
-    return ERR_NAME_NOT_RESOLVED;
-  }
-};
-
 // A mock HttpServerProperties that always returns false for IsInitialized().
 class MockHttpServerProperties : public HttpServerPropertiesImpl {
  public:
diff --git a/net/nqe/network_quality_estimator_util.cc b/net/nqe/network_quality_estimator_util.cc
index 91f5fd1b..d12934f 100644
--- a/net/nqe/network_quality_estimator_util.cc
+++ b/net/nqe/network_quality_estimator_util.cc
@@ -4,12 +4,16 @@
 
 #include "net/nqe/network_quality_estimator_util.h"
 
-#include "net/base/address_list.h"
+#include <memory>
+
+#include "base/bind.h"
+#include "base/logging.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
 #include "net/dns/host_resolver.h"
+#include "net/dns/host_resolver_source.h"
 #include "net/log/net_log_with_source.h"
 
 namespace net {
@@ -21,18 +25,20 @@
 bool IsPrivateHost(HostResolver* host_resolver,
                    const HostPortPair& host_port_pair) {
   // Try resolving |host_port_pair.host()| synchronously.
-  HostResolver::RequestInfo resolve_info(host_port_pair);
-  resolve_info.set_allow_cached_response(true);
-  AddressList addresses;
-  // Resolve synchronously using the resolver's cache.
-  int rv = host_resolver->ResolveFromCache(resolve_info, &addresses,
-                                           NetLogWithSource());
+  HostResolver::ResolveHostParameters parameters;
+  parameters.source = HostResolverSource::LOCAL_ONLY;
+  std::unique_ptr<HostResolver::ResolveHostRequest> request =
+      host_resolver->CreateRequest(host_port_pair, NetLogWithSource(),
+                                   parameters);
 
+  int rv = request->Start(base::BindOnce([](int error) { NOTREACHED(); }));
   DCHECK_NE(rv, ERR_IO_PENDING);
-  if (rv == OK && !addresses.empty()) {
+
+  if (rv == OK && request->GetAddressResults() &&
+      !request->GetAddressResults().value().empty()) {
     // Checking only the first address should be sufficient.
-    IPEndPoint ip_end_point = addresses.front();
-    net::IPAddress ip_address = ip_end_point.address();
+    IPEndPoint ip_endpoint = request->GetAddressResults().value().front();
+    IPAddress ip_address = ip_endpoint.address();
     if (!ip_address.IsPubliclyRoutable())
       return true;
   }
diff --git a/net/nqe/network_quality_estimator_util_unittest.cc b/net/nqe/network_quality_estimator_util_unittest.cc
index 0cc8daa..0f464f9 100644
--- a/net/nqe/network_quality_estimator_util_unittest.cc
+++ b/net/nqe/network_quality_estimator_util_unittest.cc
@@ -72,30 +72,25 @@
     EXPECT_EQ(OK, callback.WaitForResult());
   }
 
-  EXPECT_EQ(2u, mock_host_resolver.num_resolve());
+  EXPECT_EQ(2u, mock_host_resolver.num_non_local_resolves());
 
   EXPECT_FALSE(IsPrivateHost(&mock_host_resolver,
                              HostPortPair("2607:f8b0:4006:819::200e", 80)));
-  EXPECT_EQ(1u, mock_host_resolver.num_resolve_from_cache());
 
   EXPECT_TRUE(
       IsPrivateHost(&mock_host_resolver, HostPortPair("192.168.0.1", 443)));
-  EXPECT_EQ(2u, mock_host_resolver.num_resolve_from_cache());
 
   EXPECT_FALSE(
       IsPrivateHost(&mock_host_resolver, HostPortPair("92.168.0.1", 443)));
-  EXPECT_EQ(3u, mock_host_resolver.num_resolve_from_cache());
 
   EXPECT_TRUE(
       IsPrivateHost(&mock_host_resolver, HostPortPair("example1.com", 443)));
-  EXPECT_EQ(4u, mock_host_resolver.num_resolve_from_cache());
 
   EXPECT_FALSE(
       IsPrivateHost(&mock_host_resolver, HostPortPair("example2.com", 443)));
-  EXPECT_EQ(5u, mock_host_resolver.num_resolve_from_cache());
 
   // IsPrivateHost() should have queried only the resolver's cache.
-  EXPECT_EQ(2u, mock_host_resolver.num_resolve());
+  EXPECT_EQ(2u, mock_host_resolver.num_non_local_resolves());
 }
 
 // Verify that IsPrivateHost() returns false for a hostname whose DNS
@@ -118,8 +113,7 @@
   // Not in DNS host cache, so should not be marked as private.
   EXPECT_FALSE(
       IsPrivateHost(&mock_host_resolver, HostPortPair("example3.com", 443)));
-  EXPECT_EQ(0u, mock_host_resolver.num_resolve());
-  EXPECT_EQ(1u, mock_host_resolver.num_resolve_from_cache());
+  EXPECT_EQ(0u, mock_host_resolver.num_non_local_resolves());
 
   {
     // Resolve example3.com so that the resolution entry is cached.
@@ -132,14 +126,13 @@
         NetLogWithSource());
     EXPECT_EQ(ERR_IO_PENDING, rv);
     EXPECT_EQ(OK, callback.WaitForResult());
-    EXPECT_EQ(1u, mock_host_resolver.num_resolve());
+    EXPECT_EQ(1u, mock_host_resolver.num_non_local_resolves());
   }
   EXPECT_TRUE(
       IsPrivateHost(&mock_host_resolver, HostPortPair("example3.com", 443)));
 
   // IsPrivateHost() should have queried only the resolver's cache.
-  EXPECT_EQ(1u, mock_host_resolver.num_resolve());
-  EXPECT_EQ(2u, mock_host_resolver.num_resolve_from_cache());
+  EXPECT_EQ(1u, mock_host_resolver.num_non_local_resolves());
 }
 
 // Verify that IsPrivateHost() returns correct results for local hosts.
diff --git a/net/proxy_resolution/mock_proxy_host_resolver.cc b/net/proxy_resolution/mock_proxy_host_resolver.cc
index d124c1e6..5b372d5 100644
--- a/net/proxy_resolution/mock_proxy_host_resolver.cc
+++ b/net/proxy_resolution/mock_proxy_host_resolver.cc
@@ -61,9 +61,8 @@
 MockProxyHostResolver::~MockProxyHostResolver() = default;
 
 std::unique_ptr<ProxyHostResolver::Request>
-MockProxyHostResolver::CreateRequest(
-    const std::string& hostname,
-    ProxyResolverV8::JSBindings::ResolveDnsOperation operation) {
+MockProxyHostResolver::CreateRequest(const std::string& hostname,
+                                     ProxyResolveDnsOperation operation) {
   ++num_resolve_;
 
   if (fail_all_)
@@ -78,17 +77,15 @@
   return std::make_unique<RequestImpl>(match->second, synchronous_mode_);
 }
 
-void MockProxyHostResolver::SetError(
-    const std::string& hostname,
-    ProxyResolverV8::JSBindings::ResolveDnsOperation operation) {
+void MockProxyHostResolver::SetError(const std::string& hostname,
+                                     ProxyResolveDnsOperation operation) {
   fail_all_ = false;
   results_[{hostname, operation}].clear();
 }
 
-void MockProxyHostResolver::SetResult(
-    const std::string& hostname,
-    ProxyResolverV8::JSBindings::ResolveDnsOperation operation,
-    std::vector<IPAddress> result) {
+void MockProxyHostResolver::SetResult(const std::string& hostname,
+                                      ProxyResolveDnsOperation operation,
+                                      std::vector<IPAddress> result) {
   DCHECK(!result.empty());
   fail_all_ = false;
   results_[{hostname, operation}] = std::move(result);
@@ -126,9 +123,8 @@
 HangingProxyHostResolver::~HangingProxyHostResolver() = default;
 
 std::unique_ptr<ProxyHostResolver::Request>
-HangingProxyHostResolver::CreateRequest(
-    const std::string& hostname,
-    ProxyResolverV8::JSBindings::ResolveDnsOperation operation) {
+HangingProxyHostResolver::CreateRequest(const std::string& hostname,
+                                        ProxyResolveDnsOperation operation) {
   return std::make_unique<RequestImpl>(this);
 }
 
diff --git a/net/proxy_resolution/mock_proxy_host_resolver.h b/net/proxy_resolution/mock_proxy_host_resolver.h
index 62598c3..cb3e87f0 100644
--- a/net/proxy_resolution/mock_proxy_host_resolver.h
+++ b/net/proxy_resolution/mock_proxy_host_resolver.h
@@ -14,7 +14,7 @@
 #include "base/callback_forward.h"
 #include "net/base/ip_address.h"
 #include "net/proxy_resolution/proxy_host_resolver.h"
-#include "net/proxy_resolution/proxy_resolver_v8.h"
+#include "net/proxy_resolution/proxy_resolve_dns_operation.h"
 
 namespace net {
 
@@ -30,13 +30,13 @@
 
   std::unique_ptr<Request> CreateRequest(
       const std::string& hostname,
-      ProxyResolverV8::JSBindings::ResolveDnsOperation operation) override;
+      ProxyResolveDnsOperation operation) override;
 
   void SetError(const std::string& hostname,
-                ProxyResolverV8::JSBindings::ResolveDnsOperation operation);
+                ProxyResolveDnsOperation operation);
 
   void SetResult(const std::string& hostname,
-                 ProxyResolverV8::JSBindings::ResolveDnsOperation operation,
+                 ProxyResolveDnsOperation operation,
                  std::vector<IPAddress> result);
 
   void FailAll();
@@ -44,8 +44,7 @@
   unsigned num_resolve() const { return num_resolve_; }
 
  private:
-  using ResultKey =
-      std::pair<std::string, ProxyResolverV8::JSBindings::ResolveDnsOperation>;
+  using ResultKey = std::pair<std::string, ProxyResolveDnsOperation>;
 
   class RequestImpl;
 
@@ -66,7 +65,7 @@
 
   std::unique_ptr<Request> CreateRequest(
       const std::string& hostname,
-      ProxyResolverV8::JSBindings::ResolveDnsOperation operation) override;
+      ProxyResolveDnsOperation operation) override;
 
   int num_cancelled_requests() const { return num_cancelled_requests_; }
 
diff --git a/net/proxy_resolution/proxy_host_resolver.h b/net/proxy_resolution/proxy_host_resolver.h
index 2f32efb..085a197 100644
--- a/net/proxy_resolution/proxy_host_resolver.h
+++ b/net/proxy_resolution/proxy_host_resolver.h
@@ -11,7 +11,7 @@
 
 #include "net/base/completion_once_callback.h"
 #include "net/base/ip_address.h"
-#include "net/proxy_resolution/proxy_resolver_v8.h"
+#include "net/proxy_resolution/proxy_resolve_dns_operation.h"
 
 namespace net {
 
@@ -30,7 +30,7 @@
 
   virtual std::unique_ptr<Request> CreateRequest(
       const std::string& hostname,
-      ProxyResolverV8::JSBindings::ResolveDnsOperation operation) = 0;
+      ProxyResolveDnsOperation operation) = 0;
 };
 
 }  // namespace net
diff --git a/net/proxy_resolution/proxy_resolve_dns_operation.h b/net/proxy_resolution/proxy_resolve_dns_operation.h
new file mode 100644
index 0000000..fdb8391f
--- /dev/null
+++ b/net/proxy_resolution/proxy_resolve_dns_operation.h
@@ -0,0 +1,19 @@
+// 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 NET_PROXY_RESOLUTION_PROXY_RESOLVE_DNS_OPERATION_H_
+#define NET_PROXY_RESOLUTION_PROXY_RESOLVE_DNS_OPERATION_H_
+
+namespace net {
+
+enum class ProxyResolveDnsOperation {
+  DNS_RESOLVE,
+  DNS_RESOLVE_EX,
+  MY_IP_ADDRESS,
+  MY_IP_ADDRESS_EX,
+};
+
+}  // namespace net
+
+#endif  // NET_PROXY_RESOLUTION_PROXY_RESOLVE_DNS_OPERATION_H_
diff --git a/net/proxy_resolution/proxy_resolver_v8.cc b/net/proxy_resolution/proxy_resolver_v8.cc
index af83f15..486b08d 100644
--- a/net/proxy_resolution/proxy_resolver_v8.cc
+++ b/net/proxy_resolution/proxy_resolver_v8.cc
@@ -701,41 +701,42 @@
   // V8 callback for when "myIpAddress()" is invoked by the PAC script.
   static void MyIpAddressCallback(
       const v8::FunctionCallbackInfo<v8::Value>& args) {
-    DnsResolveCallbackHelper(args, JSBindings::MY_IP_ADDRESS);
+    DnsResolveCallbackHelper(args, ProxyResolveDnsOperation::MY_IP_ADDRESS);
   }
 
   // V8 callback for when "myIpAddressEx()" is invoked by the PAC script.
   static void MyIpAddressExCallback(
       const v8::FunctionCallbackInfo<v8::Value>& args) {
-    DnsResolveCallbackHelper(args, JSBindings::MY_IP_ADDRESS_EX);
+    DnsResolveCallbackHelper(args, ProxyResolveDnsOperation::MY_IP_ADDRESS_EX);
   }
 
   // V8 callback for when "dnsResolve()" is invoked by the PAC script.
   static void DnsResolveCallback(
       const v8::FunctionCallbackInfo<v8::Value>& args) {
-    DnsResolveCallbackHelper(args, JSBindings::DNS_RESOLVE);
+    DnsResolveCallbackHelper(args, ProxyResolveDnsOperation::DNS_RESOLVE);
   }
 
   // V8 callback for when "dnsResolveEx()" is invoked by the PAC script.
   static void DnsResolveExCallback(
       const v8::FunctionCallbackInfo<v8::Value>& args) {
-    DnsResolveCallbackHelper(args, JSBindings::DNS_RESOLVE_EX);
+    DnsResolveCallbackHelper(args, ProxyResolveDnsOperation::DNS_RESOLVE_EX);
   }
 
   // Shared code for implementing:
   //   - myIpAddress(), myIpAddressEx(), dnsResolve(), dnsResolveEx().
   static void DnsResolveCallbackHelper(
       const v8::FunctionCallbackInfo<v8::Value>& args,
-      JSBindings::ResolveDnsOperation op) {
+      ProxyResolveDnsOperation op) {
     Context* context =
         static_cast<Context*>(v8::External::Cast(*args.Data())->Value());
 
     std::string hostname;
 
     // dnsResolve() and dnsResolveEx() need at least 1 argument.
-    if (op == JSBindings::DNS_RESOLVE || op == JSBindings::DNS_RESOLVE_EX) {
+    if (op == ProxyResolveDnsOperation::DNS_RESOLVE ||
+        op == ProxyResolveDnsOperation::DNS_RESOLVE_EX) {
       if (!GetHostnameArgument(args, &hostname)) {
-        if (op == JSBindings::DNS_RESOLVE)
+        if (op == ProxyResolveDnsOperation::DNS_RESOLVE)
           args.GetReturnValue().SetNull();
         return;
       }
@@ -762,17 +763,17 @@
 
     // Each function handles resolution errors differently.
     switch (op) {
-      case JSBindings::DNS_RESOLVE:
+      case ProxyResolveDnsOperation::DNS_RESOLVE:
         args.GetReturnValue().SetNull();
         return;
-      case JSBindings::DNS_RESOLVE_EX:
+      case ProxyResolveDnsOperation::DNS_RESOLVE_EX:
         args.GetReturnValue().SetEmptyString();
         return;
-      case JSBindings::MY_IP_ADDRESS:
+      case ProxyResolveDnsOperation::MY_IP_ADDRESS:
         args.GetReturnValue().Set(
             ASCIILiteralToV8String(args.GetIsolate(), "127.0.0.1"));
         return;
-      case JSBindings::MY_IP_ADDRESS_EX:
+      case ProxyResolveDnsOperation::MY_IP_ADDRESS_EX:
         args.GetReturnValue().SetEmptyString();
         return;
     }
diff --git a/net/proxy_resolution/proxy_resolver_v8.h b/net/proxy_resolution/proxy_resolver_v8.h
index 58490f82..da55956b 100644
--- a/net/proxy_resolution/proxy_resolver_v8.h
+++ b/net/proxy_resolution/proxy_resolver_v8.h
@@ -14,6 +14,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/strings/string16.h"
 #include "net/base/net_export.h"
+#include "net/proxy_resolution/proxy_resolve_dns_operation.h"
 
 class GURL;
 
@@ -27,13 +28,6 @@
   // Interface for the javascript bindings.
   class NET_EXPORT_PRIVATE JSBindings {
    public:
-    enum ResolveDnsOperation {
-      DNS_RESOLVE,
-      DNS_RESOLVE_EX,
-      MY_IP_ADDRESS,
-      MY_IP_ADDRESS_EX,
-    };
-
     JSBindings() {}
 
     // Handler for "dnsResolve()", "dnsResolveEx()", "myIpAddress()",
@@ -41,7 +35,7 @@
     // result. If |*terminate| is set to true, then the script execution will
     // be aborted. Note that termination may not happen right away.
     virtual bool ResolveDns(const std::string& host,
-                            ResolveDnsOperation op,
+                            ProxyResolveDnsOperation op,
                             std::string* output,
                             bool* terminate) = 0;
 
diff --git a/net/proxy_resolution/proxy_resolver_v8_tracing.cc b/net/proxy_resolution/proxy_resolver_v8_tracing.cc
index 485cd090f..d6f984b 100644
--- a/net/proxy_resolution/proxy_resolver_v8_tracing.cc
+++ b/net/proxy_resolution/proxy_resolver_v8_tracing.cc
@@ -28,6 +28,7 @@
 #include "net/log/net_log_with_source.h"
 #include "net/proxy_resolution/proxy_host_resolver.h"
 #include "net/proxy_resolution/proxy_info.h"
+#include "net/proxy_resolution/proxy_resolve_dns_operation.h"
 #include "net/proxy_resolution/proxy_resolver_error_observer.h"
 #include "net/proxy_resolution/proxy_resolver_v8.h"
 
@@ -157,43 +158,45 @@
 
   // Implementation of ProxyResolverv8::JSBindings
   bool ResolveDns(const std::string& host,
-                  ResolveDnsOperation op,
+                  ProxyResolveDnsOperation op,
                   std::string* output,
                   bool* terminate) override;
   void Alert(const base::string16& message) override;
   void OnError(int line_number, const base::string16& error) override;
 
   bool ResolveDnsBlocking(const std::string& host,
-                          ResolveDnsOperation op,
+                          ProxyResolveDnsOperation op,
                           std::string* output);
 
   bool ResolveDnsNonBlocking(const std::string& host,
-                             ResolveDnsOperation op,
+                             ProxyResolveDnsOperation op,
                              std::string* output,
                              bool* terminate);
 
   bool PostDnsOperationAndWait(const std::string& host,
-                               ResolveDnsOperation op,
+                               ProxyResolveDnsOperation op,
                                bool* completed_synchronously)
-                               WARN_UNUSED_RESULT;
+      WARN_UNUSED_RESULT;
 
   void DoDnsOperation();
   void OnDnsOperationComplete(int result);
 
   void ScheduleRestartWithBlockingDns();
 
-  bool GetDnsFromLocalCache(const std::string& host, ResolveDnsOperation op,
-                            std::string* output, bool* return_value);
+  bool GetDnsFromLocalCache(const std::string& host,
+                            ProxyResolveDnsOperation op,
+                            std::string* output,
+                            bool* return_value);
 
   void SaveDnsToLocalCache(const std::string& host,
-                           ResolveDnsOperation op,
+                           ProxyResolveDnsOperation op,
                            int net_error,
                            const std::vector<IPAddress>& addresses);
 
   // Makes a key for looking up |host, op| in |dns_cache_|. Strings are used for
   // convenience, to avoid defining custom comparators.
   static std::string MakeDnsCacheKey(const std::string& host,
-                                     ResolveDnsOperation op);
+                                     ProxyResolveDnsOperation op);
 
   void HandleAlertOrError(bool is_alert, int line_number,
                           const base::string16& message);
@@ -293,7 +296,7 @@
   // These are the inputs to DoDnsOperation(). Written on the worker thread,
   // read by the origin thread.
   std::string pending_dns_host_;
-  ResolveDnsOperation pending_dns_op_;
+  ProxyResolveDnsOperation pending_dns_op_;
 };
 
 class ProxyResolverV8TracingImpl : public ProxyResolverV8Tracing {
@@ -582,7 +585,7 @@
 }
 
 bool Job::ResolveDns(const std::string& host,
-                     ResolveDnsOperation op,
+                     ProxyResolveDnsOperation op,
                      std::string* output,
                      bool* terminate) {
   if (cancelled_.IsSet()) {
@@ -590,7 +593,9 @@
     return false;
   }
 
-  if ((op == DNS_RESOLVE || op == DNS_RESOLVE_EX) && host.empty()) {
+  if ((op == ProxyResolveDnsOperation::DNS_RESOLVE ||
+       op == ProxyResolveDnsOperation::DNS_RESOLVE_EX) &&
+      host.empty()) {
     // a DNS resolve with an empty hostname is considered an error.
     return false;
   }
@@ -609,7 +614,7 @@
 }
 
 bool Job::ResolveDnsBlocking(const std::string& host,
-                             ResolveDnsOperation op,
+                             ProxyResolveDnsOperation op,
                              std::string* output) {
   CheckIsOnWorkerThread();
 
@@ -635,7 +640,7 @@
 }
 
 bool Job::ResolveDnsNonBlocking(const std::string& host,
-                                ResolveDnsOperation op,
+                                ProxyResolveDnsOperation op,
                                 std::string* output,
                                 bool* terminate) {
   CheckIsOnWorkerThread();
@@ -688,7 +693,7 @@
 }
 
 bool Job::PostDnsOperationAndWait(const std::string& host,
-                                  ResolveDnsOperation op,
+                                  ProxyResolveDnsOperation op,
                                   bool* completed_synchronously) {
   // Post the DNS request to the origin thread.
   DCHECK(!pending_dns_);
@@ -716,7 +721,8 @@
     return;
 
   bool is_myip_request =
-      pending_dns_op_ == MY_IP_ADDRESS || pending_dns_op_ == MY_IP_ADDRESS_EX;
+      pending_dns_op_ == ProxyResolveDnsOperation::MY_IP_ADDRESS ||
+      pending_dns_op_ == ProxyResolveDnsOperation::MY_IP_ADDRESS_EX;
   pending_dns_ = host_resolver()->CreateRequest(
       is_myip_request ? GetHostName() : pending_dns_host_, pending_dns_op_);
   int result =
@@ -779,7 +785,7 @@
 }
 
 bool Job::GetDnsFromLocalCache(const std::string& host,
-                               ResolveDnsOperation op,
+                               ProxyResolveDnsOperation op,
                                std::string* output,
                                bool* return_value) {
   CheckIsOnWorkerThread();
@@ -794,7 +800,7 @@
 }
 
 void Job::SaveDnsToLocalCache(const std::string& host,
-                              ResolveDnsOperation op,
+                              ProxyResolveDnsOperation op,
                               int net_error,
                               const std::vector<IPAddress>& addresses) {
   CheckIsOnOriginThread();
@@ -803,7 +809,8 @@
   std::string cache_value;
   if (net_error != OK) {
     cache_value = std::string();
-  } else if (op == DNS_RESOLVE || op == MY_IP_ADDRESS) {
+  } else if (op == ProxyResolveDnsOperation::DNS_RESOLVE ||
+             op == ProxyResolveDnsOperation::MY_IP_ADDRESS) {
     // dnsResolve() and myIpAddress() are expected to return a single IP
     // address.
     cache_value = addresses.front().ToString();
@@ -820,7 +827,7 @@
 }
 
 std::string Job::MakeDnsCacheKey(const std::string& host,
-                                 ResolveDnsOperation op) {
+                                 ProxyResolveDnsOperation op) {
   return base::StringPrintf("%d:%s", op, host.c_str());
 }
 
diff --git a/net/proxy_resolution/proxy_resolver_v8_tracing_unittest.cc b/net/proxy_resolution/proxy_resolver_v8_tracing_unittest.cc
index 45a0cd3..a22a943 100644
--- a/net/proxy_resolution/proxy_resolver_v8_tracing_unittest.cc
+++ b/net/proxy_resolution/proxy_resolver_v8_tracing_unittest.cc
@@ -24,6 +24,7 @@
 #include "net/log/net_log_with_source.h"
 #include "net/proxy_resolution/mock_proxy_host_resolver.h"
 #include "net/proxy_resolution/proxy_info.h"
+#include "net/proxy_resolution/proxy_resolve_dns_operation.h"
 #include "net/test/event_waiter.h"
 #include "net/test/gtest_util.h"
 #include "net/test/test_with_scoped_task_environment.h"
@@ -290,22 +291,22 @@
   MockBindings mock_bindings(&host_resolver);
 
   host_resolver.SetResult(GetHostName(),
-                          ProxyResolverV8::JSBindings::MY_IP_ADDRESS,
+                          ProxyResolveDnsOperation::MY_IP_ADDRESS,
                           {IPAddress(122, 133, 144, 155)});
   host_resolver.SetResult(GetHostName(),
-                          ProxyResolverV8::JSBindings::MY_IP_ADDRESS_EX,
+                          ProxyResolveDnsOperation::MY_IP_ADDRESS_EX,
                           {IPAddress(133, 122, 100, 200)});
-  host_resolver.SetError("", ProxyResolverV8::JSBindings::DNS_RESOLVE);
-  host_resolver.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetError("", ProxyResolveDnsOperation::DNS_RESOLVE);
+  host_resolver.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(166, 155, 144, 44)});
   IPAddress v6_local;
   ASSERT_TRUE(v6_local.AssignFromIPLiteral("::1"));
-  host_resolver.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE_EX,
+  host_resolver.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE_EX,
                           {v6_local, IPAddress(192, 168, 1, 1)});
-  host_resolver.SetError("host2", ProxyResolverV8::JSBindings::DNS_RESOLVE);
-  host_resolver.SetResult("host3", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetError("host2", ProxyResolveDnsOperation::DNS_RESOLVE);
+  host_resolver.SetResult("host3", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(166, 155, 144, 33)});
-  host_resolver.SetError("host6", ProxyResolverV8::JSBindings::DNS_RESOLVE_EX);
+  host_resolver.SetError("host6", ProxyResolveDnsOperation::DNS_RESOLVE_EX);
 
   std::unique_ptr<ProxyResolverV8Tracing> resolver =
       CreateResolver(mock_bindings.CreateBindings(), "dns.js");
@@ -356,9 +357,9 @@
   MockProxyHostResolver host_resolver;
   MockBindings mock_bindings(&host_resolver);
 
-  host_resolver.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(166, 155, 144, 11)});
-  host_resolver.SetResult("crazy4", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("crazy4", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(133, 199, 111, 4)});
 
   std::unique_ptr<ProxyResolverV8Tracing> resolver =
@@ -395,13 +396,13 @@
   MockProxyHostResolver host_resolver;
   MockBindings mock_bindings(&host_resolver);
 
-  host_resolver.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(166, 155, 144, 11)});
-  host_resolver.SetResult("host2", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host2", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(166, 155, 144, 22)});
-  host_resolver.SetResult("host3", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host3", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(166, 155, 144, 33)});
-  host_resolver.SetResult("host4", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host4", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(166, 155, 144, 44)});
 
   std::unique_ptr<ProxyResolverV8Tracing> resolver =
@@ -435,7 +436,7 @@
 
   for (int i = 0; i < 21; ++i) {
     host_resolver.SetResult("host" + std::to_string(i),
-                            ProxyResolverV8::JSBindings::DNS_RESOLVE,
+                            ProxyResolveDnsOperation::DNS_RESOLVE,
                             {IPAddress(166, 155, 144, 11)});
   }
 
@@ -478,11 +479,11 @@
   MockBindings mock_bindings(&host_resolver);
 
   host_resolver.SetResult(GetHostName(),
-                          ProxyResolverV8::JSBindings::MY_IP_ADDRESS,
+                          ProxyResolveDnsOperation::MY_IP_ADDRESS,
                           {IPAddress(122, 133, 144, 155)});
   for (int i = 0; i < 21; ++i) {
     host_resolver.SetResult("host" + std::to_string(i),
-                            ProxyResolverV8::JSBindings::DNS_RESOLVE,
+                            ProxyResolveDnsOperation::DNS_RESOLVE,
                             {IPAddress(166, 155, 144, 11)});
   }
 
@@ -514,9 +515,9 @@
   MockProxyHostResolver host_resolver(synchronous_host_resolver);
   MockBindings mock_bindings(&host_resolver);
 
-  host_resolver.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(91, 13, 12, 1)});
-  host_resolver.SetResult("host2", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host2", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(91, 13, 12, 2)});
 
   std::unique_ptr<ProxyResolverV8Tracing> resolver =
@@ -525,9 +526,9 @@
   // Initialization did 2 dnsResolves.
   EXPECT_EQ(2u, host_resolver.num_resolve());
 
-  host_resolver.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(145, 88, 13, 3)});
-  host_resolver.SetResult("host2", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host2", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(137, 89, 8, 45)});
 
   TestCompletionCallback callback;
@@ -823,9 +824,9 @@
   MockProxyHostResolver host_resolver;
   MockBindings mock_bindings(&host_resolver);
 
-  host_resolver.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(182, 111, 0, 222)});
-  host_resolver.SetResult("host2", ProxyResolverV8::JSBindings::DNS_RESOLVE_EX,
+  host_resolver.SetResult("host2", ProxyResolveDnsOperation::DNS_RESOLVE_EX,
                           {IPAddress(111, 33, 44, 55)});
 
   std::unique_ptr<ProxyResolverV8Tracing> resolver =
@@ -861,22 +862,22 @@
   MockProxyHostResolver host_resolver0;
   MockBindings mock_bindings0(&host_resolver0);
   host_resolver0.SetResult(GetHostName(),
-                           ProxyResolverV8::JSBindings::MY_IP_ADDRESS,
+                           ProxyResolveDnsOperation::MY_IP_ADDRESS,
                            {IPAddress(122, 133, 144, 155)});
   host_resolver0.SetResult(GetHostName(),
-                           ProxyResolverV8::JSBindings::MY_IP_ADDRESS_EX,
+                           ProxyResolveDnsOperation::MY_IP_ADDRESS_EX,
                            {IPAddress(133, 122, 100, 200)});
-  host_resolver0.SetError("", ProxyResolverV8::JSBindings::DNS_RESOLVE);
-  host_resolver0.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver0.SetError("", ProxyResolveDnsOperation::DNS_RESOLVE);
+  host_resolver0.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE,
                            {IPAddress(166, 155, 144, 44)});
   IPAddress v6_local;
   ASSERT_TRUE(v6_local.AssignFromIPLiteral("::1"));
-  host_resolver0.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE_EX,
+  host_resolver0.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE_EX,
                            {v6_local, IPAddress(192, 168, 1, 1)});
-  host_resolver0.SetError("host2", ProxyResolverV8::JSBindings::DNS_RESOLVE);
-  host_resolver0.SetResult("host3", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver0.SetError("host2", ProxyResolveDnsOperation::DNS_RESOLVE);
+  host_resolver0.SetResult("host3", ProxyResolveDnsOperation::DNS_RESOLVE,
                            {IPAddress(166, 155, 144, 33)});
-  host_resolver0.SetError("host6", ProxyResolverV8::JSBindings::DNS_RESOLVE_EX);
+  host_resolver0.SetError("host6", ProxyResolveDnsOperation::DNS_RESOLVE_EX);
   std::unique_ptr<ProxyResolverV8Tracing> resolver0 =
       CreateResolver(mock_bindings0.CreateBindings(), "dns.js");
 
@@ -897,7 +898,7 @@
   // ------------------------
   MockProxyHostResolver host_resolver3;
   MockBindings mock_bindings3(&host_resolver3);
-  host_resolver3.SetResult("foo", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver3.SetResult("foo", ProxyResolveDnsOperation::DNS_RESOLVE,
                            {IPAddress(166, 155, 144, 33)});
   std::unique_ptr<ProxyResolverV8Tracing> resolver3 =
       CreateResolver(mock_bindings3.CreateBindings(), "simple_dns.js");
diff --git a/net/proxy_resolution/proxy_resolver_v8_tracing_wrapper_unittest.cc b/net/proxy_resolution/proxy_resolver_v8_tracing_wrapper_unittest.cc
index b3ebc8cc..13b4cd1 100644
--- a/net/proxy_resolution/proxy_resolver_v8_tracing_wrapper_unittest.cc
+++ b/net/proxy_resolution/proxy_resolver_v8_tracing_wrapper_unittest.cc
@@ -28,6 +28,7 @@
 #include "net/log/test_net_log_util.h"
 #include "net/proxy_resolution/mock_proxy_host_resolver.h"
 #include "net/proxy_resolution/proxy_info.h"
+#include "net/proxy_resolution/proxy_resolve_dns_operation.h"
 #include "net/proxy_resolution/proxy_resolver_error_observer.h"
 #include "net/test/event_waiter.h"
 #include "net/test/gtest_util.h"
@@ -313,22 +314,22 @@
   MockErrorObserver* error_observer = new MockErrorObserver;
 
   host_resolver.SetResult(GetHostName(),
-                          ProxyResolverV8::JSBindings::MY_IP_ADDRESS,
+                          ProxyResolveDnsOperation::MY_IP_ADDRESS,
                           {IPAddress(122, 133, 144, 155)});
   host_resolver.SetResult(GetHostName(),
-                          ProxyResolverV8::JSBindings::MY_IP_ADDRESS_EX,
+                          ProxyResolveDnsOperation::MY_IP_ADDRESS_EX,
                           {IPAddress(133, 122, 100, 200)});
-  host_resolver.SetError("", ProxyResolverV8::JSBindings::DNS_RESOLVE);
-  host_resolver.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetError("", ProxyResolveDnsOperation::DNS_RESOLVE);
+  host_resolver.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(166, 155, 144, 44)});
   IPAddress v6_local;
   ASSERT_TRUE(v6_local.AssignFromIPLiteral("::1"));
-  host_resolver.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE_EX,
+  host_resolver.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE_EX,
                           {v6_local, IPAddress(192, 168, 1, 1)});
-  host_resolver.SetError("host2", ProxyResolverV8::JSBindings::DNS_RESOLVE);
-  host_resolver.SetResult("host3", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetError("host2", ProxyResolveDnsOperation::DNS_RESOLVE);
+  host_resolver.SetResult("host3", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(166, 155, 144, 33)});
-  host_resolver.SetError("host6", ProxyResolverV8::JSBindings::DNS_RESOLVE_EX);
+  host_resolver.SetError("host6", ProxyResolveDnsOperation::DNS_RESOLVE_EX);
 
   std::unique_ptr<ProxyResolver> resolver = CreateResolver(
       &log, &host_resolver, base::WrapUnique(error_observer), "dns.js");
@@ -393,9 +394,9 @@
   MockProxyHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
 
-  host_resolver.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(166, 155, 144, 11)});
-  host_resolver.SetResult("crazy4", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("crazy4", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(133, 199, 111, 4)});
 
   std::unique_ptr<ProxyResolver> resolver =
@@ -448,13 +449,13 @@
   MockProxyHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
 
-  host_resolver.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(166, 155, 144, 11)});
-  host_resolver.SetResult("host2", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host2", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(166, 155, 144, 22)});
-  host_resolver.SetResult("host3", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host3", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(166, 155, 144, 33)});
-  host_resolver.SetResult("host4", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host4", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(166, 155, 144, 44)});
 
   std::unique_ptr<ProxyResolver> resolver =
@@ -495,7 +496,7 @@
 
   for (int i = 0; i < 21; ++i) {
     host_resolver.SetResult("host" + std::to_string(i),
-                            ProxyResolverV8::JSBindings::DNS_RESOLVE,
+                            ProxyResolveDnsOperation::DNS_RESOLVE,
                             {IPAddress(166, 155, 144, 11)});
   }
 
@@ -544,11 +545,11 @@
   MockErrorObserver* error_observer = new MockErrorObserver;
 
   host_resolver.SetResult(GetHostName(),
-                          ProxyResolverV8::JSBindings::MY_IP_ADDRESS,
+                          ProxyResolveDnsOperation::MY_IP_ADDRESS,
                           {IPAddress(122, 133, 144, 155)});
   for (int i = 0; i < 21; ++i) {
     host_resolver.SetResult("host" + std::to_string(i),
-                            ProxyResolverV8::JSBindings::DNS_RESOLVE,
+                            ProxyResolveDnsOperation::DNS_RESOLVE,
                             {IPAddress(166, 155, 144, 11)});
   }
 
@@ -584,9 +585,9 @@
   MockProxyHostResolver host_resolver(synchronous_host_resolver);
   MockErrorObserver* error_observer = new MockErrorObserver;
 
-  host_resolver.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(91, 13, 12, 1)});
-  host_resolver.SetResult("host2", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host2", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(91, 13, 12, 2)});
 
   std::unique_ptr<ProxyResolver> resolver =
@@ -596,9 +597,9 @@
   // Initialization did 2 dnsResolves.
   EXPECT_EQ(2u, host_resolver.num_resolve());
 
-  host_resolver.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(145, 88, 13, 3)});
-  host_resolver.SetResult("host2", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host2", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(137, 89, 8, 45)});
 
   TestCompletionCallback callback;
@@ -934,9 +935,9 @@
   MockProxyHostResolver host_resolver;
   MockErrorObserver* error_observer = new MockErrorObserver;
 
-  host_resolver.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE,
                           {IPAddress(182, 111, 0, 222)});
-  host_resolver.SetResult("host2", ProxyResolverV8::JSBindings::DNS_RESOLVE_EX,
+  host_resolver.SetResult("host2", ProxyResolveDnsOperation::DNS_RESOLVE_EX,
                           {IPAddress(111, 33, 44, 55)});
 
   std::unique_ptr<ProxyResolver> resolver = CreateResolver(
@@ -976,22 +977,22 @@
   // ------------------------
   MockProxyHostResolver host_resolver0;
   host_resolver0.SetResult(GetHostName(),
-                           ProxyResolverV8::JSBindings::MY_IP_ADDRESS,
+                           ProxyResolveDnsOperation::MY_IP_ADDRESS,
                            {IPAddress(122, 133, 144, 155)});
   host_resolver0.SetResult(GetHostName(),
-                           ProxyResolverV8::JSBindings::MY_IP_ADDRESS_EX,
+                           ProxyResolveDnsOperation::MY_IP_ADDRESS_EX,
                            {IPAddress(133, 122, 100, 200)});
-  host_resolver0.SetError("", ProxyResolverV8::JSBindings::DNS_RESOLVE);
-  host_resolver0.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver0.SetError("", ProxyResolveDnsOperation::DNS_RESOLVE);
+  host_resolver0.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE,
                            {IPAddress(166, 155, 144, 44)});
   IPAddress v6_local;
   ASSERT_TRUE(v6_local.AssignFromIPLiteral("::1"));
-  host_resolver0.SetResult("host1", ProxyResolverV8::JSBindings::DNS_RESOLVE_EX,
+  host_resolver0.SetResult("host1", ProxyResolveDnsOperation::DNS_RESOLVE_EX,
                            {v6_local, IPAddress(192, 168, 1, 1)});
-  host_resolver0.SetError("host2", ProxyResolverV8::JSBindings::DNS_RESOLVE);
-  host_resolver0.SetResult("host3", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver0.SetError("host2", ProxyResolveDnsOperation::DNS_RESOLVE);
+  host_resolver0.SetResult("host3", ProxyResolveDnsOperation::DNS_RESOLVE,
                            {IPAddress(166, 155, 144, 33)});
-  host_resolver0.SetError("host6", ProxyResolverV8::JSBindings::DNS_RESOLVE_EX);
+  host_resolver0.SetError("host6", ProxyResolveDnsOperation::DNS_RESOLVE_EX);
   std::unique_ptr<ProxyResolver> resolver0 =
       CreateResolver(nullptr, &host_resolver0,
                      std::make_unique<MockErrorObserver>(), "dns.js");
@@ -1014,7 +1015,7 @@
   // Setup resolver3
   // ------------------------
   MockProxyHostResolver host_resolver3;
-  host_resolver3.SetResult("foo", ProxyResolverV8::JSBindings::DNS_RESOLVE,
+  host_resolver3.SetResult("foo", ProxyResolveDnsOperation::DNS_RESOLVE,
                            {IPAddress(166, 155, 144, 33)});
   std::unique_ptr<ProxyResolver> resolver3 =
       CreateResolver(nullptr, &host_resolver3,
diff --git a/net/proxy_resolution/proxy_resolver_v8_unittest.cc b/net/proxy_resolution/proxy_resolver_v8_unittest.cc
index 7ea786a..2292f2c 100644
--- a/net/proxy_resolution/proxy_resolver_v8_unittest.cc
+++ b/net/proxy_resolution/proxy_resolver_v8_unittest.cc
@@ -42,30 +42,30 @@
   }
 
   bool ResolveDns(const std::string& host,
-                  ResolveDnsOperation op,
+                  ProxyResolveDnsOperation op,
                   std::string* output,
                   bool* terminate) override {
     *terminate = should_terminate;
 
-    if (op == MY_IP_ADDRESS) {
+    if (op == ProxyResolveDnsOperation::MY_IP_ADDRESS) {
       my_ip_address_count++;
       *output = my_ip_address_result;
       return !my_ip_address_result.empty();
     }
 
-    if (op == MY_IP_ADDRESS_EX) {
+    if (op == ProxyResolveDnsOperation::MY_IP_ADDRESS_EX) {
       my_ip_address_ex_count++;
       *output = my_ip_address_ex_result;
       return !my_ip_address_ex_result.empty();
     }
 
-    if (op == DNS_RESOLVE) {
+    if (op == ProxyResolveDnsOperation::DNS_RESOLVE) {
       dns_resolves.push_back(host);
       *output = dns_resolve_result;
       return !dns_resolve_result.empty();
     }
 
-    if (op == DNS_RESOLVE_EX) {
+    if (op == ProxyResolveDnsOperation::DNS_RESOLVE_EX) {
       dns_resolves_ex.push_back(host);
       *output = dns_resolve_ex_result;
       return !dns_resolve_ex_result.empty();
diff --git a/net/quic/bidirectional_stream_quic_impl_unittest.cc b/net/quic/bidirectional_stream_quic_impl_unittest.cc
index 014dfee..1dfb060 100644
--- a/net/quic/bidirectional_stream_quic_impl_unittest.cc
+++ b/net/quic/bidirectional_stream_quic_impl_unittest.cc
@@ -712,7 +712,8 @@
       QuicTestPacketMaker* maker) {
     std::unique_ptr<quic::QuicReceivedPacket> packet(
         maker->MakeRstPacket(packet_number, include_version, stream_id_,
-                             quic::QUIC_STREAM_CANCELLED, bytes_written));
+                             quic::QUIC_STREAM_CANCELLED, bytes_written,
+                             /*include_stop_sending_if_v99=*/true));
     DVLOG(2) << "packet(" << packet_number << "): " << std::endl
              << quic::QuicTextUtils::HexDump(packet->AsStringPiece());
     return packet;
diff --git a/net/quic/quic_chromium_client_session_test.cc b/net/quic/quic_chromium_client_session_test.cc
index 3a2ccfd..f12ef851 100644
--- a/net/quic/quic_chromium_client_session_test.cc
+++ b/net/quic/quic_chromium_client_session_test.cc
@@ -528,7 +528,8 @@
     quic_data.AddWrite(
         SYNCHRONOUS, client_maker_.MakeRstPacket(
                          3, true, GetNthClientInitiatedBidirectionalStreamId(0),
-                         quic::QUIC_RST_ACKNOWLEDGEMENT));
+                         quic::QUIC_STREAM_CANCELLED, 0,
+                         /*include_stop_sending_if_v99=*/false));
     // After the STREAM_ID_BLOCKED is sent, receive a MAX_STREAM_ID to increase
     // the limit.
     quic_data.AddRead(
@@ -568,6 +569,15 @@
                                GetNthClientInitiatedBidirectionalStreamId(0),
                                quic::QUIC_STREAM_CANCELLED, 0);
   session_->OnRstStream(rst);
+  if (version_ == quic::QUIC_VERSION_99) {
+    // For version99, to close the stream completely, we also must receive a
+    // STOP_SENDING frame:
+    quic::QuicStopSendingFrame stop_sending(
+        quic::kInvalidControlFrameId,
+        GetNthClientInitiatedBidirectionalStreamId(0),
+        quic::QUIC_STREAM_CANCELLED);
+    session_->OnStopSendingFrame(stop_sending);
+  }
   // Pump the message loop to read the max stream id packet.
   base::RunLoop().RunUntilIdle();
 
@@ -656,10 +666,13 @@
         SYNCHRONOUS,
         client_maker_.MakeStreamIdBlockedPacket(
             2, true, GetNthClientInitiatedBidirectionalStreamId(49)));
+    // This node receives the RST_STREAM+STOP_SENDING, it responds
+    // with only a RST_STREAM.
     quic_data.AddWrite(
         SYNCHRONOUS, client_maker_.MakeRstPacket(
                          3, true, GetNthClientInitiatedBidirectionalStreamId(0),
-                         quic::QUIC_RST_ACKNOWLEDGEMENT));
+                         quic::QUIC_STREAM_CANCELLED, 0,
+                         /*include_stop_sending_if_v99=*/false));
   } else {
     quic_data.AddWrite(
         SYNCHRONOUS, client_maker_.MakeRstPacket(
@@ -698,6 +711,15 @@
                                GetNthClientInitiatedBidirectionalStreamId(0),
                                quic::QUIC_STREAM_CANCELLED, 0);
   session_->OnRstStream(rst);
+  if (version_ == quic::QUIC_VERSION_99) {
+    // For version99, we require a STOP_SENDING as well as a RESET_STREAM to
+    // fully close the stream.
+    quic::QuicStopSendingFrame stop_sending(
+        quic::kInvalidControlFrameId,
+        GetNthClientInitiatedBidirectionalStreamId(0),
+        quic::QUIC_STREAM_CANCELLED);
+    session_->OnStopSendingFrame(stop_sending);
+  }
   EXPECT_EQ(kMaxOpenStreams - 1, session_->GetNumOpenOutgoingStreams());
 
   quic_data.Resume();
diff --git a/net/quic/quic_chromium_client_stream_test.cc b/net/quic/quic_chromium_client_stream_test.cc
index 45de6530..329fde9 100644
--- a/net/quic/quic_chromium_client_stream_test.cc
+++ b/net/quic/quic_chromium_client_stream_test.cc
@@ -373,13 +373,36 @@
       quic::kInvalidControlFrameId,
       quic::test::GetNthClientInitiatedBidirectionalStreamId(GetParam(), 0),
       quic::QUIC_STREAM_CANCELLED, 0);
-  EXPECT_CALL(
-      session_,
-      SendRstStream(
-          quic::test::GetNthClientInitiatedBidirectionalStreamId(GetParam(), 0),
-          quic::QUIC_RST_ACKNOWLEDGEMENT, 0));
-  stream_->OnStreamReset(rst);
+  if (GetParam() != quic::QUIC_VERSION_99) {
+    EXPECT_CALL(
+        session_,
+        SendRstStream(quic::test::GetNthClientInitiatedBidirectionalStreamId(
+                          GetParam(), 0),
+                      quic::QUIC_RST_ACKNOWLEDGEMENT, 0));
+  } else {
+    // Intercept & check that the call to the QuicConnection's OnStreamReast
+    // has correct stream ID and error code -- for V99/IETF Quic, it should
+    // have the STREAM_CANCELLED error code, not RST_ACK... Capture
+    // OnStreamReset (rather than SendRstStream) because the V99 path bypasses
+    // SendRstStream, calling SendRstStreamInner directly. Mocking
+    // SendRstStreamInner is problematic since the test relies on it to perform
+    // the closing operations and getting the stream in the correct state.
+    EXPECT_CALL(
+        *(static_cast<quic::test::MockQuicConnection*>(session_.connection())),
+        OnStreamReset(stream_->id(), quic::QUIC_STREAM_CANCELLED));
+  }
 
+  stream_->OnStreamReset(rst);
+  if (GetParam() == quic::QUIC_VERSION_99) {
+    // Make a STOP_SENDING frame and pass it to QUIC. For V99/IETF QUIC,
+    // we need both a REST_STREAM and a STOP_SENDING to effect a closed
+    // stream.
+    quic::QuicStopSendingFrame stop_sending_frame(
+        quic::kInvalidControlFrameId,
+        quic::test::GetNthClientInitiatedBidirectionalStreamId(GetParam(), 0),
+        quic::QUIC_STREAM_CANCELLED);
+    session_.OnStopSendingFrame(stop_sending_frame);
+  }
   EXPECT_FALSE(handle_->IsOpen());
   EXPECT_EQ(quic::QUIC_STREAM_CANCELLED, handle_->stream_error());
 }
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index f5bee85..334b38a 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -369,7 +369,8 @@
       quic::QuicRstStreamErrorCode error_code,
       size_t bytes_written) {
     return client_maker_.MakeRstPacket(num, false, stream_id, error_code,
-                                       bytes_written);
+                                       bytes_written,
+                                       /*include_stop_sending_if_v99=*/true);
   }
 
   std::unique_ptr<quic::QuicEncryptedPacket>
@@ -8480,7 +8481,8 @@
         SYNCHRONOUS,
         client_maker->MakeRstPacket(
             4, false, GetNthClientInitiatedBidirectionalStreamId(0),
-            quic::QUIC_STREAM_CANCELLED, client_data_offset));
+            quic::QUIC_STREAM_CANCELLED, client_data_offset,
+            /*include_stop_sending_if_v99=*/true));
 
     headers = client_maker->ConnectRequestHeaders("mail.example.org:443");
     headers["proxy-authorization"] = "Basic Zm9vOmJheg==";
diff --git a/net/quic/quic_proxy_client_socket_unittest.cc b/net/quic/quic_proxy_client_socket_unittest.cc
index 056d0016..ab8e4bd 100644
--- a/net/quic/quic_proxy_client_socket_unittest.cc
+++ b/net/quic/quic_proxy_client_socket_unittest.cc
@@ -280,6 +280,20 @@
         largest_received, smallest_received, least_unacked, kSendFeedback);
   }
 
+  std::unique_ptr<quic::QuicReceivedPacket> ConstructAckAndRstOnlyPacket(
+      uint64_t packet_number,
+      quic::QuicRstStreamErrorCode error_code,
+      uint64_t largest_received,
+      uint64_t smallest_received,
+      uint64_t least_unacked,
+      size_t bytes_written) {
+    return client_maker_.MakeAckAndRstPacket(
+        packet_number, !kIncludeVersion, client_data_stream_id1_, error_code,
+        largest_received, smallest_received, least_unacked, kSendFeedback,
+        bytes_written,
+        /*include_stop_sending=*/false);
+  }
+
   std::unique_ptr<quic::QuicReceivedPacket> ConstructAckAndRstPacket(
       uint64_t packet_number,
       quic::QuicRstStreamErrorCode error_code,
@@ -290,7 +304,8 @@
     return client_maker_.MakeAckAndRstPacket(
         packet_number, !kIncludeVersion, client_data_stream_id1_, error_code,
         largest_received, smallest_received, least_unacked, kSendFeedback,
-        bytes_written);
+        bytes_written,
+        /*include_stop_sending_if_v99=*/true);
   }
 
   std::unique_ptr<quic::QuicReceivedPacket> ConstructRstPacket(
@@ -299,7 +314,8 @@
       size_t bytes_written) {
     return client_maker_.MakeRstPacket(packet_number, !kIncludeVersion,
                                        client_data_stream_id1_, error_code,
-                                       bytes_written);
+                                       bytes_written,
+                                       /*include_stop_sending_if_v99=*/true);
   }
 
   std::unique_ptr<quic::QuicReceivedPacket> ConstructConnectRequestPacket(
@@ -386,7 +402,8 @@
       size_t bytes_written) {
     return server_maker_.MakeRstPacket(packet_number, !kIncludeVersion,
                                        client_data_stream_id1_, error_code,
-                                       bytes_written);
+                                       bytes_written,
+                                       /*include_stop_sending_if_v99=*/true);
   }
 
   std::unique_ptr<quic::QuicReceivedPacket> ConstructServerDataPacket(
@@ -1622,10 +1639,9 @@
     mock_quic_data_.AddWrite(
         ASYNC, ConstructAckAndMultipleDataFramesPacket(
                    3, 1, 1, 1, 0, {header, quic::QuicString(kMsg2, kLen2)}));
-    mock_quic_data_.AddWrite(
-        SYNCHRONOUS,
-        ConstructAckAndRstPacket(4, quic::QUIC_RST_ACKNOWLEDGEMENT, 2, 2, 1,
-                                 header.length() + kLen2));
+    mock_quic_data_.AddWrite(SYNCHRONOUS, ConstructAckAndRstOnlyPacket(
+                                              4, quic::QUIC_STREAM_CANCELLED, 2,
+                                              2, 1, header.length() + kLen2));
   }
 
   Initialize();
@@ -1757,10 +1773,9 @@
     mock_quic_data_.AddWrite(
         ASYNC, ConstructAckAndMultipleDataFramesPacket(
                    3, 1, 1, 1, 0, {header, quic::QuicString(kMsg1, kLen1)}));
-    mock_quic_data_.AddWrite(
-        SYNCHRONOUS,
-        ConstructAckAndRstPacket(4, quic::QUIC_RST_ACKNOWLEDGEMENT, 2, 2, 1,
-                                 header.length() + kLen1));
+    mock_quic_data_.AddWrite(SYNCHRONOUS, ConstructAckAndRstOnlyPacket(
+                                              4, quic::QUIC_STREAM_CANCELLED, 2,
+                                              2, 1, header.length() + kLen1));
   }
 
   Initialize();
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index a020a1f..63505fd 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -4622,7 +4622,8 @@
   socket_data1.AddWrite(
       SYNCHRONOUS, client_maker_.MakeRstPacket(
                        5, false, GetNthClientInitiatedBidirectionalStreamId(1),
-                       quic::QUIC_STREAM_CANCELLED, 0));
+                       quic::QUIC_STREAM_CANCELLED, 0,
+                       /*include_stop_sending_if_v99=*/true));
 
   socket_data1.AddSocketDataToFactory(socket_factory_.get());
 
@@ -4835,7 +4836,8 @@
   quic_data3.AddWrite(
       SYNCHRONOUS, client_maker_.MakeRstPacket(
                        5, false, GetNthClientInitiatedBidirectionalStreamId(0),
-                       quic::QUIC_STREAM_CANCELLED, 0));
+                       quic::QUIC_STREAM_CANCELLED, 0,
+                       /*include_stop_sending_if_v99=*/true));
   quic_data3.AddSocketDataToFactory(socket_factory_.get());
 
   // Fast forward to fire the migrate back timer and verify the session
@@ -5578,7 +5580,8 @@
   socket_data1.AddWrite(
       SYNCHRONOUS, client_maker_.MakeRstPacket(
                        4, false, GetNthClientInitiatedBidirectionalStreamId(1),
-                       quic::QUIC_STREAM_CANCELLED, 0));
+                       quic::QUIC_STREAM_CANCELLED, 0,
+                       /*include_stop_sending_if_v99=*/true));
 
   socket_data1.AddSocketDataToFactory(socket_factory_.get());
 
@@ -5704,7 +5707,8 @@
       SYNCHRONOUS,
       client_maker_.MakeRstPacket(packet_number++, true,
                                   GetNthClientInitiatedBidirectionalStreamId(1),
-                                  quic::QUIC_STREAM_CANCELLED, 0));
+                                  quic::QUIC_STREAM_CANCELLED, 0,
+                                  /*include_stop_sending_if_v99=*/true));
   socket_data1.AddRead(
       ASYNC,
       ConstructOkResponsePacket(
@@ -5845,7 +5849,8 @@
       SYNCHRONOUS,
       client_maker_.MakeRstPacket(packet_number++, true,
                                   GetNthClientInitiatedBidirectionalStreamId(1),
-                                  quic::QUIC_STREAM_CANCELLED, 0));
+                                  quic::QUIC_STREAM_CANCELLED, 0,
+                                  /*include_stop_sending_if_v99=*/true));
   socket_data1.AddWrite(
       SYNCHRONOUS,
       ConstructGetRequestPacket(packet_number++,
diff --git a/net/quic/quic_test_packet_maker.cc b/net/quic/quic_test_packet_maker.cc
index d0e5fcd8..a402151 100644
--- a/net/quic/quic_test_packet_maker.cc
+++ b/net/quic/quic_test_packet_maker.cc
@@ -192,7 +192,8 @@
     bool include_version,
     quic::QuicStreamId stream_id,
     quic::QuicRstStreamErrorCode error_code) {
-  return MakeRstPacket(num, include_version, stream_id, error_code, 0);
+  return MakeRstPacket(num, include_version, stream_id, error_code, 0,
+                       /*include_stop_sending_if_v99=*/true);
 }
 
 std::unique_ptr<quic::QuicReceivedPacket> QuicTestPacketMaker::MakeRstPacket(
@@ -200,7 +201,8 @@
     bool include_version,
     quic::QuicStreamId stream_id,
     quic::QuicRstStreamErrorCode error_code,
-    size_t bytes_written) {
+    size_t bytes_written,
+    bool include_stop_sending_if_v99) {
   quic::QuicPacketHeader header;
   header.destination_connection_id = connection_id_;
   header.destination_connection_id_length = GetDestinationConnectionIdLength();
@@ -221,7 +223,7 @@
   // The STOP_SENDING frame must be outside of the if (version==99) so that it
   // stays in scope until the packet is built.
   quic::QuicStopSendingFrame stop(1, stream_id, error_code);
-  if (version_ == quic::QUIC_VERSION_99) {
+  if (include_stop_sending_if_v99 && version_ == quic::QUIC_VERSION_99) {
     frames.push_back(quic::QuicFrame(&stop));
     DVLOG(1) << "Adding frame: " << frames.back();
   }
@@ -327,7 +329,8 @@
     bool send_feedback) {
   return MakeAckAndRstPacket(num, include_version, stream_id, error_code,
                              largest_received, smallest_received, least_unacked,
-                             send_feedback, 0);
+                             send_feedback, 0,
+                             /*include_stop_sending_if_v99=*/true);
 }
 
 std::unique_ptr<quic::QuicReceivedPacket>
@@ -340,7 +343,8 @@
     uint64_t smallest_received,
     uint64_t least_unacked,
     bool send_feedback,
-    size_t bytes_written) {
+    size_t bytes_written,
+    bool include_stop_sending_if_v99) {
   quic::QuicPacketHeader header;
   header.destination_connection_id = connection_id_;
   header.destination_connection_id_length = GetDestinationConnectionIdLength();
@@ -380,7 +384,7 @@
   // The STOP_SENDING frame must be outside of the if (version==99) so that it
   // stays in scope until the packet is built.
   quic::QuicStopSendingFrame stop(1, stream_id, error_code);
-  if (version_ == quic::QUIC_VERSION_99) {
+  if (version_ == quic::QUIC_VERSION_99 && include_stop_sending_if_v99) {
     frames.push_back(quic::QuicFrame(&stop));
     DVLOG(1) << "Adding frame: " << frames.back();
   }
diff --git a/net/quic/quic_test_packet_maker.h b/net/quic/quic_test_packet_maker.h
index 0504966..de0f4a7 100644
--- a/net/quic/quic_test_packet_maker.h
+++ b/net/quic/quic_test_packet_maker.h
@@ -84,7 +84,8 @@
       bool include_version,
       quic::QuicStreamId stream_id,
       quic::QuicRstStreamErrorCode error_code,
-      size_t bytes_written);
+      size_t bytes_written,
+      bool include_stop_sending_if_v99);
 
   std::unique_ptr<quic::QuicReceivedPacket> MakeRstAndRequestHeadersPacket(
       uint64_t num,
@@ -117,7 +118,8 @@
       uint64_t smallest_received,
       uint64_t least_unacked,
       bool send_feedback,
-      size_t bytes_written);
+      size_t bytes_written,
+      bool include_stop_sending_if_v99);
   std::unique_ptr<quic::QuicReceivedPacket> MakeRstAckAndConnectionClosePacket(
       uint64_t num,
       bool include_version,
diff --git a/net/socket/ssl_connect_job_unittest.cc b/net/socket/ssl_connect_job_unittest.cc
index c8d1d74..a86a748 100644
--- a/net/socket/ssl_connect_job_unittest.cc
+++ b/net/socket/ssl_connect_job_unittest.cc
@@ -370,7 +370,7 @@
   // Make resolution eventually fail, so old jobs can easily be removed from the
   // socket pool.
   host_resolver_.rules()->AddSimulatedFailure(
-      direct_transport_socket_params_->destination().hostname());
+      direct_transport_socket_params_->destination().host());
   for (int initial_priority = MINIMUM_PRIORITY;
        initial_priority <= MAXIMUM_PRIORITY; ++initial_priority) {
     SCOPED_TRACE(initial_priority);
@@ -602,7 +602,7 @@
   // Make resolution eventually fail, so old jobs can easily be removed from the
   // socket pool.
   host_resolver_.rules()->AddSimulatedFailure(
-      socks_socket_params_->transport_params()->destination().hostname());
+      socks_socket_params_->transport_params()->destination().host());
   for (int initial_priority = MINIMUM_PRIORITY;
        initial_priority <= MAXIMUM_PRIORITY; ++initial_priority) {
     SCOPED_TRACE(initial_priority);
@@ -694,7 +694,7 @@
   // Make resolution eventually fail, so old jobs can easily be removed from the
   // socket pool.
   host_resolver_.rules()->AddSimulatedFailure(
-      socks_socket_params_->transport_params()->destination().hostname());
+      socks_socket_params_->transport_params()->destination().host());
   for (int initial_priority = MINIMUM_PRIORITY;
        initial_priority <= MAXIMUM_PRIORITY; ++initial_priority) {
     SCOPED_TRACE(initial_priority);
diff --git a/net/socket/transport_connect_job.cc b/net/socket/transport_connect_job.cc
index 4071605..96b6642 100644
--- a/net/socket/transport_connect_job.cc
+++ b/net/socket/transport_connect_job.cc
@@ -14,7 +14,6 @@
 #include "base/strings/string_util.h"
 #include "base/trace_event/trace_event.h"
 #include "base/values.h"
-#include "net/base/host_port_pair.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
 #include "net/base/trace_constants.h"
@@ -50,10 +49,8 @@
     bool disable_resolver_cache,
     const OnHostResolutionCallback& host_resolution_callback)
     : destination_(host_port_pair),
-      host_resolution_callback_(host_resolution_callback) {
-  if (disable_resolver_cache)
-    destination_.set_allow_cached_response(false);
-}
+      disable_resolver_cache_(disable_resolver_cache),
+      host_resolution_callback_(host_resolution_callback) {}
 
 TransportSocketParams::~TransportSocketParams() = default;
 
@@ -134,7 +131,7 @@
   // Also record any attempts made on either of the sockets.
   ConnectionAttempts attempts;
   if (resolve_result_ != OK) {
-    DCHECK_EQ(0u, addresses_.size());
+    DCHECK(!request_->GetAddressResults());
     attempts.push_back(ConnectionAttempt(IPEndPoint(), resolve_result_));
   }
   attempts.insert(attempts.begin(), connection_attempts_.begin(),
@@ -254,11 +251,17 @@
   next_state_ = STATE_RESOLVE_HOST_COMPLETE;
   connect_timing_.dns_start = base::TimeTicks::Now();
 
-  return host_resolver()->Resolve(
-      params_->destination(), priority(), &addresses_,
-      base::BindOnce(&TransportConnectJob::OnIOComplete,
-                     base::Unretained(this)),
-      &request_, net_log());
+  HostResolver::ResolveHostParameters parameters;
+  parameters.initial_priority = priority();
+  parameters.cache_usage =
+      params_->disable_resolver_cache()
+          ? HostResolver::ResolveHostParameters::CacheUsage::DISALLOWED
+          : HostResolver::ResolveHostParameters::CacheUsage::ALLOWED;
+  request_ = host_resolver()->CreateRequest(params_->destination(), net_log(),
+                                            parameters);
+
+  return request_->Start(base::BindOnce(&TransportConnectJob::OnIOComplete,
+                                        base::Unretained(this)));
 }
 
 int TransportConnectJob::DoResolveHostComplete(int result) {
@@ -272,10 +275,12 @@
 
   if (result != OK)
     return result;
+  DCHECK(request_->GetAddressResults());
 
   // Invoke callback, and abort if it fails.
   if (!params_->host_resolution_callback().is_null()) {
-    result = params_->host_resolution_callback().Run(addresses_, net_log());
+    result = params_->host_resolution_callback().Run(
+        request_->GetAddressResults().value(), net_log());
     if (result != OK)
       return result;
   }
@@ -291,18 +296,21 @@
   if (socket_performance_watcher_factory()) {
     socket_performance_watcher =
         socket_performance_watcher_factory()->CreateSocketPerformanceWatcher(
-            SocketPerformanceWatcherFactory::PROTOCOL_TCP, addresses_);
+            SocketPerformanceWatcherFactory::PROTOCOL_TCP,
+            request_->GetAddressResults().value());
   }
   transport_socket_ = client_socket_factory()->CreateTransportClientSocket(
-      addresses_, std::move(socket_performance_watcher), net_log().net_log(),
+      request_->GetAddressResults().value(),
+      std::move(socket_performance_watcher), net_log().net_log(),
       net_log().source());
 
   // If the list contains IPv6 and IPv4 addresses, and the first address
   // is IPv6, the IPv4 addresses will be tried as fallback addresses, per
   // "Happy Eyeballs" (RFC 6555).
   bool try_ipv6_connect_with_ipv4_fallback =
-      addresses_.front().GetFamily() == ADDRESS_FAMILY_IPV6 &&
-      !AddressListOnlyContainsIPv6(addresses_);
+      request_->GetAddressResults().value().front().GetFamily() ==
+          ADDRESS_FAMILY_IPV6 &&
+      !AddressListOnlyContainsIPv6(request_->GetAddressResults().value());
 
   transport_socket_->ApplySocketTag(socket_tag());
 
@@ -328,11 +336,12 @@
       transport_socket_->AddConnectionAttempts(fallback_attempts);
     }
 
-    bool is_ipv4 = addresses_.front().GetFamily() == ADDRESS_FAMILY_IPV4;
+    bool is_ipv4 = request_->GetAddressResults().value().front().GetFamily() ==
+                   ADDRESS_FAMILY_IPV4;
     RaceResult race_result = RACE_UNKNOWN;
     if (is_ipv4)
       race_result = RACE_IPV4_SOLO;
-    else if (AddressListOnlyContainsIPv6(addresses_))
+    else if (AddressListOnlyContainsIPv6(request_->GetAddressResults().value()))
       race_result = RACE_IPV6_SOLO;
     else
       race_result = RACE_IPV6_WINS;
@@ -365,7 +374,8 @@
   DCHECK(!fallback_transport_socket_.get());
   DCHECK(!fallback_addresses_.get());
 
-  fallback_addresses_.reset(new AddressList(addresses_));
+  fallback_addresses_.reset(
+      new AddressList(request_->GetAddressResults().value()));
   MakeAddressListStartWithIPv4(fallback_addresses_.get());
 
   // Create a |SocketPerformanceWatcher|, and pass the ownership.
diff --git a/net/socket/transport_connect_job.h b/net/socket/transport_connect_job.h
index 912347c..17b1605 100644
--- a/net/socket/transport_connect_job.h
+++ b/net/socket/transport_connect_job.h
@@ -12,6 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
+#include "net/base/host_port_pair.h"
 #include "net/base/net_export.h"
 #include "net/dns/host_resolver.h"
 #include "net/socket/connect_job.h"
@@ -20,7 +21,6 @@
 
 namespace net {
 
-class HostPortPair;
 class NetLogWithSource;
 
 typedef base::RepeatingCallback<int(const AddressList&,
@@ -38,7 +38,8 @@
       bool disable_resolver_cache,
       const OnHostResolutionCallback& host_resolution_callback);
 
-  const HostResolver::RequestInfo& destination() const { return destination_; }
+  const HostPortPair& destination() const { return destination_; }
+  bool disable_resolver_cache() const { return disable_resolver_cache_; }
   const OnHostResolutionCallback& host_resolution_callback() const {
     return host_resolution_callback_;
   }
@@ -47,7 +48,8 @@
   friend class base::RefCounted<TransportSocketParams>;
   ~TransportSocketParams();
 
-  HostResolver::RequestInfo destination_;
+  const HostPortPair destination_;
+  const bool disable_resolver_cache_;
   const OnHostResolutionCallback host_resolution_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(TransportSocketParams);
@@ -147,12 +149,11 @@
   void CopyConnectionAttemptsFromSockets();
 
   scoped_refptr<TransportSocketParams> params_;
-  std::unique_ptr<HostResolver::Request> request_;
+  std::unique_ptr<HostResolver::ResolveHostRequest> request_;
 
   State next_state_;
 
   std::unique_ptr<StreamSocket> transport_socket_;
-  AddressList addresses_;
 
   std::unique_ptr<StreamSocket> fallback_transport_socket_;
   std::unique_ptr<AddressList> fallback_addresses_;
diff --git a/net/socket/websocket_transport_connect_job.cc b/net/socket/websocket_transport_connect_job.cc
index 4c555bc..ebe2365 100644
--- a/net/socket/websocket_transport_connect_job.cc
+++ b/net/socket/websocket_transport_connect_job.cc
@@ -10,6 +10,7 @@
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "base/values.h"
+#include "net/base/address_list.h"
 #include "net/base/net_errors.h"
 #include "net/base/trace_constants.h"
 #include "net/log/net_log_event_type.h"
@@ -102,11 +103,17 @@
   next_state_ = STATE_RESOLVE_HOST_COMPLETE;
   connect_timing_.dns_start = base::TimeTicks::Now();
 
-  return host_resolver()->Resolve(
-      params_->destination(), priority(), &addresses_,
-      base::Bind(&WebSocketTransportConnectJob::OnIOComplete,
-                 base::Unretained(this)),
-      &request_, net_log());
+  HostResolver::ResolveHostParameters parameters;
+  parameters.initial_priority = priority();
+  parameters.cache_usage =
+      params_->disable_resolver_cache()
+          ? HostResolver::ResolveHostParameters::CacheUsage::DISALLOWED
+          : HostResolver::ResolveHostParameters::CacheUsage::ALLOWED;
+  request_ = host_resolver()->CreateRequest(params_->destination(), net_log(),
+                                            parameters);
+
+  return request_->Start(base::BindOnce(
+      &WebSocketTransportConnectJob::OnIOComplete, base::Unretained(this)));
 }
 
 int WebSocketTransportConnectJob::DoResolveHostComplete(int result) {
@@ -119,10 +126,12 @@
 
   if (result != OK)
     return result;
+  DCHECK(request_->GetAddressResults());
 
   // Invoke callback, and abort if it fails.
   if (!params_->host_resolution_callback().is_null()) {
-    result = params_->host_resolution_callback().Run(addresses_, net_log());
+    result = params_->host_resolution_callback().Run(
+        request_->GetAddressResults().value(), net_log());
     if (result != OK)
       return result;
   }
@@ -132,13 +141,16 @@
 }
 
 int WebSocketTransportConnectJob::DoTransportConnect() {
+  DCHECK(request_->GetAddressResults());
+
   AddressList ipv4_addresses;
   AddressList ipv6_addresses;
   int result = ERR_UNEXPECTED;
   next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE;
 
-  for (AddressList::const_iterator it = addresses_.begin();
-       it != addresses_.end(); ++it) {
+  for (AddressList::const_iterator it =
+           request_->GetAddressResults().value().begin();
+       it != request_->GetAddressResults().value().end(); ++it) {
     switch (it->GetFamily()) {
       case ADDRESS_FAMILY_IPV4:
         ipv4_addresses.push_back(*it);
diff --git a/net/socket/websocket_transport_connect_job.h b/net/socket/websocket_transport_connect_job.h
index e0ce3f9b..b146c35e 100644
--- a/net/socket/websocket_transport_connect_job.h
+++ b/net/socket/websocket_transport_connect_job.h
@@ -14,6 +14,7 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "net/base/net_export.h"
+#include "net/dns/host_resolver.h"
 #include "net/log/net_log_with_source.h"
 #include "net/socket/transport_connect_job.h"
 
@@ -84,11 +85,10 @@
   void ChangePriorityInternal(RequestPriority priority) override;
 
   scoped_refptr<TransportSocketParams> params_;
-  std::unique_ptr<HostResolver::Request> request_;
+  std::unique_ptr<HostResolver::ResolveHostRequest> request_;
 
   State next_state_;
 
-  AddressList addresses_;
   // The addresses are divided into IPv4 and IPv6, which are performed partially
   // in parallel. If the list of IPv6 addresses is non-empty, then the IPv6 jobs
   // go first, followed after |kIPv6FallbackTimerInMs| by the IPv4
diff --git a/net/third_party/quic/core/http/end_to_end_test.cc b/net/third_party/quic/core/http/end_to_end_test.cc
index 8dcc7ef..ff4a4c2 100644
--- a/net/third_party/quic/core/http/end_to_end_test.cc
+++ b/net/third_party/quic/core/http/end_to_end_test.cc
@@ -3733,6 +3733,32 @@
   EXPECT_EQ(kStopSendingTestCode, client_stream->last_stop_sending_code());
 }
 
+TEST_P(EndToEndTest, SimpleStopSendingRstStreamTest) {
+  ASSERT_TRUE(Initialize());
+
+  // Send a request without a fin, to keep the stream open
+  SpdyHeaderBlock headers;
+  headers[":method"] = "POST";
+  headers[":path"] = "/foo";
+  headers[":scheme"] = "https";
+  headers[":authority"] = server_hostname_;
+  client_->SendMessage(headers, "", /*fin=*/false);
+  // Stream should be open
+  ASSERT_NE(nullptr, client_->latest_created_stream());
+  EXPECT_FALSE(
+      QuicStreamPeer::write_side_closed(client_->latest_created_stream()));
+  EXPECT_FALSE(
+      QuicStreamPeer::read_side_closed(client_->latest_created_stream()));
+
+  // Send a RST_STREAM+STOP_SENDING on the stream
+  // Code is not important.
+  client_->latest_created_stream()->Reset(QUIC_BAD_APPLICATION_PAYLOAD);
+  client_->WaitForResponse();
+
+  // Stream should be gone.
+  ASSERT_EQ(nullptr, client_->latest_created_stream());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/net/third_party/quic/core/http/quic_server_session_base_test.cc b/net/third_party/quic/core/http/quic_server_session_base_test.cc
index 4ffdc75..b10db22 100644
--- a/net/third_party/quic/core/http/quic_server_session_base_test.cc
+++ b/net/third_party/quic/core/http/quic_server_session_base_test.cc
@@ -170,6 +170,29 @@
     return connection_->transport_version();
   }
 
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes a
+  // one-way close. This method can be used to inject a STOP_SENDING, which
+  // would cause a close in the opposite direction. This allows tests to do the
+  // extra work to get a two-way (full) close where desired. Also sets up
+  // expects needed to ensure that the STOP_SENDING worked as expected.
+  void InjectStopSendingFrame(QuicStreamId stream_id,
+                              QuicRstStreamErrorCode rst_stream_code) {
+    if (transport_version() != QUIC_VERSION_99) {
+      // Only needed for version 99/IETF QUIC. Noop otherwise.
+      return;
+    }
+    QuicStopSendingFrame stop_sending(
+        kInvalidControlFrameId, stream_id,
+        static_cast<QuicApplicationErrorCode>(rst_stream_code));
+    EXPECT_CALL(owner_, OnStopSendingReceived(_)).Times(1);
+    // Expect the RESET_STREAM that is generated in response to receiving a
+    // STOP_SENDING.
+    EXPECT_CALL(*connection_, SendControlFrame(_));
+    EXPECT_CALL(*connection_, OnStreamReset(stream_id, rst_stream_code));
+    session_->OnStopSendingFrame(stop_sending);
+  }
+
   StrictMock<MockQuicSessionVisitor> owner_;
   StrictMock<MockQuicCryptoServerStreamHelper> stream_helper_;
   MockQuicConnectionHelper helper_;
@@ -216,11 +239,21 @@
                           GetNthClientInitiatedBidirectionalId(0),
                           QUIC_ERROR_PROCESSING_STREAM, 0);
   EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
-  EXPECT_CALL(*connection_, SendControlFrame(_));
-  EXPECT_CALL(*connection_,
-              OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
-                            QUIC_RST_ACKNOWLEDGEMENT));
+  if (transport_version() != QUIC_VERSION_99) {
+    // For non-version 99, the RESET_STREAM will do the full close.
+    // Set up expects accordingly.
+    EXPECT_CALL(*connection_, SendControlFrame(_));
+    EXPECT_CALL(*connection_,
+                OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
+                              QUIC_RST_ACKNOWLEDGEMENT));
+  }
   visitor_->OnRstStream(rst1);
+
+  // For version-99 will create and receive a stop-sending, completing
+  // the full-close expected by this test.
+  InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0),
+                         QUIC_ERROR_PROCESSING_STREAM);
+
   EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
 
   // Send the same two bytes of payload in a new packet.
@@ -237,11 +270,21 @@
                           GetNthClientInitiatedBidirectionalId(0),
                           QUIC_ERROR_PROCESSING_STREAM, 0);
   EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
-  EXPECT_CALL(*connection_, SendControlFrame(_));
-  EXPECT_CALL(*connection_,
-              OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
-                            QUIC_RST_ACKNOWLEDGEMENT));
+  if (transport_version() != QUIC_VERSION_99) {
+    // For non-version 99, the RESET_STREAM will do the full close.
+    // Set up expects accordingly.
+    EXPECT_CALL(*connection_, SendControlFrame(_));
+    EXPECT_CALL(*connection_,
+                OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
+                              QUIC_RST_ACKNOWLEDGEMENT));
+  }
   visitor_->OnRstStream(rst1);
+
+  // For version-99 will create and receive a stop-sending, completing
+  // the full-close expected by this test.
+  InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0),
+                         QUIC_ERROR_PROCESSING_STREAM);
+
   EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
 
   // Send two bytes of payload.
@@ -269,12 +312,21 @@
                          GetNthClientInitiatedBidirectionalId(0),
                          QUIC_ERROR_PROCESSING_STREAM, 0);
   EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
-  EXPECT_CALL(*connection_, SendControlFrame(_));
-  EXPECT_CALL(*connection_,
-              OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
-                            QUIC_RST_ACKNOWLEDGEMENT));
+  if (transport_version() != QUIC_VERSION_99) {
+    // For non-version 99, the RESET_STREAM will do the full close.
+    // Set up expects accordingly.
+    EXPECT_CALL(*connection_, SendControlFrame(_));
+    EXPECT_CALL(*connection_,
+                OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
+                              QUIC_RST_ACKNOWLEDGEMENT));
+  }
   visitor_->OnRstStream(rst);
 
+  // For version-99 will create and receive a stop-sending, completing
+  // the full-close expected by this test.
+  InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0),
+                         QUIC_ERROR_PROCESSING_STREAM);
+
   // If we were tracking, we'd probably want to reject this because it's data
   // past the reset point of stream 3.  As it's a closed stream we just drop the
   // data on the floor, but accept the packet because it has data for stream 5.
diff --git a/net/third_party/quic/core/http/quic_spdy_server_stream_base_test.cc b/net/third_party/quic/core/http/quic_spdy_server_stream_base_test.cc
index 056c071c..83d2508 100644
--- a/net/third_party/quic/core/http/quic_spdy_server_stream_base_test.cc
+++ b/net/third_party/quic/core/http/quic_spdy_server_stream_base_test.cc
@@ -58,10 +58,32 @@
   EXPECT_FALSE(stream_->reading_stopped());
 
   EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0);
-  EXPECT_CALL(session_, SendRstStream(_, QUIC_RST_ACKNOWLEDGEMENT, _)).Times(1);
+
+  if (session_.connection()->transport_version() != QUIC_VERSION_99) {
+    EXPECT_CALL(session_, SendRstStream(_, QUIC_RST_ACKNOWLEDGEMENT, _))
+        .Times(1);
+  } else {
+    // Intercept & check that the call to the QuicConnection's OnStreamReast
+    // has correct stream ID and error code -- for V99/IETF Quic, it should
+    // have the STREAM_CANCELLED error code, not RST_ACK... Capture
+    // OnStreamReset (rather than SendRstStream) because the V99 path bypasses
+    // SendRstStream, calling SendRstStreamInner directly. Mocking
+    // SendRstStreamInner is problematic since the test relies on it to perform
+    // the closing operations and getting the stream in the correct state.
+    EXPECT_CALL(*(static_cast<MockQuicConnection*>(session_.connection())),
+                OnStreamReset(stream_->id(), QUIC_STREAM_CANCELLED));
+  }
   QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(),
                                QUIC_STREAM_CANCELLED, 1234);
   stream_->OnStreamReset(rst_frame);
+  if (session_.connection()->transport_version() == QUIC_VERSION_99) {
+    // Create and inject a STOP SENDING frame to complete the close
+    // of the stream. This is only needed for version 99/IETF QUIC.
+    QuicStopSendingFrame stop_sending(
+        kInvalidControlFrameId, stream_->id(),
+        static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED));
+    session_.OnStopSendingFrame(stop_sending);
+  }
 
   EXPECT_TRUE(stream_->reading_stopped());
   EXPECT_TRUE(stream_->write_side_closed());
diff --git a/net/third_party/quic/core/http/quic_spdy_session_test.cc b/net/third_party/quic/core/http/quic_spdy_session_test.cc
index 82953c3..2781419 100644
--- a/net/third_party/quic/core/http/quic_spdy_session_test.cc
+++ b/net/third_party/quic/core/http/quic_spdy_session_test.cc
@@ -995,12 +995,33 @@
   EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams());
 
   EXPECT_CALL(*connection_, SendControlFrame(_));
-  EXPECT_CALL(*connection_,
-              OnStreamReset(GetNthClientInitiatedBidirectionalId(0), _));
+  if (!IsVersion99()) {
+    // For version99, OnStreamReset gets called because of the STOP_SENDING,
+    // below. EXPECT the call there.
+    EXPECT_CALL(*connection_,
+                OnStreamReset(GetNthClientInitiatedBidirectionalId(0), _));
+  }
   QuicRstStreamFrame rst1(kInvalidControlFrameId,
                           GetNthClientInitiatedBidirectionalId(0),
                           QUIC_ERROR_PROCESSING_STREAM, 0);
   session_.OnRstStream(rst1);
+
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes a
+  // one-way close.
+  if (transport_version() == QUIC_VERSION_99) {
+    // Only needed for version 99/IETF QUIC.
+    QuicStopSendingFrame stop_sending(
+        kInvalidControlFrameId, GetNthClientInitiatedBidirectionalId(0),
+        static_cast<QuicApplicationErrorCode>(QUIC_ERROR_PROCESSING_STREAM));
+    // Expect the RESET_STREAM that is generated in response to receiving a
+    // STOP_SENDING.
+    EXPECT_CALL(*connection_,
+                OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
+                              QUIC_ERROR_PROCESSING_STREAM));
+    session_.OnStopSendingFrame(stop_sending);
+  }
+
   EXPECT_EQ(0u, session_.GetNumOpenIncomingStreams());
   // Connection should remain alive.
   EXPECT_TRUE(connection_->connected());
@@ -1213,20 +1234,32 @@
   const QuicStreamOffset kByteOffset =
       1 + kInitialSessionFlowControlWindowForTest / 2;
 
+  EXPECT_CALL(*connection_, SendControlFrame(_))
+      .Times(2)
+      .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
   if (!IsVersion99()) {
-    EXPECT_CALL(*connection_, SendControlFrame(_))
-        .Times(2)
-        .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
-  } else {
-    // V99 has an additional, STOP_SENDING, frame.
-    EXPECT_CALL(*connection_, SendControlFrame(_))
-        .Times(3)
-        .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
+    // For version99 the call to OnStreamReset happens as a result of receiving
+    // the STOP SENDING, so set up the EXPECT there.
+    EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _));
   }
-  EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _));
   QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream->id(),
                                QUIC_STREAM_CANCELLED, kByteOffset);
   session_.OnRstStream(rst_frame);
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes a
+  // one-way close.
+  if (transport_version() == QUIC_VERSION_99) {
+    // Only needed for version 99/IETF QUIC.
+    QuicStopSendingFrame stop_sending(
+        kInvalidControlFrameId, stream->id(),
+        static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED));
+    // Expect the RESET_STREAM that is generated in response to receiving a
+    // STOP_SENDING.
+    EXPECT_CALL(*connection_,
+                OnStreamReset(stream->id(), QUIC_STREAM_CANCELLED));
+    session_.OnStopSendingFrame(stop_sending);
+  }
+
   EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed());
 }
 
diff --git a/net/third_party/quic/core/quic_connection.cc b/net/third_party/quic/core/quic_connection.cc
index 8d2d634..82a02c3 100644
--- a/net/third_party/quic/core/quic_connection.cc
+++ b/net/third_party/quic/core/quic_connection.cc
@@ -1192,7 +1192,22 @@
 }
 
 bool QuicConnection::OnStopSendingFrame(const QuicStopSendingFrame& frame) {
-  return visitor_->OnStopSendingFrame(frame);
+  DCHECK(connected_);
+
+  // Since a reset stream frame was received, this is not a connectivity probe.
+  // A probe only contains a PING and full padding.
+  UpdatePacketContent(NOT_PADDED_PING);
+
+  if (debug_visitor_ != nullptr) {
+    debug_visitor_->OnStopSendingFrame(frame);
+  }
+
+  QUIC_DLOG(INFO) << ENDPOINT << "STOP_SENDING frame received for stream: "
+                  << frame.stream_id
+                  << " with error: " << frame.application_error_code;
+
+  visitor_->OnStopSendingFrame(frame);
+  return connected_;
 }
 
 bool QuicConnection::OnPathChallengeFrame(const QuicPathChallengeFrame& frame) {
@@ -1696,6 +1711,8 @@
       ++packet_iterator;
       continue;
     }
+    // NOTE THAT RemoveFramesForStream removes only STREAM frames
+    // for the specified stream.
     RemoveFramesForStream(retransmittable_frames, id);
     if (!retransmittable_frames->empty()) {
       ++packet_iterator;
diff --git a/net/third_party/quic/core/quic_connection.h b/net/third_party/quic/core/quic_connection.h
index bf57bf0..aa86c90 100644
--- a/net/third_party/quic/core/quic_connection.h
+++ b/net/third_party/quic/core/quic_connection.h
@@ -294,6 +294,9 @@
   // Called when RTT may have changed, including when an RTT is read from
   // the config.
   virtual void OnRttChanged(QuicTime::Delta rtt) const {}
+
+  // Called when a StopSendingFrame has been parsed.
+  virtual void OnStopSendingFrame(const QuicStopSendingFrame& frame) {}
 };
 
 class QUIC_EXPORT_PRIVATE QuicConnectionHelperInterface {
diff --git a/net/third_party/quic/core/quic_dispatcher.cc b/net/third_party/quic/core/quic_dispatcher.cc
index 0f77a7a..2fdefc3f 100644
--- a/net/third_party/quic/core/quic_dispatcher.cc
+++ b/net/third_party/quic/core/quic_dispatcher.cc
@@ -731,6 +731,8 @@
 
 void QuicDispatcher::OnRstStreamReceived(const QuicRstStreamFrame& frame) {}
 
+void QuicDispatcher::OnStopSendingReceived(const QuicStopSendingFrame& frame) {}
+
 void QuicDispatcher::OnConnectionAddedToTimeWaitList(
     QuicConnectionId connection_id) {
   QUIC_DLOG(INFO) << "Connection " << connection_id
diff --git a/net/third_party/quic/core/quic_dispatcher.h b/net/third_party/quic/core/quic_dispatcher.h
index 885a772..43165c4 100644
--- a/net/third_party/quic/core/quic_dispatcher.h
+++ b/net/third_party/quic/core/quic_dispatcher.h
@@ -91,6 +91,11 @@
   // Collects reset error code received on streams.
   void OnRstStreamReceived(const QuicRstStreamFrame& frame) override;
 
+  // QuicSession::Visitor interface implementation (via inheritance of
+  // QuicTimeWaitListManager::Visitor):
+  // Collects reset error code received on streams.
+  void OnStopSendingReceived(const QuicStopSendingFrame& frame) override;
+
   // QuicTimeWaitListManager::Visitor interface implementation
   // Called whenever the time wait list manager adds a new connection to the
   // time-wait list.
diff --git a/net/third_party/quic/core/quic_session.cc b/net/third_party/quic/core/quic_session.cc
index cf9eee8..c32d7be 100644
--- a/net/third_party/quic/core/quic_session.cc
+++ b/net/third_party/quic/core/quic_session.cc
@@ -185,6 +185,10 @@
     return false;
   }
 
+  if (visitor_) {
+    visitor_->OnStopSendingReceived(frame);
+  }
+
   // If stream is closed, ignore the frame
   if (IsClosedStream(stream_id)) {
     QUIC_DVLOG(1)
@@ -219,9 +223,14 @@
     return true;
   }
   stream->OnStopSending(frame.application_error_code);
-  // TODO(fkastenholz): Add in code to start rst-stream in the opposite
-  // direction once we add IETF-QUIC semantics for rst-stream.
 
+  stream->set_stream_error(
+      static_cast<QuicRstStreamErrorCode>(frame.application_error_code));
+  SendRstStreamInner(
+      stream->id(),
+      static_cast<quic::QuicRstStreamErrorCode>(frame.application_error_code),
+      stream->stream_bytes_written(),
+      /*close_write_side_only=*/true);
   return true;
 }
 
@@ -557,26 +566,34 @@
 void QuicSession::SendRstStream(QuicStreamId id,
                                 QuicRstStreamErrorCode error,
                                 QuicStreamOffset bytes_written) {
-  if (QuicContainsKey(static_stream_map_, id)) {
-    QUIC_BUG << "Cannot send RST for a static stream with ID " << id;
-    return;
-  }
+  SendRstStreamInner(id, error, bytes_written, /*close_write_side_only=*/false);
+}
 
+void QuicSession::SendRstStreamInner(QuicStreamId id,
+                                     QuicRstStreamErrorCode error,
+                                     QuicStreamOffset bytes_written,
+                                     bool close_write_side_only) {
   if (connection()->connected()) {
-    // Only send a RST_STREAM frame if still connected.
-    // Send a RST_STREAM frame. If version 99, will include
-    // an IETF-QUIC STOP_SENDING frame in the packet so that
-    // the peer also shuts down and sends a RST_STREAM back.
-    QuicConnection::ScopedPacketFlusher* flusher =
-        (connection_->transport_version() == QUIC_VERSION_99)
-            ? new QuicConnection::ScopedPacketFlusher(
-                  connection(), QuicConnection::SEND_ACK_IF_QUEUED)
-            : nullptr;
-    control_frame_manager_.WriteOrBufferRstStreamStopSending(id, error,
-                                                             bytes_written);
-    if (flusher) {
-      delete flusher;
-      flusher = nullptr;
+    // Only send if still connected.
+    if (close_write_side_only) {
+      DCHECK_EQ(QUIC_VERSION_99, connection_->transport_version());
+      // Send a RST_STREAM frame.
+      control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written);
+    } else {
+      // Send a RST_STREAM frame plus, if version 99, an IETF
+      // QUIC STOP_SENDING frame. Both sre sent to emulate
+      // the two-way close that Google QUIC's RST_STREAM does.
+      QuicConnection::ScopedPacketFlusher* flusher =
+          (connection_->transport_version() == QUIC_VERSION_99)
+              ? new QuicConnection::ScopedPacketFlusher(
+                    connection(), QuicConnection::SEND_ACK_IF_QUEUED)
+              : nullptr;
+      control_frame_manager_.WriteOrBufferRstStreamStopSending(id, error,
+                                                               bytes_written);
+      if (flusher) {
+        delete flusher;
+        flusher = nullptr;
+      }
     }
     connection_->OnStreamReset(id, error);
   }
@@ -584,7 +601,21 @@
     OnStreamDoneWaitingForAcks(id);
     return;
   }
-  CloseStreamInner(id, true);
+
+  if (!close_write_side_only) {
+    CloseStreamInner(id, true);
+    return;
+  }
+  DCHECK_EQ(QUIC_VERSION_99, connection_->transport_version());
+
+  DynamicStreamMap::iterator it = dynamic_stream_map_.find(id);
+  if (it != dynamic_stream_map_.end()) {
+    QuicStream* stream = it->second.get();
+    if (stream) {
+      stream->set_rst_sent(true);
+      stream->CloseWriteSide();
+    }
+  }
 }
 
 void QuicSession::SendGoAway(QuicErrorCode error_code,
@@ -631,7 +662,6 @@
 
 void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) {
   QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id;
-
   DynamicStreamMap::iterator it = dynamic_stream_map_.find(stream_id);
   if (it == dynamic_stream_map_.end()) {
     // When CloseStreamInner has been called recursively (via
@@ -667,7 +697,6 @@
     InsertLocallyClosedStreamsHighestOffset(
         stream_id, stream->flow_controller()->highest_received_byte_offset());
   }
-
   dynamic_stream_map_.erase(it);
   if (IsIncomingStream(stream_id)) {
     --num_dynamic_incoming_streams_;
diff --git a/net/third_party/quic/core/quic_session.h b/net/third_party/quic/core/quic_session.h
index 7044e913..009b864 100644
--- a/net/third_party/quic/core/quic_session.h
+++ b/net/third_party/quic/core/quic_session.h
@@ -62,6 +62,10 @@
 
     // Called when the session receives reset on a stream from the peer.
     virtual void OnRstStreamReceived(const QuicRstStreamFrame& frame) = 0;
+
+    // Called when the session receives a STOP_SENDING for a stream from the
+    // peer.
+    virtual void OnStopSendingReceived(const QuicStopSendingFrame& frame) = 0;
   };
 
   // CryptoHandshakeEvent enumerates the events generated by a QuicCryptoStream.
@@ -383,6 +387,17 @@
     return num_locally_closed_incoming_streams_highest_offset_;
   }
 
+  // Does actual work of sending reset-stream or reset-stream&stop-sending
+  // If the connection is not version 99/IETF QUIC, will always send a
+  // RESET_STREAM and close_write_side_only is ignored. If the connection is
+  // IETF QUIC/Version 99 then will send a RESET_STREAM and STOP_SENDING if
+  // close_write_side_only is false, just a RESET_STREAM if
+  // close_write_side_only is true.
+  virtual void SendRstStreamInner(QuicStreamId id,
+                                  QuicRstStreamErrorCode error,
+                                  QuicStreamOffset bytes_written,
+                                  bool close_write_side_only);
+
  protected:
   using StaticStreamMap = QuicSmallMap<QuicStreamId, QuicStream*, 2>;
 
diff --git a/net/third_party/quic/core/quic_session_test.cc b/net/third_party/quic/core/quic_session_test.cc
index 6f7d803..1c36112b 100644
--- a/net/third_party/quic/core/quic_session_test.cc
+++ b/net/third_party/quic/core/quic_session_test.cc
@@ -1288,19 +1288,23 @@
   const QuicStreamOffset kByteOffset =
       1 + kInitialSessionFlowControlWindowForTest / 2;
 
-  if (transport_version() == QUIC_VERSION_99) {
-    EXPECT_CALL(*connection_, SendControlFrame(_))
-        .Times(3)
-        .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
-  } else {
-    EXPECT_CALL(*connection_, SendControlFrame(_))
-        .Times(2)
-        .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
-  }
+  EXPECT_CALL(*connection_, SendControlFrame(_))
+      .Times(2)
+      .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
   EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _));
+
   QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream->id(),
                                QUIC_STREAM_CANCELLED, kByteOffset);
   session_.OnRstStream(rst_frame);
+  if (transport_version() == QUIC_VERSION_99) {
+    // The test is predicated on the stream being fully closed. For V99, the
+    // RST_STREAM only does one side (the read side from the perspective of the
+    // node receiving the RST_STREAM). This is needed to fully close the
+    // stream and therefore fulfill all of the expects.
+    QuicStopSendingFrame frame(kInvalidControlFrameId, stream->id(),
+                               QUIC_STREAM_CANCELLED);
+    EXPECT_TRUE(session_.OnStopSendingFrame(frame));
+  }
   EXPECT_EQ(kByteOffset, session_.flow_controller()->bytes_consumed());
 }
 
@@ -1727,19 +1731,27 @@
 
   QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream2->id(),
                                QUIC_STREAM_CANCELLED, 1234);
+  // Just for the RST_STREAM
+  EXPECT_CALL(*connection_, SendControlFrame(_))
+      .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame));
   if (transport_version() == QUIC_VERSION_99) {
-    // Once for the RST_STREAM, once for the STOP_SENDING
-    EXPECT_CALL(*connection_, SendControlFrame(_))
-        .Times(2)
-        .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame));
+    EXPECT_CALL(*connection_,
+                OnStreamReset(stream2->id(), QUIC_STREAM_CANCELLED));
   } else {
-    // Just for the RST_STREAM
-    EXPECT_CALL(*connection_, SendControlFrame(_))
-        .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame));
+    EXPECT_CALL(*connection_,
+                OnStreamReset(stream2->id(), QUIC_RST_ACKNOWLEDGEMENT));
   }
-  EXPECT_CALL(*connection_,
-              OnStreamReset(stream2->id(), QUIC_RST_ACKNOWLEDGEMENT));
   stream2->OnStreamReset(rst_frame);
+
+  if (transport_version() == QUIC_VERSION_99) {
+    // The test is predicated on the stream being fully closed. For V99, the
+    // RST_STREAM only does one side (the read side from the perspective of the
+    // node receiving the RST_STREAM). This is needed to fully close the
+    // stream and therefore fulfill all of the expects.
+    QuicStopSendingFrame frame(kInvalidControlFrameId, stream2->id(),
+                               QUIC_STREAM_CANCELLED);
+    EXPECT_TRUE(session_.OnStopSendingFrame(frame));
+  }
   EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream2->id()));
   ASSERT_EQ(1u, session_.closed_streams()->size());
   EXPECT_EQ(stream2->id(), session_.closed_streams()->front()->id());
@@ -1757,6 +1769,10 @@
   EXPECT_CALL(*connection_,
               OnStreamReset(stream4->id(), QUIC_STREAM_CANCELLED));
   stream4->WriteOrBufferData(body, false, nullptr);
+  // Note well: Reset() actually closes the stream in both directions. For
+  // GOOGLE QUIC it sends a RST_STREAM (which does a 2-way close), for IETF
+  // QUIC/V99 it sends both a RST_STREAM and a STOP_SENDING (each of which
+  // closes in only one direction).
   stream4->Reset(QUIC_STREAM_CANCELLED);
   EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream4->id()));
   EXPECT_EQ(2u, session_.closed_streams()->size());
@@ -2286,10 +2302,24 @@
   }
 
   TestStream* stream = session_.CreateOutgoingBidirectionalStream();
+
+  // Ensure that the stream starts out open in both directions.
+  EXPECT_FALSE(QuicStreamPeer::write_side_closed(stream));
+  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream));
+
   QuicStreamId stream_id = stream->id();
   QuicStopSendingFrame frame(1, stream_id, 123);
   EXPECT_CALL(*stream, OnStopSending(123));
+  // Expect a reset to come back out.
+  EXPECT_CALL(*connection_, SendControlFrame(_));
+  EXPECT_CALL(
+      *connection_,
+      OnStreamReset(stream_id, static_cast<QuicRstStreamErrorCode>(123)));
   EXPECT_TRUE(session_.OnStopSendingFrame(frame));
+  // When the STOP_SENDING is received, the node generates a RST_STREAM,
+  // which closes the stream in the write direction. Ensure this.
+  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream));
+  EXPECT_TRUE(QuicStreamPeer::write_side_closed(stream));
 }
 
 }  // namespace
diff --git a/net/third_party/quic/core/quic_stream.cc b/net/third_party/quic/core/quic_stream.cc
index f72b4d85..7fa1def6 100644
--- a/net/third_party/quic/core/quic_stream.cc
+++ b/net/third_party/quic/core/quic_stream.cc
@@ -367,7 +367,11 @@
   }
 
   stream_error_ = frame.error_code;
-  CloseWriteSide();
+  // Google QUIC closes both sides of the stream in response to a
+  // RESET_STREAM, IETF QUIC closes only the read side.
+  if (transport_version() != QUIC_VERSION_99) {
+    CloseWriteSide();
+  }
   CloseReadSide();
 }
 
diff --git a/net/third_party/quic/core/quic_stream.h b/net/third_party/quic/core/quic_stream.h
index 5dee6de..77995fb1 100644
--- a/net/third_party/quic/core/quic_stream.h
+++ b/net/third_party/quic/core/quic_stream.h
@@ -345,6 +345,11 @@
   // QuicStream class.
   virtual void OnStopSending(uint16_t code);
 
+  // Close the write side of the socket.  Further writes will fail.
+  // Can be called by the subclass or internally.
+  // Does not send a FIN.  May cause the stream to be closed.
+  virtual void CloseWriteSide();
+
  protected:
   // Sends as many bytes in the first |count| buffers of |iov| to the connection
   // as the connection will consume. If FIN is consumed, the write side is
@@ -362,11 +367,6 @@
                                            QuicStreamOffset offset,
                                            bool fin);
 
-  // Close the write side of the socket.  Further writes will fail.
-  // Can be called by the subclass or internally.
-  // Does not send a FIN.  May cause the stream to be closed.
-  virtual void CloseWriteSide();
-
   // Close the read side of the socket.  May cause the stream to be closed.
   // Subclasses and consumers should use StopReading to terminate reading early
   // if expecting a FIN. Can be used directly by subclasses if not expecting a
diff --git a/net/third_party/quic/core/quic_stream_test.cc b/net/third_party/quic/core/quic_stream_test.cc
index 8e27ea3..e7feca3 100644
--- a/net/third_party/quic/core/quic_stream_test.cc
+++ b/net/third_party/quic/core/quic_stream_test.cc
@@ -127,6 +127,18 @@
     return true;
   }
 
+  bool ClearResetStreamFrame(const QuicFrame& frame) {
+    EXPECT_EQ(RST_STREAM_FRAME, frame.type);
+    DeleteFrame(&const_cast<QuicFrame&>(frame));
+    return true;
+  }
+
+  bool ClearStopSendingFrame(const QuicFrame& frame) {
+    EXPECT_EQ(STOP_SENDING_FRAME, frame.type);
+    DeleteFrame(&const_cast<QuicFrame&>(frame));
+    return true;
+  }
+
  protected:
   MockQuicConnectionHelper helper_;
   MockAlarmFactory alarm_factory_;
@@ -1445,6 +1457,10 @@
 TEST_P(QuicParameterizedStreamTest, CheckStopSending) {
   Initialize();
   const int kStopSendingCode = 123;
+  // These must start as false.
+  EXPECT_FALSE(QuicStreamPeer::write_side_closed(stream_));
+  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
+  // Expect to actually see a stop sending if and only if we are in version 99.
   if (connection_->transport_version() == QUIC_VERSION_99) {
     EXPECT_CALL(*session_, SendStopSending(kStopSendingCode, stream_->id()))
         .Times(1);
@@ -1452,6 +1468,74 @@
     EXPECT_CALL(*session_, SendStopSending(_, _)).Times(0);
   }
   stream_->SendStopSending(kStopSendingCode);
+  // Sending a STOP_SENDING does not actually close the local stream.
+  // Our implementation waits for the responding RESET_STREAM to effect the
+  // closes. Therefore, read- and write-side closes should both be false.
+  EXPECT_FALSE(QuicStreamPeer::write_side_closed(stream_));
+  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
+}
+
+// Test that OnStreamReset does one-way (read) closes if version 99, two way
+// (read and write) if not version 99.
+TEST_P(QuicStreamTest, OnStreamResetReadOrReadWrite) {
+  Initialize();
+  EXPECT_FALSE(QuicStreamPeer::write_side_closed(stream_));
+  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
+
+  QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(),
+                               QUIC_STREAM_CANCELLED, 1234);
+  stream_->OnStreamReset(rst_frame);
+  if (connection_->transport_version() == QUIC_VERSION_99) {
+    // Version 99/IETF QUIC should close just the read side.
+    EXPECT_TRUE(QuicStreamPeer::read_side_closed(stream_));
+    EXPECT_FALSE(QuicStreamPeer::write_side_closed(stream_));
+  } else {
+    // Google QUIC should close both sides of the stream.
+    EXPECT_TRUE(QuicStreamPeer::write_side_closed(stream_));
+    EXPECT_TRUE(QuicStreamPeer::read_side_closed(stream_));
+  }
+}
+
+// Test that receiving a STOP_SENDING just closes the write side of the stream.
+// If not V99, the test is a noop (no STOP_SENDING in Google QUIC).
+TEST_P(QuicStreamTest, OnStopSendingReadOrReadWrite) {
+  Initialize();
+  if (connection_->transport_version() != QUIC_VERSION_99) {
+    return;
+  }
+
+  EXPECT_FALSE(QuicStreamPeer::write_side_closed(stream_));
+  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
+
+  // Simulate receipt of a STOP_SENDING.
+  stream_->OnStopSending(123);
+
+  // Should close just the read side.
+  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
+  EXPECT_TRUE(QuicStreamPeer::write_side_closed(stream_));
+}
+
+// SendOnlyRstStream must only send a RESET_STREAM (no bundled STOP_SENDING).
+TEST_P(QuicStreamTest, SendOnlyRstStream) {
+  Initialize();
+  if (connection_->transport_version() != QUIC_VERSION_99) {
+    return;
+  }
+
+  EXPECT_CALL(*connection_,
+              OnStreamReset(stream_->id(), QUIC_BAD_APPLICATION_PAYLOAD));
+  EXPECT_CALL(*connection_, SendControlFrame(_))
+      .Times(1)
+      .WillOnce(Invoke(this, &QuicStreamTest::ClearResetStreamFrame));
+
+  QuicSessionPeer::SendRstStreamInner(session_.get(), stream_->id(),
+                                      QUIC_BAD_APPLICATION_PAYLOAD,
+                                      stream_->stream_bytes_written(),
+                                      /*close_write_side_only=*/true);
+
+  // ResetStreamOnly should just close the write side.
+  EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
+  EXPECT_TRUE(QuicStreamPeer::write_side_closed(stream_));
 }
 
 }  // namespace
diff --git a/net/third_party/quic/test_tools/mock_quic_session_visitor.h b/net/third_party/quic/test_tools/mock_quic_session_visitor.h
index 2c36527..450eb826 100644
--- a/net/third_party/quic/test_tools/mock_quic_session_visitor.h
+++ b/net/third_party/quic/test_tools/mock_quic_session_visitor.h
@@ -27,6 +27,7 @@
   MOCK_METHOD1(OnWriteBlocked,
                void(QuicBlockedWriterInterface* blocked_writer));
   MOCK_METHOD1(OnRstStreamReceived, void(const QuicRstStreamFrame& frame));
+  MOCK_METHOD1(OnStopSendingReceived, void(const QuicStopSendingFrame& frame));
   MOCK_METHOD1(OnConnectionAddedToTimeWaitList,
                void(QuicConnectionId connection_id));
 };
diff --git a/net/third_party/quic/test_tools/quic_session_peer.cc b/net/third_party/quic/test_tools/quic_session_peer.cc
index 22b48e8..537605ac 100644
--- a/net/third_party/quic/test_tools/quic_session_peer.cc
+++ b/net/third_party/quic/test_tools/quic_session_peer.cc
@@ -184,5 +184,14 @@
   return &session->v99_streamid_manager_.unidirectional_stream_id_manager_;
 }
 
+// static
+void QuicSessionPeer::SendRstStreamInner(QuicSession* session,
+                                         QuicStreamId id,
+                                         QuicRstStreamErrorCode error,
+                                         QuicStreamOffset bytes_written,
+                                         bool close_write_side_only) {
+  session->SendRstStreamInner(id, error, bytes_written, close_write_side_only);
+}
+
 }  // namespace test
 }  // namespace quic
diff --git a/net/third_party/quic/test_tools/quic_session_peer.h b/net/third_party/quic/test_tools/quic_session_peer.h
index eb75675..a83a1d8 100644
--- a/net/third_party/quic/test_tools/quic_session_peer.h
+++ b/net/third_party/quic/test_tools/quic_session_peer.h
@@ -67,6 +67,11 @@
       QuicSession* session);
   static QuicStreamIdManager* v99_unidirectional_stream_id_manager(
       QuicSession* session);
+  static void SendRstStreamInner(QuicSession* session,
+                                 QuicStreamId id,
+                                 QuicRstStreamErrorCode error,
+                                 QuicStreamOffset bytes_written,
+                                 bool close_write_side_only);
 };
 
 }  // namespace test
diff --git a/net/third_party/quic/test_tools/quic_stream_peer.cc b/net/third_party/quic/test_tools/quic_stream_peer.cc
index e944573..7ec755b 100644
--- a/net/third_party/quic/test_tools/quic_stream_peer.cc
+++ b/net/third_party/quic/test_tools/quic_stream_peer.cc
@@ -33,6 +33,11 @@
 }
 
 // static
+bool QuicStreamPeer::write_side_closed(QuicStream* stream) {
+  return stream->write_side_closed();
+}
+
+// static
 void QuicStreamPeer::CloseReadSide(QuicStream* stream) {
   stream->CloseReadSide();
 }
diff --git a/net/third_party/quic/test_tools/quic_stream_peer.h b/net/third_party/quic/test_tools/quic_stream_peer.h
index 407aeb7..9fe9b6a 100644
--- a/net/third_party/quic/test_tools/quic_stream_peer.h
+++ b/net/third_party/quic/test_tools/quic_stream_peer.h
@@ -27,6 +27,7 @@
   static void SetWriteSideClosed(bool value, QuicStream* stream);
   static void SetStreamBytesWritten(QuicStreamOffset stream_bytes_written,
                                     QuicStream* stream);
+  static bool write_side_closed(QuicStream* stream);
   static bool read_side_closed(QuicStream* stream);
   static void CloseReadSide(QuicStream* stream);
 
diff --git a/net/third_party/quic/test_tools/quic_test_utils.h b/net/third_party/quic/test_tools/quic_test_utils.h
index aa92bfe48..e3a34a3 100644
--- a/net/third_party/quic/test_tools/quic_test_utils.h
+++ b/net/third_party/quic/test_tools/quic_test_utils.h
@@ -556,6 +556,7 @@
     QuicConnection::SendConnectivityProbingResponsePacket(peer_address);
   }
   MOCK_METHOD1(OnPathResponseFrame, bool(const QuicPathResponseFrame&));
+  MOCK_METHOD1(OnStopSendingFrame, bool(const QuicStopSendingFrame& frame));
 };
 
 class PacketSavingConnection : public MockQuicConnection {
diff --git a/net/third_party/quic/tools/quic_simple_server_session_test.cc b/net/third_party/quic/tools/quic_simple_server_session_test.cc
index 475be18..1c13eade6 100644
--- a/net/third_party/quic/tools/quic_simple_server_session_test.cc
+++ b/net/third_party/quic/tools/quic_simple_server_session_test.cc
@@ -256,6 +256,25 @@
     return connection_->transport_version() == QUIC_VERSION_99;
   }
 
+  void InjectStopSending(QuicStreamId stream_id,
+                         QuicRstStreamErrorCode rst_stream_code) {
+    // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+    // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
+    // a one-way close.
+    if (connection_->transport_version() != QUIC_VERSION_99) {
+      // Only needed for version 99/IETF QUIC.
+      return;
+    }
+    EXPECT_CALL(owner_, OnStopSendingReceived(_)).Times(1);
+    QuicStopSendingFrame stop_sending(
+        kInvalidControlFrameId, stream_id,
+        static_cast<QuicApplicationErrorCode>(rst_stream_code));
+    // Expect the RESET_STREAM that is generated in response to receiving a
+    // STOP_SENDING.
+    EXPECT_CALL(*connection_, OnStreamReset(stream_id, rst_stream_code));
+    session_->OnStopSendingFrame(stop_sending);
+  }
+
   StrictMock<MockQuicSessionVisitor> owner_;
   StrictMock<MockQuicCryptoServerStreamHelper> stream_helper_;
   MockQuicConnectionHelper helper_;
@@ -288,10 +307,18 @@
                           QUIC_ERROR_PROCESSING_STREAM, 0);
   EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
   EXPECT_CALL(*connection_, SendControlFrame(_));
-  EXPECT_CALL(*connection_,
-              OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
-                            QUIC_RST_ACKNOWLEDGEMENT));
+  if (!IsVersion99()) {
+    // For version 99, this is covered in InjectStopSending()
+    EXPECT_CALL(*connection_,
+                OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
+                              QUIC_RST_ACKNOWLEDGEMENT));
+  }
   visitor_->OnRstStream(rst1);
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
+  // a one-way close.
+  InjectStopSending(GetNthClientInitiatedBidirectionalId(0),
+                    QUIC_ERROR_PROCESSING_STREAM);
   EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
 
   // Send the same two bytes of payload in a new packet.
@@ -310,11 +337,18 @@
   EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
   if (!IsVersion99()) {
     EXPECT_CALL(*connection_, SendControlFrame(_));
+    // For version 99, this is covered in InjectStopSending()
+    EXPECT_CALL(*connection_,
+                OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
+                              QUIC_RST_ACKNOWLEDGEMENT));
   }
-  EXPECT_CALL(*connection_,
-              OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
-                            QUIC_RST_ACKNOWLEDGEMENT));
   visitor_->OnRstStream(rst1);
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
+  // a one-way close.
+  InjectStopSending(GetNthClientInitiatedBidirectionalId(0),
+                    QUIC_ERROR_PROCESSING_STREAM);
+
   EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams());
 
   // Send two bytes of payload.
@@ -344,11 +378,17 @@
   EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
   if (!IsVersion99()) {
     EXPECT_CALL(*connection_, SendControlFrame(_));
+    // For version 99, this is covered in InjectStopSending()
+    EXPECT_CALL(*connection_,
+                OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
+                              QUIC_RST_ACKNOWLEDGEMENT));
   }
-  EXPECT_CALL(*connection_,
-              OnStreamReset(GetNthClientInitiatedBidirectionalId(0),
-                            QUIC_RST_ACKNOWLEDGEMENT));
   visitor_->OnRstStream(rst);
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
+  // a one-way close.
+  InjectStopSending(GetNthClientInitiatedBidirectionalId(0),
+                    QUIC_ERROR_PROCESSING_STREAM);
 
   // If we were tracking, we'd probably want to reject this because it's data
   // past the reset point of stream 3.  As it's a closed stream we just drop the
@@ -772,8 +812,11 @@
   // stream to be opened.
   QuicStreamId stream_got_reset = GetNthServerInitiatedUnidirectionalId(0);
   EXPECT_CALL(*connection_, SendControlFrame(_));
-  EXPECT_CALL(*connection_,
-              OnStreamReset(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT));
+  if (!IsVersion99()) {
+    // For version 99, this is covered in InjectStopSending()
+    EXPECT_CALL(*connection_,
+                OnStreamReset(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT));
+  }
   EXPECT_CALL(*session_, WriteHeadersMock(stream_to_open, _, false,
                                           QuicStream::kDefaultPriority, _));
   if (IsVersion99()) {
@@ -799,6 +842,10 @@
         QuicMaxStreamIdFrame(0, GetNthServerInitiatedUnidirectionalId(10)));
   }
   visitor_->OnRstStream(rst);
+  // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a
+  // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes
+  // a one-way close.
+  InjectStopSending(stream_got_reset, QUIC_STREAM_CANCELLED);
 }
 
 }  // namespace
diff --git a/net/third_party/quic/tools/quic_simple_server_stream_test.cc b/net/third_party/quic/tools/quic_simple_server_stream_test.cc
index a8d5fdd..63ecb8d 100644
--- a/net/third_party/quic/tools/quic_simple_server_stream_test.cc
+++ b/net/third_party/quic/tools/quic_simple_server_stream_test.cc
@@ -172,6 +172,8 @@
 
   using QuicSession::ActivateStream;
 
+  MOCK_METHOD1(OnStopSendingReceived, void(const QuicStopSendingFrame& frame));
+
   spdy::SpdyHeaderBlock original_request_headers_;
 };
 
@@ -673,7 +675,12 @@
   QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(),
                                QUIC_STREAM_CANCELLED, 1234);
   stream_->OnStreamReset(rst_frame);
-
+  if (connection_->transport_version() == QUIC_VERSION_99) {
+    // For V99 receiving a RST_STREAM causes a 1-way close; the test requires
+    // a full close. A CloseWriteSide closes the other half of the stream.
+    // Everything should then work properly.
+    stream_->CloseWriteSide();
+  }
   EXPECT_TRUE(stream_->reading_stopped());
   EXPECT_TRUE(stream_->write_side_closed());
 }
diff --git a/remoting/android/java/src/org/chromium/chromoting/OAuthTokenConsumer.java b/remoting/android/java/src/org/chromium/chromoting/OAuthTokenConsumer.java
index eb29b85..e0aa158 100644
--- a/remoting/android/java/src/org/chromium/chromoting/OAuthTokenConsumer.java
+++ b/remoting/android/java/src/org/chromium/chromoting/OAuthTokenConsumer.java
@@ -121,8 +121,7 @@
                 }
                 return null;
             }
-        }
-                .executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
+        }.executeOnTaskRunner(OAuthTokenFetcher.TASK_RUNNER);
     }
 
     private void handleErrorOnMainThread(final OAuthTokenFetcher.Callback callback,
diff --git a/remoting/android/java/src/org/chromium/chromoting/base/OAuthTokenFetcher.java b/remoting/android/java/src/org/chromium/chromoting/base/OAuthTokenFetcher.java
index 4f69ac76..9df1dcb 100644
--- a/remoting/android/java/src/org/chromium/chromoting/base/OAuthTokenFetcher.java
+++ b/remoting/android/java/src/org/chromium/chromoting/base/OAuthTokenFetcher.java
@@ -15,6 +15,10 @@
 import com.google.android.gms.auth.UserRecoverableAuthException;
 
 import org.chromium.base.task.AsyncTask;
+import org.chromium.base.task.PostTask;
+import org.chromium.base.task.TaskPriority;
+import org.chromium.base.task.TaskRunner;
+import org.chromium.base.task.TaskTraits;
 
 import java.io.IOException;
 
@@ -57,6 +61,9 @@
     /** Request code used for starting the OAuth recovery activity. */
     public static final int REQUEST_CODE_RECOVER_FROM_OAUTH_ERROR = 100;
 
+    public static final TaskRunner TASK_RUNNER = PostTask.createSequencedTaskRunner(
+            new TaskTraits().taskPriority(TaskPriority.BEST_EFFORT));
+
     /**
      * Reference to the context to fetch token. It will be used for starting other activities to
      * handle user-recoverable errors if it is an activity, otherwise user-recoverable errors will
@@ -115,8 +122,7 @@
                 }
                 return null;
             }
-        }
-                .executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
+        }.executeOnTaskRunner(TASK_RUNNER);
     }
 
     private void handleTokenReceived(final String token) {
diff --git a/remoting/ios/app/app_delegate.mm b/remoting/ios/app/app_delegate.mm
index 60ed69a..97fe90c 100644
--- a/remoting/ios/app/app_delegate.mm
+++ b/remoting/ios/app/app_delegate.mm
@@ -49,7 +49,6 @@
 - (BOOL)application:(UIApplication*)application
     didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
   [self launchRootViewController];
-  [RemotingTheme applyColorSchemes];
   [AVAudioSession.sharedInstance setCategory:AVAudioSessionCategoryAmbient
                                        error:NULL];
   [AppInitializer onAppDidFinishLaunching];
diff --git a/remoting/ios/app/remoting_theme.h b/remoting/ios/app/remoting_theme.h
index 8f9c722..3adc7b9 100644
--- a/remoting/ios/app/remoting_theme.h
+++ b/remoting/ios/app/remoting_theme.h
@@ -10,9 +10,6 @@
 // Styles to be used when rendering the iOS client's UI.
 @interface RemotingTheme : NSObject
 
-// Applys default color schemes on elements like buttons and alerts.
-+ (void)applyColorSchemes;
-
 // Colors
 
 @property(class, nonatomic, readonly) UIColor* buttonBackgroundColor;
diff --git a/remoting/ios/app/remoting_theme.mm b/remoting/ios/app/remoting_theme.mm
index 9c315bf..c5236ce0 100644
--- a/remoting/ios/app/remoting_theme.mm
+++ b/remoting/ios/app/remoting_theme.mm
@@ -16,17 +16,6 @@
 
 @implementation RemotingTheme
 
-+ (void)applyColorSchemes {
-  MDCBasicColorScheme* colorScheme = [[MDCBasicColorScheme alloc]
-      initWithPrimaryColor:RemotingTheme.flatButtonTextColor];
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-  // TODO(crbug.com/930714): +[MDCAlertColorThemer applyColorScheme:] is
-  // deprecated. Needs to be replaced.
-  [MDCAlertColorThemer applyColorScheme:colorScheme];
-#pragma GCC diagnostic pop
-}
-
 #pragma mark - Colors
 
 + (UIColor*)firstLaunchViewBackgroundColor {
diff --git a/remoting/test/BUILD.gn b/remoting/test/BUILD.gn
index 0bb66b9b..2b7d0d7 100644
--- a/remoting/test/BUILD.gn
+++ b/remoting/test/BUILD.gn
@@ -10,10 +10,6 @@
   sources = [
     "access_token_fetcher.cc",
     "access_token_fetcher.h",
-    "app_remoting_report_issue_request.cc",
-    "app_remoting_report_issue_request.h",
-    "app_remoting_service_urls.cc",
-    "app_remoting_service_urls.h",
     "chromoting_test_driver_environment.cc",
     "chromoting_test_driver_environment.h",
     "connection_setup_info.cc",
@@ -24,8 +20,6 @@
     "cyclic_frame_generator.h",
     "fake_access_token_fetcher.cc",
     "fake_access_token_fetcher.h",
-    "fake_app_remoting_report_issue_request.cc",
-    "fake_app_remoting_report_issue_request.h",
     "fake_host_list_fetcher.cc",
     "fake_host_list_fetcher.h",
     "fake_network_dispatcher.cc",
@@ -36,8 +30,6 @@
     "fake_port_allocator.h",
     "fake_refresh_token_store.cc",
     "fake_refresh_token_store.h",
-    "fake_remote_host_info_fetcher.cc",
-    "fake_remote_host_info_fetcher.h",
     "fake_socket_factory.cc",
     "fake_socket_factory.h",
     "frame_generator_util.cc",
@@ -54,8 +46,6 @@
     "remote_connection_observer.h",
     "remote_host_info.cc",
     "remote_host_info.h",
-    "remote_host_info_fetcher.cc",
-    "remote_host_info_fetcher.h",
     "rgb_value.cc",
     "rgb_value.h",
     "scroll_frame_generator.cc",
@@ -111,44 +101,6 @@
   ]
 }
 
-static_library("ar_test_driver_common") {
-  testonly = true
-
-  sources = [
-    "app_remoting_connected_client_fixture.cc",
-    "app_remoting_connected_client_fixture.h",
-    "app_remoting_connection_helper.cc",
-    "app_remoting_connection_helper.h",
-    "app_remoting_latency_test_fixture.cc",
-    "app_remoting_latency_test_fixture.h",
-    "app_remoting_test_driver_environment.cc",
-    "app_remoting_test_driver_environment.h",
-  ]
-
-  deps = [
-    ":test_support",
-    "//testing/gtest",
-    "//third_party/webrtc/modules/desktop_capture",
-  ]
-}
-
-# An external version of the test driver tool which includes minimal tests
-executable("ar_sample_test_driver") {
-  testonly = true
-
-  sources = [
-    "app_remoting_sample_test_driver_environment.cc",
-    "app_remoting_test_driver.cc",
-  ]
-
-  deps = [
-    ":ar_test_driver_common",
-    "//base/test:test_support",
-    "//build/win:default_exe_manifest",
-    "//testing/gtest",
-  ]
-}
-
 if (enable_remoting_host && !is_android && !is_chromeos) {
   static_library("fake_connection_event_logger") {
     testonly = true
@@ -230,18 +182,14 @@
 
   sources = [
     "access_token_fetcher_unittest.cc",
-    "app_remoting_report_issue_request_unittest.cc",
-    "app_remoting_test_driver_environment_unittest.cc",
     "chromoting_test_driver_environment_unittest.cc",
     "connection_time_observer_unittest.cc",
     "host_list_fetcher_unittest.cc",
-    "remote_host_info_fetcher_unittest.cc",
     "test_chromoting_client_unittest.cc",
     "test_video_renderer_unittest.cc",
   ]
 
   deps = [
-    ":ar_test_driver_common",
     ":test_support",
     "//base",
     "//net:test_support",
diff --git a/remoting/test/app_remoting_connected_client_fixture.cc b/remoting/test/app_remoting_connected_client_fixture.cc
deleted file mode 100644
index 9e0bad4..0000000
--- a/remoting/test/app_remoting_connected_client_fixture.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/test/app_remoting_connected_client_fixture.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/json/json_reader.h"
-#include "base/logging.h"
-#include "base/run_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/timer/timer.h"
-#include "base/values.h"
-#include "remoting/protocol/host_stub.h"
-#include "remoting/test/app_remoting_connection_helper.h"
-#include "remoting/test/app_remoting_test_driver_environment.h"
-#include "remoting/test/remote_application_details.h"
-#include "remoting/test/test_chromoting_client.h"
-
-namespace {
-
-void SimpleHostMessageHandler(
-    const std::string& target_message_type,
-    const std::string& target_message_data,
-    const base::Closure& done_closure,
-    bool* message_received,
-    const remoting::protocol::ExtensionMessage& message) {
-  if (message.type() == target_message_type &&
-      message.data() == target_message_data) {
-    *message_received = true;
-    done_closure.Run();
-  }
-}
-}  // namespace
-
-namespace remoting {
-namespace test {
-
-AppRemotingConnectedClientFixture::AppRemotingConnectedClientFixture()
-    : application_details_(
-          AppRemotingSharedData->GetDetailsFromAppName(GetParam())) {}
-
-AppRemotingConnectedClientFixture::~AppRemotingConnectedClientFixture() =
-    default;
-
-void AppRemotingConnectedClientFixture::SetUp() {
-  connection_helper_.reset(
-      new AppRemotingConnectionHelper(application_details_));
-  std::unique_ptr<TestChromotingClient> test_chromoting_client(
-      new TestChromotingClient());
-
-  test_chromoting_client->AddRemoteConnectionObserver(this);
-
-  connection_helper_->Initialize(std::move(test_chromoting_client));
-  if (!connection_helper_->StartConnection()) {
-    LOG(ERROR) << "Remote host connection could not be established.";
-    FAIL();
-  }
-}
-
-void AppRemotingConnectedClientFixture::TearDown() {
-  connection_helper_->test_chromoting_client()->RemoveRemoteConnectionObserver(
-      this);
-  connection_helper_.reset();
-}
-
-void AppRemotingConnectedClientFixture::HostMessageReceived(
-    const protocol::ExtensionMessage& message) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  if (!host_message_received_callback_.is_null()) {
-    host_message_received_callback_.Run(message);
-  }
-}
-
-bool AppRemotingConnectedClientFixture::VerifyResponseForSimpleHostMessage(
-    const std::string& message_request_title,
-    const std::string& message_response_title,
-    const std::string& message_payload,
-    const base::TimeDelta& max_wait_time) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  bool message_received = false;
-
-  DCHECK(!run_loop_ || !run_loop_->running());
-  run_loop_.reset(new base::RunLoop());
-
-  host_message_received_callback_ =
-      base::Bind(&SimpleHostMessageHandler, message_response_title,
-                 message_payload, run_loop_->QuitClosure(), &message_received);
-
-  protocol::ExtensionMessage message;
-  message.set_type(message_request_title);
-  message.set_data(message_payload);
-  connection_helper_->host_stub()->DeliverClientMessage(message);
-
-  base::OneShotTimer timer;
-  timer.Start(FROM_HERE, max_wait_time, run_loop_->QuitClosure());
-
-  run_loop_->Run();
-  timer.Stop();
-  host_message_received_callback_.Reset();
-
-  return message_received;
-}
-
-}  // namespace test
-}  // namespace remoting
diff --git a/remoting/test/app_remoting_connected_client_fixture.h b/remoting/test/app_remoting_connected_client_fixture.h
deleted file mode 100644
index 66f38b16..0000000
--- a/remoting/test/app_remoting_connected_client_fixture.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_TEST_APP_REMOTING_CONNECTED_CLIENT_FIXTURE_H_
-#define REMOTING_TEST_APP_REMOTING_CONNECTED_CLIENT_FIXTURE_H_
-
-#include <memory>
-#include <string>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "remoting/test/remote_connection_observer.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-class RunLoop;
-}
-
-namespace remoting {
-namespace test {
-
-struct RemoteApplicationDetails;
-class AppRemotingConnectionHelper;
-
-// Allows for custom handling of ExtensionMessage messages.
-typedef base::Callback<void(const protocol::ExtensionMessage& message)>
-    HostMessageReceivedCallback;
-
-// Creates a connection to a remote host which is available for tests to use.
-// All callbacks must occur on the same thread the object was created on.
-class AppRemotingConnectedClientFixture
-    : public testing::TestWithParam<const char*>,
-      public RemoteConnectionObserver {
- public:
-  AppRemotingConnectedClientFixture();
-  ~AppRemotingConnectedClientFixture() override;
-
- protected:
-  // Sends the request to the host and waits for a reply up to |max_wait_time|.
-  // Returns true if we received a response within the maximum time limit.
-  bool VerifyResponseForSimpleHostMessage(
-      const std::string& message_request_title,
-      const std::string& message_response_title,
-      const std::string& message_payload,
-      const base::TimeDelta& max_wait_time);
-
- private:
-  // testing::Test interface.
-  void SetUp() override;
-  void TearDown() override;
-
-  // RemoteConnectionObserver interface.
-  void HostMessageReceived(const protocol::ExtensionMessage& message) override;
-
-  // Handles messages from the host.
-  void HandleOnHostMessage(const remoting::protocol::ExtensionMessage& message);
-
-  // Contains the details for the application being tested.
-  const RemoteApplicationDetails& application_details_;
-
-  // Used to run the thread's message loop.
-  std::unique_ptr<base::RunLoop> run_loop_;
-
-  // Used to ensure RemoteConnectionObserver methods are called on the same
-  // thread.
-  base::ThreadChecker thread_checker_;
-
-  // Creates and manages the connection to the remote host.
-  std::unique_ptr<AppRemotingConnectionHelper> connection_helper_;
-
-  // Called when an ExtensionMessage is received from the host.
-  HostMessageReceivedCallback host_message_received_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppRemotingConnectedClientFixture);
-};
-
-}  // namespace test
-}  // namespace remoting
-
-#endif  // REMOTING_TEST_APP_REMOTING_CONNECTED_CLIENT_FIXTURE_H_
diff --git a/remoting/test/app_remoting_connection_helper.cc b/remoting/test/app_remoting_connection_helper.cc
deleted file mode 100644
index 478fb09..0000000
--- a/remoting/test/app_remoting_connection_helper.cc
+++ /dev/null
@@ -1,221 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/test/app_remoting_connection_helper.h"
-
-#include <utility>
-
-#include "base/json/json_reader.h"
-#include "base/logging.h"
-#include "base/run_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/values.h"
-#include "remoting/protocol/host_stub.h"
-#include "remoting/test/app_remoting_test_driver_environment.h"
-#include "remoting/test/remote_application_details.h"
-#include "remoting/test/test_chromoting_client.h"
-
-namespace {
-const int kDefaultDPI = 96;
-const int kDefaultWidth = 1024;
-const int kDefaultHeight = 768;
-
-const char kHostProcessWindowTitle[] = "Host Process";
-}  // namespace
-
-namespace remoting {
-namespace test {
-
-AppRemotingConnectionHelper::AppRemotingConnectionHelper(
-    const RemoteApplicationDetails& application_details)
-    : application_details_(application_details),
-      connection_is_ready_for_tests_(false) {}
-
-AppRemotingConnectionHelper::~AppRemotingConnectionHelper() {
-  // |client_| destroys some of its members via DeleteSoon on the message loop's
-  // TaskRunner so we need to run the loop until it has no more work to do.
-  if (!connection_is_ready_for_tests_) {
-    client_->RemoveRemoteConnectionObserver(this);
-  }
-  client_.reset();
-
-  base::RunLoop().RunUntilIdle();
-}
-
-void AppRemotingConnectionHelper::Initialize(
-    std::unique_ptr<TestChromotingClient> test_chromoting_client) {
-  client_ = std::move(test_chromoting_client);
-  client_->AddRemoteConnectionObserver(this);
-}
-
-bool AppRemotingConnectionHelper::StartConnection() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(client_);
-
-  RemoteHostInfo remote_host_info;
-  remoting::test::AppRemotingSharedData->GetRemoteHostInfoForApplicationId(
-      application_details_.application_id, &remote_host_info);
-
-  if (!remote_host_info.IsReadyForConnection()) {
-    return false;
-  }
-  remoting::test::AppRemotingSharedData->AddHostToReleaseList(
-      application_details_.application_id, remote_host_info.host_id);
-
-  DCHECK(!run_loop_ || !run_loop_->running());
-  run_loop_.reset(new base::RunLoop());
-
-  // We will wait up to 30 seconds to complete the remote connection and for the
-  // main application window to become visible.
-  DCHECK(!timer_.IsRunning());
-  timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(30),
-               run_loop_->QuitClosure());
-
-  client_->StartConnection(
-      /*use_test_api_settings=*/false,
-      remote_host_info.GenerateConnectionSetupInfo(
-          AppRemotingSharedData->access_token(),
-          AppRemotingSharedData->user_name()));
-
-  run_loop_->Run();
-  timer_.Stop();
-
-  if (connection_is_ready_for_tests_) {
-    return true;
-  } else {
-    client_->EndConnection();
-    return false;
-  }
-}
-
-protocol::ClipboardStub* AppRemotingConnectionHelper::clipboard_forwarder() {
-  return client_->clipboard_forwarder();
-}
-
-protocol::HostStub* AppRemotingConnectionHelper::host_stub() {
-  return client_->host_stub();
-}
-
-protocol::InputStub* AppRemotingConnectionHelper::input_stub() {
-  return client_->input_stub();
-}
-
-void AppRemotingConnectionHelper::ConnectionStateChanged(
-    protocol::ConnectionToHost::State state,
-    protocol::ErrorCode error_code) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  // If the connection is closed or failed then mark the connection as closed
-  // and quit the current RunLoop if it exists.
-  if (state == protocol::ConnectionToHost::CLOSED ||
-      state == protocol::ConnectionToHost::FAILED ||
-      error_code != protocol::OK) {
-    connection_is_ready_for_tests_ = false;
-
-    if (run_loop_) {
-      run_loop_->Quit();
-    }
-  }
-}
-
-void AppRemotingConnectionHelper::ConnectionReady(bool ready) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  if (ready) {
-    SendClientConnectionDetailsToHost();
-  } else {
-    // We will only get called here with a false value for |ready| if the video
-    // renderer encounters an error.
-    connection_is_ready_for_tests_ = false;
-
-    if (run_loop_) {
-      run_loop_->Quit();
-    }
-  }
-}
-
-void AppRemotingConnectionHelper::HostMessageReceived(
-    const protocol::ExtensionMessage& message) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  VLOG(2) << "HostMessage received by HostMessageReceived()."
-          << " type: " << message.type() << " data: " << message.data();
-
-  if (message.type() == "onWindowAdded") {
-    HandleOnWindowAddedMessage(message);
-  } else {
-    VLOG(2) << "HostMessage not handled by HostMessageReceived().";
-  }
-}
-
-void AppRemotingConnectionHelper::SendClientConnectionDetailsToHost() {
-  // First send an access token which will be used for Google Drive access.
-  protocol::ExtensionMessage message;
-  message.set_type("accessToken");
-  message.set_data(AppRemotingSharedData->access_token());
-
-  VLOG(1) << "Sending access token to host";
-  client_->host_stub()->DeliverClientMessage(message);
-
-  // Next send the host a description of the client screen size.
-  protocol::ClientResolution client_resolution;
-  client_resolution.set_width_deprecated(kDefaultWidth);
-  client_resolution.set_height_deprecated(kDefaultHeight);
-  client_resolution.set_x_dpi(kDefaultDPI);
-  client_resolution.set_y_dpi(kDefaultDPI);
-  client_resolution.set_dips_width(kDefaultWidth);
-  client_resolution.set_dips_height(kDefaultHeight);
-
-  VLOG(1) << "Sending ClientResolution details to host";
-  client_->host_stub()->NotifyClientResolution(client_resolution);
-
-  // Finally send a message to start sending us video packets.
-  protocol::VideoControl video_control;
-  video_control.set_enable(true);
-
-  VLOG(1) << "Sending enable VideoControl message to host";
-  client_->host_stub()->ControlVideo(video_control);
-}
-
-void AppRemotingConnectionHelper::HandleOnWindowAddedMessage(
-    const remoting::protocol::ExtensionMessage& message) {
-  DCHECK_EQ(message.type(), "onWindowAdded");
-
-  const base::DictionaryValue* message_data = nullptr;
-  std::unique_ptr<base::Value> host_message =
-      base::JSONReader::Read(message.data());
-  if (!host_message.get() || !host_message->GetAsDictionary(&message_data)) {
-    LOG(ERROR) << "onWindowAdded message received was not valid JSON.";
-    if (run_loop_) {
-      run_loop_->Quit();
-    }
-    return;
-  }
-
-  std::string current_window_title;
-  message_data->GetString("title", &current_window_title);
-  if (current_window_title == kHostProcessWindowTitle) {
-    LOG(ERROR) << "Host Process Window is visible, this likely means that the "
-               << "underlying application is in a bad state, YMMV.";
-  }
-
-  std::string main_window_title = application_details_.main_window_title;
-  if (current_window_title.find_first_of(main_window_title) == 0) {
-    connection_is_ready_for_tests_ = true;
-    client_->RemoveRemoteConnectionObserver(this);
-
-    if (timer_.IsRunning()) {
-      timer_.Stop();
-    }
-
-    DCHECK(run_loop_);
-    // Now that the main window is visible, give the app some time to settle
-    // before signaling that it is ready to run tests.
-    timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(2),
-                 run_loop_->QuitClosure());
-  }
-}
-
-}  // namespace test
-}  // namespace remoting
diff --git a/remoting/test/app_remoting_connection_helper.h b/remoting/test/app_remoting_connection_helper.h
deleted file mode 100644
index 7820d3a..0000000
--- a/remoting/test/app_remoting_connection_helper.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_TEST_APP_REMOTING_CONNECTION_HELPER_H_
-#define REMOTING_TEST_APP_REMOTING_CONNECTION_HELPER_H_
-
-#include <memory>
-#include <string>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/threading/thread_checker.h"
-#include "base/timer/timer.h"
-#include "remoting/test/remote_connection_observer.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-class RunLoop;
-}
-
-namespace remoting {
-namespace test {
-
-struct RemoteApplicationDetails;
-class TestChromotingClient;
-
-// Creates a connection to a remote host which is available for tests to use.
-// A TestChromotingClient is required from caller.
-class AppRemotingConnectionHelper
-    : public RemoteConnectionObserver {
- public:
-  explicit AppRemotingConnectionHelper(
-      const RemoteApplicationDetails& application_details);
-  ~AppRemotingConnectionHelper() override;
-
-  // Initialize internal structures.
-  void Initialize(std::unique_ptr<TestChromotingClient> test_chromoting_client);
-
-  // Starts a connection with the remote host.
-  // NOTE: Initialize() must be called before calling this method.
-  bool StartConnection();
-
-  // Stubs used to send messages to the remote host.
-  protocol::ClipboardStub* clipboard_forwarder();
-  protocol::HostStub* host_stub();
-  protocol::InputStub* input_stub();
-
-  TestChromotingClient* test_chromoting_client() { return client_.get(); }
-
-  // Returns true if connection is ready for tests.
-  bool ConnectionIsReadyForTest() { return connection_is_ready_for_tests_; }
-
- private:
-  // RemoteConnectionObserver interface.
-  void ConnectionStateChanged(protocol::ConnectionToHost::State state,
-                              protocol::ErrorCode error_code) override;
-  void ConnectionReady(bool ready) override;
-  void HostMessageReceived(const protocol::ExtensionMessage& message) override;
-
-  // Sends client details to the host in order to complete the connection.
-  void SendClientConnectionDetailsToHost();
-
-  // Handles onWindowAdded messages from the host.
-  void HandleOnWindowAddedMessage(
-      const remoting::protocol::ExtensionMessage& message);
-
-  // Contains the details for the application being tested.
-  const RemoteApplicationDetails& application_details_;
-
-  // Indicates whether the remote connection is ready to be used for testing.
-  // True when a chromoting connection to the remote host has been established
-  // and the main application window is visible.
-  bool connection_is_ready_for_tests_;
-
-  // Used to run the thread's message loop.
-  std::unique_ptr<base::RunLoop> run_loop_;
-
-  // Used for setting timeouts and delays.
-  base::OneShotTimer timer_;
-
-  // Used to ensure RemoteConnectionObserver methods are called on the same
-  // thread.
-  base::ThreadChecker thread_checker_;
-
-  // Creates and manages the connection to the remote host.
-  std::unique_ptr<TestChromotingClient> client_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppRemotingConnectionHelper);
-};
-
-}  // namespace test
-}  // namespace remoting
-
-#endif  // REMOTING_TEST_APP_REMOTING_CONNECTION_HELPER_H_
diff --git a/remoting/test/app_remoting_latency_test_fixture.cc b/remoting/test/app_remoting_latency_test_fixture.cc
deleted file mode 100644
index b011911..0000000
--- a/remoting/test/app_remoting_latency_test_fixture.cc
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/test/app_remoting_latency_test_fixture.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/run_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "remoting/proto/event.pb.h"
-#include "remoting/protocol/input_stub.h"
-#include "remoting/test/app_remoting_connection_helper.h"
-#include "remoting/test/app_remoting_test_driver_environment.h"
-#include "remoting/test/rgb_value.h"
-#include "remoting/test/test_chromoting_client.h"
-#include "remoting/test/test_video_renderer.h"
-
-namespace remoting {
-namespace test {
-
-AppRemotingLatencyTestFixture::AppRemotingLatencyTestFixture() {
-  // NOTE: Derived fixture must initialize application details in constructor.
-}
-
-AppRemotingLatencyTestFixture::~AppRemotingLatencyTestFixture() = default;
-
-void AppRemotingLatencyTestFixture::SetUp() {
-  std::unique_ptr<TestVideoRenderer> test_video_renderer(
-      new TestVideoRenderer());
-  test_video_renderer_ = test_video_renderer->GetWeakPtr();
-
-  std::unique_ptr<TestChromotingClient> test_chromoting_client(
-      new TestChromotingClient(std::move(test_video_renderer)));
-
-  test_chromoting_client->AddRemoteConnectionObserver(this);
-
-  connection_helper_.reset(
-      new AppRemotingConnectionHelper(GetApplicationDetails()));
-  connection_helper_->Initialize(std::move(test_chromoting_client));
-
-  if (!connection_helper_->StartConnection()) {
-    LOG(ERROR) << "Remote host connection could not be established.";
-    FAIL();
-  }
-
-  if (!PrepareApplicationForTesting()) {
-    LOG(ERROR) << "Unable to prepare application for testing.";
-    FAIL();
-  }
-}
-
-void AppRemotingLatencyTestFixture::TearDown() {
-  // Only reset application state when remote host connection is established.
-  if (connection_helper_->ConnectionIsReadyForTest()) {
-    ResetApplicationState();
-  }
-
-  connection_helper_->test_chromoting_client()->RemoveRemoteConnectionObserver(
-      this);
-  connection_helper_.reset();
-}
-
-WaitForImagePatternMatchCallback
-AppRemotingLatencyTestFixture::SetExpectedImagePattern(
-    const webrtc::DesktopRect& expected_rect,
-    const RGBValue& expected_color) {
-  std::unique_ptr<base::RunLoop> run_loop(new base::RunLoop());
-
-  test_video_renderer_->ExpectAverageColorInRect(expected_rect, expected_color,
-                                                 run_loop->QuitClosure());
-
-  return base::Bind(&AppRemotingLatencyTestFixture::WaitForImagePatternMatch,
-                    base::Unretained(this), base::Passed(&run_loop));
-}
-
-void AppRemotingLatencyTestFixture::SaveFrameDataToDisk(
-    bool save_frame_data_to_disk) {
-  test_video_renderer_->SaveFrameDataToDisk(save_frame_data_to_disk);
-}
-
-bool AppRemotingLatencyTestFixture::WaitForImagePatternMatch(
-    std::unique_ptr<base::RunLoop> run_loop,
-    const base::TimeDelta& max_wait_time) {
-  DCHECK(run_loop);
-  DCHECK(!timer_.IsRunning());
-
-  timer_.Start(FROM_HERE, max_wait_time, run_loop->QuitClosure());
-
-  run_loop->Run();
-
-  // Image pattern is matched if we stopped because of the reply not the timer.
-  bool image_pattern_is_matched = (timer_.IsRunning());
-  timer_.Stop();
-  run_loop.reset();
-
-  return image_pattern_is_matched;
-}
-
-void AppRemotingLatencyTestFixture::HostMessageReceived(
-    const protocol::ExtensionMessage& message) {
-  if (!host_message_received_callback_.is_null()) {
-    host_message_received_callback_.Run(message);
-  }
-}
-
-void AppRemotingLatencyTestFixture::PressKey(ui::DomCode dom_code,
-                                             bool pressed) {
-  remoting::protocol::KeyEvent event;
-  event.set_usb_keycode(static_cast<unsigned int>(dom_code));
-  event.set_pressed(pressed);
-  connection_helper_->input_stub()->InjectKeyEvent(event);
-}
-
-void AppRemotingLatencyTestFixture::PressAndReleaseKey(ui::DomCode dom_code) {
-  PressKey(dom_code, true);
-  PressKey(dom_code, false);
-}
-
-void AppRemotingLatencyTestFixture::PressAndReleaseKeyCombination(
-    const std::vector<ui::DomCode>& dom_codes) {
-  for (auto iter = dom_codes.begin(); iter != dom_codes.end(); ++iter) {
-    PressKey(*iter, true);
-  }
-  for (auto iter = dom_codes.rbegin(); iter != dom_codes.rend(); ++iter) {
-    PressKey(*iter, false);
-  }
-}
-
-void AppRemotingLatencyTestFixture::SetHostMessageReceivedCallback(
-    const HostMessageReceivedCallback& host_message_received_callback) {
-  host_message_received_callback_ = host_message_received_callback;
-}
-
-void AppRemotingLatencyTestFixture::ResetHostMessageReceivedCallback() {
-  host_message_received_callback_.Reset();
-}
-
-void AppRemotingLatencyTestFixture::ResetApplicationState() {
-  DCHECK(!timer_.IsRunning());
-  DCHECK(!run_loop_ || !run_loop_->running());
-
-  // Give the app some time to settle before reseting to initial state.
-  run_loop_.reset(new base::RunLoop());
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, run_loop_->QuitClosure(), base::TimeDelta::FromSeconds(1));
-  run_loop_->Run();
-
-  // Press Alt + F4 and wait for amount of time for the input to be delivered
-  // and processed.
-  std::vector<ui::DomCode> dom_codes;
-  dom_codes.push_back(ui::DomCode::ALT_LEFT);
-  dom_codes.push_back(ui::DomCode::F4);
-  PressAndReleaseKeyCombination(dom_codes);
-
-  run_loop_.reset(new base::RunLoop());
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, run_loop_->QuitClosure(), base::TimeDelta::FromSeconds(2));
-  run_loop_->Run();
-
-  // Press 'N' to choose not save and wait for 1 second for the input to be
-  // delivered and processed.
-  PressAndReleaseKey(ui::DomCode::US_N);
-
-  run_loop_.reset(new base::RunLoop());
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, run_loop_->QuitClosure(), base::TimeDelta::FromSeconds(2));
-  run_loop_->Run();
-  run_loop_.reset();
-}
-
-}  // namespace test
-}  // namespace remoting
diff --git a/remoting/test/app_remoting_latency_test_fixture.h b/remoting/test/app_remoting_latency_test_fixture.h
deleted file mode 100644
index 9a3df1bb..0000000
--- a/remoting/test/app_remoting_latency_test_fixture.h
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_TEST_APP_REMOTING_LATENCY_TEST_FIXTURE_H_
-#define REMOTING_TEST_APP_REMOTING_LATENCY_TEST_FIXTURE_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/timer/timer.h"
-#include "remoting/test/remote_connection_observer.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
-#include "ui/events/keycodes/dom/dom_code.h"
-
-namespace base {
-class RunLoop;
-class TimeDelta;
-}
-
-namespace webrtc {
-class DesktopRect;
-}
-
-namespace remoting {
-namespace test {
-
-struct RemoteApplicationDetails;
-struct RGBValue;
-class AppRemotingConnectionHelper;
-class TestVideoRenderer;
-
-// Allows for custom handling of ExtensionMessage messages.
-typedef base::Callback<void(const protocol::ExtensionMessage& message)>
-    HostMessageReceivedCallback;
-
-// Called to wait for expected image pattern to be matched within up to a max
-// wait time.
-typedef base::Callback<bool(const base::TimeDelta& max_wait_time)>
-    WaitForImagePatternMatchCallback;
-
-// Creates a connection to a remote host which is available for tests to use.
-// Provides convenient methods to create test cases to measure the input and
-// rendering latency between client and the remote host.
-// NOTE: This is an abstract class. To use it, please derive from this class
-// and implement GetApplicationDetails to specify the application details.
-class AppRemotingLatencyTestFixture : public testing::Test,
-                                      public RemoteConnectionObserver {
- public:
-  AppRemotingLatencyTestFixture();
-  ~AppRemotingLatencyTestFixture() override;
-
- protected:
-  // Set expected image pattern for comparison.
-  // A WaitForImagePatternMatchCallback is returned to allow waiting for the
-  // expected image pattern to be matched.
-  WaitForImagePatternMatchCallback SetExpectedImagePattern(
-      const webrtc::DesktopRect& expected_rect,
-      const RGBValue& expected_avg_color);
-
-  // Turn on/off saving video frames to disk.
-  void SaveFrameDataToDisk(bool save_frame_data_to_disk);
-
-  // Inject press & release key event.
-  void PressAndReleaseKey(ui::DomCode usb_keycode);
-
-  // Inject press & release a combination of key events.
-  void PressAndReleaseKeyCombination(
-      const std::vector<ui::DomCode>& usb_keycodes);
-
-  // Setter for |host_message_received_callback_|.
-  void SetHostMessageReceivedCallback(
-      const HostMessageReceivedCallback& host_message_received_callback);
-
-  // Reset |host_message_received_callback_| to null.
-  void ResetHostMessageReceivedCallback();
-
-  // Get the details of the application to be run.
-  virtual const RemoteApplicationDetails& GetApplicationDetails() = 0;
-
-  // Used to ensure the application under test is ready for testing.
-  virtual bool PrepareApplicationForTesting() = 0;
-
-  // Clean up the running application to initial state.
-  virtual void ResetApplicationState();
-
-  // Creates and manages the connection to the remote host.
-  std::unique_ptr<AppRemotingConnectionHelper> connection_helper_;
-
- private:
-  // testing::Test interface.
-  void SetUp() override;
-  void TearDown() override;
-
-  // RemoteConnectionObserver interface.
-  void HostMessageReceived(const protocol::ExtensionMessage& message) override;
-
-  // Inject press key event.
-  void PressKey(ui::DomCode usb_keycode, bool pressed);
-
-  // Waits for an image pattern matched reply up to |max_wait_time|. Returns
-  // true if we received a response within the maximum time limit.
-  // NOTE: This method should only be run when as a returned callback by
-  // SetExpectedImagePattern.
-  bool WaitForImagePatternMatch(std::unique_ptr<base::RunLoop> run_loop,
-                                const base::TimeDelta& max_wait_time);
-
-  // Used to run the thread's message loop.
-  std::unique_ptr<base::RunLoop> run_loop_;
-
-  // Used for setting timeouts and delays.
-  base::OneShotTimer timer_;
-
-  // Used to maintain a reference to the TestVideoRenderer instance while it
-  // exists.
-  base::WeakPtr<TestVideoRenderer> test_video_renderer_;
-
-  // Called when an ExtensionMessage is received from the host.  Used to
-  // override default message handling.
-  HostMessageReceivedCallback host_message_received_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppRemotingLatencyTestFixture);
-};
-
-}  // namespace test
-}  // namespace remoting
-
-#endif  // REMOTING_TEST_APP_REMOTING_LATENCY_TEST_FIXTURE_H_
diff --git a/remoting/test/app_remoting_report_issue_request.cc b/remoting/test/app_remoting_report_issue_request.cc
deleted file mode 100644
index a3a0eae..0000000
--- a/remoting/test/app_remoting_report_issue_request.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/test/app_remoting_report_issue_request.h"
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/logging.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_status_code.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "net/url_request/url_fetcher.h"
-#include "remoting/base/url_request_context_getter.h"
-
-namespace {
-const char kRequestTestOrigin[] =
-    "Origin: chrome-extension://ljacajndfccfgnfohlgkdphmbnpkjflk";
-}
-
-namespace remoting {
-namespace test {
-
-AppRemotingReportIssueRequest::AppRemotingReportIssueRequest() = default;
-
-AppRemotingReportIssueRequest::~AppRemotingReportIssueRequest() = default;
-
-bool AppRemotingReportIssueRequest::Start(
-    const std::string& application_id,
-    const std::string& host_id,
-    const std::string& access_token,
-    ServiceEnvironment service_environment,
-    bool abandon_host,
-    base::Closure done_callback) {
-  DCHECK(request_complete_callback_.is_null()) << "Request pending";
-
-  VLOG(2) << "AppRemotingReportIssueRequest::Start() called";
-
-  std::string service_url(
-      GetReportIssueUrl(application_id, host_id, service_environment));
-  if (service_url.empty()) {
-    LOG(ERROR) << "Unrecognized service type: " << service_environment;
-    return false;
-  }
-  VLOG(1) << "Sending Report Issue service request to: " << service_url;
-
-  request_complete_callback_ = done_callback;
-
-  request_context_getter_ = new remoting::URLRequestContextGetter(
-      base::ThreadTaskRunnerHandle::Get());
-
-  std::string upload_data = abandon_host ? "{ 'abandonHost': 'true' }" : "{}";
-
-  request_ = net::URLFetcher::Create(GURL(service_url), net::URLFetcher::POST,
-                                     this, TRAFFIC_ANNOTATION_FOR_TESTS);
-  request_->SetRequestContext(request_context_getter_.get());
-  request_->AddExtraRequestHeader("Authorization: OAuth " + access_token);
-  request_->AddExtraRequestHeader(kRequestTestOrigin);
-  request_->SetUploadData("application/json; charset=UTF-8", upload_data);
-  request_->Start();
-
-  return true;
-}
-
-void AppRemotingReportIssueRequest::OnURLFetchComplete(
-    const net::URLFetcher* source) {
-  VLOG(2) << "URL Fetch Completed for: " << source->GetOriginalURL();
-
-  int response_code = request_->GetResponseCode();
-  if (response_code != net::HTTP_OK && response_code != net::HTTP_NO_CONTENT) {
-    LOG(ERROR) << "ReportIssue request failed with error code: "
-               << response_code;
-  }
-
-  base::ResetAndReturn(&request_complete_callback_).Run();
-}
-
-}  // namespace test
-}  // namespace remoting
diff --git a/remoting/test/app_remoting_report_issue_request.h b/remoting/test/app_remoting_report_issue_request.h
deleted file mode 100644
index 8c41eb4..0000000
--- a/remoting/test/app_remoting_report_issue_request.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_TEST_APP_REMOTING_REPORT_ISSUE_REQUEST_H_
-#define REMOTING_TEST_APP_REMOTING_REPORT_ISSUE_REQUEST_H_
-
-#include <memory>
-#include <string>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "net/url_request/url_fetcher_delegate.h"
-#include "remoting/test/app_remoting_service_urls.h"
-
-namespace remoting {
-class URLRequestContextGetter;
-}
-
-namespace remoting {
-namespace test {
-
-// Calls the App Remoting service API to report an issue.  This is typically
-// used to abandon a remote host or to upload crash logs.
-// Must be used from a thread running an IO message loop.
-// The public method is virtual to allow for testing using a fake.
-class AppRemotingReportIssueRequest : public net::URLFetcherDelegate {
- public:
-  AppRemotingReportIssueRequest();
-  ~AppRemotingReportIssueRequest() override;
-
-  // Makes a service call to the ReportIssue API.
-  virtual bool Start(const std::string& application_id,
-                     const std::string& host_id,
-                     const std::string& access_token,
-                     ServiceEnvironment service_environment,
-                     bool abandon_host,
-                     base::Closure done_callback);
-
- private:
-  // net::URLFetcherDelegate interface.
-  void OnURLFetchComplete(const net::URLFetcher* source) override;
-
-  // Holds the URLFetcher for the ReportIssue request.
-  std::unique_ptr<net::URLFetcher> request_;
-
-  // Provides application-specific context for the network request.
-  scoped_refptr<remoting::URLRequestContextGetter> request_context_getter_;
-
-  // Caller-supplied callback which is signalled when the request is complete.
-  base::Closure request_complete_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppRemotingReportIssueRequest);
-};
-
-}  // namespace test
-}  // namespace remoting
-
-#endif  // REMOTING_TEST_APP_REMOTING_REPORT_ISSUE_REQUEST_H_
diff --git a/remoting/test/app_remoting_report_issue_request_unittest.cc b/remoting/test/app_remoting_report_issue_request_unittest.cc
deleted file mode 100644
index 194cf4e4e..0000000
--- a/remoting/test/app_remoting_report_issue_request_unittest.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/test/app_remoting_report_issue_request.h"
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/timer/timer.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-const char kTestApplicationId[] = "klasdfjlkasdfjklasjfdkljsadf";
-const char kTestHostId[] = "test_host_id_value";
-const char kAccessTokenValue[] = "test_access_token_value";
-const char kReportIssueResponse[] = "{}";
-}  // namespace
-
-namespace remoting {
-namespace test {
-
-// Provides base functionality for the AppRemotingReportIssueRequest Tests.  The
-// FakeURLFetcherFactory allows us to override the response data and payload for
-// specified URLs.  We use this to stub out network calls made by the
-// AppRemotingReportIssueRequest.  This fixture also creates an IO MessageLoop,
-// if necessary, for use by the AppRemotingReportIssueRequest class.
-class AppRemotingReportIssueRequestTest : public ::testing::Test {
- public:
-  AppRemotingReportIssueRequestTest();
-  ~AppRemotingReportIssueRequestTest() override;
-
- protected:
-  // testing::Test interface.
-  void SetUp() override;
-
-  // Sets the HTTP status and data returned for a specified URL.
-  void SetFakeResponse(const GURL& url,
-                       const std::string& data,
-                       net::HttpStatusCode code,
-                       net::URLRequestStatus::Status status);
-
-  // Used for result verification.
-  std::string dev_service_environment_url_;
-
-  std::unique_ptr<base::RunLoop> run_loop_;
-  base::OneShotTimer timer_;
-
-  AppRemotingReportIssueRequest app_remoting_report_issue_request_;
-
- private:
-  net::FakeURLFetcherFactory url_fetcher_factory_;
-  std::unique_ptr<base::MessageLoopForIO> message_loop_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppRemotingReportIssueRequestTest);
-};
-
-AppRemotingReportIssueRequestTest::AppRemotingReportIssueRequestTest()
-    : url_fetcher_factory_(nullptr), message_loop_(new base::MessageLoopForIO) {
-}
-
-AppRemotingReportIssueRequestTest::~AppRemotingReportIssueRequestTest() =
-    default;
-
-void AppRemotingReportIssueRequestTest::SetUp() {
-  run_loop_.reset(new base::RunLoop());
-
-  dev_service_environment_url_ =
-      GetReportIssueUrl(kTestApplicationId, kTestHostId, kDeveloperEnvironment);
-  SetFakeResponse(GURL(dev_service_environment_url_), kReportIssueResponse,
-                  net::HTTP_NOT_FOUND, net::URLRequestStatus::FAILED);
-}
-
-void AppRemotingReportIssueRequestTest::SetFakeResponse(
-    const GURL& url,
-    const std::string& data,
-    net::HttpStatusCode code,
-    net::URLRequestStatus::Status status) {
-  url_fetcher_factory_.SetFakeResponse(url, data, code, status);
-}
-
-TEST_F(AppRemotingReportIssueRequestTest, ReportIssueFromDev) {
-  SetFakeResponse(GURL(dev_service_environment_url_), kReportIssueResponse,
-                  net::HTTP_OK, net::URLRequestStatus::SUCCESS);
-
-  timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1),
-               run_loop_->QuitClosure());
-
-  bool request_started = app_remoting_report_issue_request_.Start(
-      kTestApplicationId, kTestHostId, kAccessTokenValue, kDeveloperEnvironment,
-      true, run_loop_->QuitClosure());
-  EXPECT_TRUE(request_started);
-
-  run_loop_->Run();
-
-  // Verify we stopped because of the request completing and not the timer.
-  EXPECT_TRUE(timer_.IsRunning());
-  timer_.Stop();
-}
-
-TEST_F(AppRemotingReportIssueRequestTest, ReportIssueFromInvalidEnvironment) {
-  bool request_started = app_remoting_report_issue_request_.Start(
-      kTestApplicationId, kTestHostId, kAccessTokenValue, kUnknownEnvironment,
-      true, run_loop_->QuitClosure());
-
-  EXPECT_FALSE(request_started);
-}
-
-TEST_F(AppRemotingReportIssueRequestTest, ReportIssueNetworkError) {
-  timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1),
-               run_loop_->QuitClosure());
-
-  bool request_started = app_remoting_report_issue_request_.Start(
-      kTestApplicationId, kTestHostId, kAccessTokenValue, kDeveloperEnvironment,
-      true, run_loop_->QuitClosure());
-  EXPECT_TRUE(request_started);
-
-  run_loop_->Run();
-
-  // Verify we stopped because of the request completing and not the timer.
-  EXPECT_TRUE(timer_.IsRunning());
-  timer_.Stop();
-}
-
-TEST_F(AppRemotingReportIssueRequestTest, MultipleRequestsCanBeIssued) {
-  SetFakeResponse(GURL(dev_service_environment_url_), kReportIssueResponse,
-                  net::HTTP_OK, net::URLRequestStatus::SUCCESS);
-
-  timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1),
-               run_loop_->QuitClosure());
-
-  bool request_started = app_remoting_report_issue_request_.Start(
-      kTestApplicationId, kTestHostId, kAccessTokenValue, kDeveloperEnvironment,
-      true, run_loop_->QuitClosure());
-  EXPECT_TRUE(request_started);
-
-  run_loop_->Run();
-
-  // Verify we stopped because of the request completing and not the timer.
-  EXPECT_TRUE(timer_.IsRunning());
-  timer_.Stop();
-
-  run_loop_.reset(new base::RunLoop());
-  timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1),
-               run_loop_->QuitClosure());
-
-  request_started = app_remoting_report_issue_request_.Start(
-      kTestApplicationId, kTestHostId, kAccessTokenValue, kDeveloperEnvironment,
-      true, run_loop_->QuitClosure());
-  EXPECT_TRUE(request_started);
-
-  run_loop_->Run();
-
-  // Verify we stopped because of the request completing and not the timer.
-  EXPECT_TRUE(timer_.IsRunning());
-  timer_.Stop();
-
-  run_loop_.reset(new base::RunLoop());
-  timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1),
-               run_loop_->QuitClosure());
-
-  request_started = app_remoting_report_issue_request_.Start(
-      kTestApplicationId, kTestHostId, kAccessTokenValue, kDeveloperEnvironment,
-      true, run_loop_->QuitClosure());
-  EXPECT_TRUE(request_started);
-
-  run_loop_->Run();
-
-  // Verify we stopped because of the request completing and not the timer.
-  EXPECT_TRUE(timer_.IsRunning());
-  timer_.Stop();
-}
-
-}  // namespace test
-}  // namespace remoting
diff --git a/remoting/test/app_remoting_sample_test_driver_environment.cc b/remoting/test/app_remoting_sample_test_driver_environment.cc
deleted file mode 100644
index d362eca..0000000
--- a/remoting/test/app_remoting_sample_test_driver_environment.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/memory/ptr_util.h"
-#include "remoting/test/app_remoting_test_driver_environment.h"
-
-namespace remoting {
-namespace test {
-
-std::unique_ptr<AppRemotingTestDriverEnvironment>
-CreateAppRemotingTestDriverEnvironment(
-    const AppRemotingTestDriverEnvironment::EnvironmentOptions& options) {
-  return base::WrapUnique<AppRemotingTestDriverEnvironment>(
-      new AppRemotingTestDriverEnvironment(options));
-}
-
-}  // namespace test
-}  // namespace remoting
diff --git a/remoting/test/app_remoting_service_urls.cc b/remoting/test/app_remoting_service_urls.cc
deleted file mode 100644
index a787cfa..0000000
--- a/remoting/test/app_remoting_service_urls.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/test/app_remoting_service_urls.h"
-
-#include "base/logging.h"
-#include "base/strings/stringprintf.h"
-
-namespace {
-// The placeholder is the environment endpoint qualifier.  No trailing slash
-// is added as it will be appended as needed later.
-const char kAppRemotingTestEndpointBase[] =
-    "https://www-googleapis-test.sandbox.google.com/appremoting/%s";
-const char kAppRemotingDevEndpointQualifier[] = "v1beta1_dev";
-
-// Placeholder value is for the Application ID.
-const char kRunApplicationApi[] = "applications/%s/run";
-
-// First placeholder value is for the Application ID.  Second placeholder is for
-// the Host ID to report the issue for.
-const char kReportIssueApi[] = "applications/%s/hosts/%s/reportIssue";
-}  // namespace
-
-namespace remoting {
-namespace test {
-
-bool IsSupportedServiceEnvironment(ServiceEnvironment service_environment) {
-  return (service_environment >= 0 &&
-          service_environment < kUnknownEnvironment);
-}
-
-std::string GetBaseUrl(ServiceEnvironment service_environment) {
-  std::string base_service_url;
-
-  if (service_environment == kDeveloperEnvironment) {
-    base_service_url = base::StringPrintf(kAppRemotingTestEndpointBase,
-                                          kAppRemotingDevEndpointQualifier);
-  }
-
-  return base_service_url;
-}
-
-std::string GetRunApplicationUrl(const std::string& extension_id,
-                                 ServiceEnvironment service_environment) {
-  std::string service_url;
-  if (!IsSupportedServiceEnvironment(service_environment)) {
-    return service_url;
-  }
-
-  service_url = GetBaseUrl(service_environment);
-  if (!service_url.empty()) {
-    std::string api_string =
-        base::StringPrintf(kRunApplicationApi, extension_id.c_str());
-    service_url =
-        base::StringPrintf("%s/%s", service_url.c_str(), api_string.c_str());
-  }
-
-  return service_url;
-}
-
-std::string GetReportIssueUrl(const std::string& extension_id,
-                              const std::string& host_id,
-                              ServiceEnvironment service_environment) {
-  std::string service_url;
-  if (!IsSupportedServiceEnvironment(service_environment)) {
-    return service_url;
-  }
-
-  service_url = GetBaseUrl(service_environment);
-  if (!service_url.empty()) {
-    std::string api_string = base::StringPrintf(
-        kReportIssueApi, extension_id.c_str(), host_id.c_str());
-    service_url =
-        base::StringPrintf("%s/%s", service_url.c_str(), api_string.c_str());
-  }
-
-  return service_url;
-}
-
-}  // namespace test
-}  // namespace remoting
diff --git a/remoting/test/app_remoting_service_urls.h b/remoting/test/app_remoting_service_urls.h
deleted file mode 100644
index 7d1226b..0000000
--- a/remoting/test/app_remoting_service_urls.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_TEST_APP_REMOTING_SERVICE_URLS_H_
-#define REMOTING_TEST_APP_REMOTING_SERVICE_URLS_H_
-
-#include <string>
-
-namespace remoting {
-namespace test {
-
-// Specifies the service API to call for app remoting host information.
-// Note: When adding new environments, add them before kUnknownEnvironment as
-//       the last entry is used for bounds checking.
-enum ServiceEnvironment {
-  kDeveloperEnvironment,
-  kUnknownEnvironment
-};
-
-// Used to determine if the service_environment is one of the supported values.
-bool IsSupportedServiceEnvironment(ServiceEnvironment service_environment);
-
-// Generates and returns a URL for the specified application and environment to
-// request remote host details.
-std::string GetRunApplicationUrl(const std::string& extension_id,
-                                 ServiceEnvironment service_environment);
-
-// Generates and returns a URL for the specified application and environment to
-// report an issue.
-std::string GetReportIssueUrl(const std::string& extension_id,
-                              const std::string& host_id,
-                              ServiceEnvironment service_environment);
-
-}  // namespace test
-}  // namespace remoting
-
-#endif  // REMOTING_TEST_APP_REMOTING_SERVICE_URLS_H_
diff --git a/remoting/test/app_remoting_test_driver.cc b/remoting/test/app_remoting_test_driver.cc
deleted file mode 100644
index 310ee4a..0000000
--- a/remoting/test/app_remoting_test_driver.cc
+++ /dev/null
@@ -1,269 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/at_exit.h"
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/stringprintf.h"
-#include "base/test/launcher/unit_test_launcher.h"
-#include "base/test/test_suite.h"
-#include "base/test/test_switches.h"
-#include "google_apis/google_api_keys.h"
-#include "net/base/escape.h"
-#include "remoting/test/app_remoting_test_driver_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace switches {
-const char kAuthCodeSwitchName[] = "authcode";
-const char kHelpSwitchName[] = "help";
-const char kLoggingLevelSwitchName[] = "verbosity";
-const char kRefreshTokenFileSwitchName[] = "refresh-token-file";
-const char kReleaseHostsAfterTestingSwitchName[] = "release-hosts-after-tests";
-const char kShowHostAvailabilitySwitchName[] = "show-host-availability";
-const char kSingleProcessTestsSwitchName[] = "single-process-tests";
-const char kUserNameSwitchName[] = "username";
-}  // namespace switches
-
-namespace {
-
-// Requested permissions needed for App Remoting tests.  The spaces in between
-// scope fragments are necessary and will be escaped properly before use.
-const char kAppRemotingAuthScopeValues[] =
-    "https://www.googleapis.com/auth/appremoting.runapplication"
-    " https://www.googleapis.com/auth/googletalk"
-    " https://www.googleapis.com/auth/userinfo.email"
-    " https://docs.google.com/feeds"
-    " https://www.googleapis.com/auth/drive";
-
-std::string GetAuthorizationCodeUri() {
-  // Replace space characters with a '+' sign when formatting.
-  bool use_plus = true;
-  return base::StringPrintf(
-      "https://accounts.google.com/o/oauth2/auth"
-      "?scope=%s"
-      "&redirect_uri=https://chromoting-oauth.talkgadget.google.com/"
-      "talkgadget/oauth/chrome-remote-desktop/dev"
-      "&response_type=code"
-      "&client_id=%s"
-      "&access_type=offline"
-      "&approval_prompt=force",
-      net::EscapeUrlEncodedData(kAppRemotingAuthScopeValues, use_plus).c_str(),
-      net::EscapeUrlEncodedData(
-          google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING),
-          use_plus).c_str());
-}
-
-void PrintUsage() {
-  printf("\n**************************************\n");
-  printf("*** App Remoting Test Driver Usage ***\n");
-  printf("**************************************\n");
-
-  printf("\nUsage:\n");
-  printf("  ar_test_driver --username=<example@gmail.com> [options]\n");
-  printf("\nRequired Parameters:\n");
-  printf("  %s: Specifies which account to use when running tests\n",
-         switches::kUserNameSwitchName);
-  printf("\nOptional Parameters:\n");
-  printf("  %s: Exchanged for a refresh and access token for authentication\n",
-         switches::kAuthCodeSwitchName);
-  printf("  %s: Path to a JSON file containing username/refresh_token KVPs\n",
-         switches::kRefreshTokenFileSwitchName);
-  printf("  %s: Displays additional usage information\n",
-         switches::kHelpSwitchName);
-  printf(
-      "  %s: Retrieves and displays the connection status for all known "
-      "hosts, no tests will be run\n",
-      switches::kShowHostAvailabilitySwitchName);
-  printf(
-      "  %s: Send a message to the service after all tests have been run to "
-      "release remote hosts the tool used for testing.\n",
-      switches::kReleaseHostsAfterTestingSwitchName);
-  printf(
-      "  %s: Specifies the optional logging level of the tool (0-3)."
-      " [default: off]\n",
-      switches::kLoggingLevelSwitchName);
-}
-
-void PrintAuthCodeInfo() {
-  printf("\n*******************************\n");
-  printf("*** Auth Code Example Usage ***\n");
-  printf("*******************************\n\n");
-
-  printf("If this is the first time you are running the tool,\n");
-  printf("you will need to provide an authorization code.\n");
-  printf("This code will be exchanged for a long term refresh token which\n");
-  printf("will be stored locally and used to acquire a short lived access\n");
-  printf("token to connect to the remoting service apis and establish a\n");
-  printf("remote host connection.\n\n");
-
-  printf("Note: You may need to repeat this step if the stored refresh token");
-  printf("\n      has been revoked or expired.\n");
-  printf("      Passing in the same auth code twice will result in an error\n");
-
-  printf(
-      "\nFollow these steps to produce an auth code:\n"
-      " - Open the Authorization URL link shown below in your browser\n"
-      " - Approve the requested permissions for the tool\n"
-      " - Copy the 'code' value in the redirected URL\n"
-      " - Run the tool and pass in copied auth code as a parameter\n");
-
-  printf("\nAuthorization URL:\n");
-  printf("%s\n", GetAuthorizationCodeUri().c_str());
-
-  printf("\nRedirected URL Example:\n");
-  printf(
-      "https://chromoting-oauth.talkgadget.google.com/talkgadget/oauth/"
-      "chrome-remote-desktop/dev?code=4/AKtf...\n");
-
-  printf("\nTool usage example with the newly created auth code:\n");
-  printf("ar_test_driver --%s=example@gmail.com --%s=4/AKtf...\n\n",
-         switches::kUserNameSwitchName, switches::kAuthCodeSwitchName);
-}
-
-void PrintJsonFileInfo() {
-  printf("\n*****************************************\n");
-  printf("*** Refresh Token File Example Usage ***\n");
-  printf("****************************************\n\n");
-
-  printf("In order to use this option, a valid JSON file must exist, be\n");
-  printf("properly formatted, and contain a username/token KVP.\n");
-  printf("Contents of example_file.json\n");
-  printf("{\n");
-  printf("  \"username1@fauxdomain.com\": \"1/3798Gsdf898shksdvfyi8sshad\",\n");
-  printf("  \"username2@fauxdomain.com\": \"1/8974sdf87asdgadfgaerhfRsAa\",\n");
-  printf("}\n\n");
-
-  printf("\nTool usage example:\n");
-  printf("ar_test_driver --%s=%s --%s=./example_file.json\n\n",
-         switches::kUserNameSwitchName, "username1@fauxdomain.com",
-         switches::kRefreshTokenFileSwitchName);
-}
-
-}  // namespace
-
-int main(int argc, char** argv) {
-  base::TestSuite test_suite(argc, argv);
-  base::MessageLoopForIO message_loop;
-
-  if (!base::CommandLine::InitializedForCurrentProcess()) {
-    if (!base::CommandLine::Init(argc, argv)) {
-      LOG(ERROR) << "Failed to initialize command line singleton.";
-      return -1;
-    }
-  }
-
-  // The pointer returned here refers to a singleton, since we don't own the
-  // lifetime of the object, don't wrap in a scoped_ptr construct or release it.
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  DCHECK(command_line);
-
-  // We do not want to retry failures as a failed test should signify an error
-  // to be investigated.
-  command_line->AppendSwitchASCII(switches::kTestLauncherRetryLimit, "0");
-  command_line->AppendSwitchASCII(
-      switches::kIsolatedScriptTestLauncherRetryLimit, "0");
-
-  // We do not want to run the tests in parallel and we do not want to retry
-  // failures.  The reason for running in a single process is that some tests
-  // may share the same remoting host and they cannot be run concurrently, also
-  // the test output gets spammed with test launcher messages which reduces the
-  // readability of the results.
-  command_line->AppendSwitch(switches::kSingleProcessTestsSwitchName);
-
-  // If the user passed in the help flag, then show the help info for this tool
-  // and 'run' the tests which will print the gtest specific help and then exit.
-  // NOTE: We do this check after updating the switches as otherwise the gtest
-  //       help is written in parallel with our text and can appear interleaved.
-  if (command_line->HasSwitch(switches::kHelpSwitchName)) {
-    PrintUsage();
-    PrintJsonFileInfo();
-    PrintAuthCodeInfo();
-#if defined(OS_IOS)
-    return base::LaunchUnitTests(
-        argc, argv,
-        base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
-#else
-    return base::LaunchUnitTestsSerially(
-        argc, argv,
-        base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
-#endif
-  }
-
-  remoting::test::AppRemotingTestDriverEnvironment::EnvironmentOptions options;
-
-  // Verify we received the required input from the command line.
-  options.user_name =
-      command_line->GetSwitchValueASCII(switches::kUserNameSwitchName);
-  if (options.user_name.empty()) {
-    LOG(ERROR) << "No user name passed in, can't authenticate without that!";
-    PrintUsage();
-    return -1;
-  }
-  VLOG(1) << "Running tests as: " << options.user_name;
-
-  // Check to see if the user passed in a one time use auth_code for
-  // refreshing their credentials.
-  std::string auth_code(
-      command_line->GetSwitchValueASCII(switches::kAuthCodeSwitchName));
-
-  options.refresh_token_file_path =
-      command_line->GetSwitchValuePath(switches::kRefreshTokenFileSwitchName);
-
-  options.release_hosts_when_done =
-      command_line->HasSwitch(switches::kReleaseHostsAfterTestingSwitchName);
-
-  options.service_environment =
-        remoting::test::ServiceEnvironment::kDeveloperEnvironment;
-
-  // Update the logging verbosity level is user specified one.
-  std::string verbosity_level(
-      command_line->GetSwitchValueASCII(switches::kLoggingLevelSwitchName));
-  if (!verbosity_level.empty()) {
-    // Turn on logging for the test_driver and remoting components.
-    // This switch is parsed during logging::InitLogging.
-    command_line->AppendSwitchASCII("vmodule",
-                                    "*/remoting/*=" + verbosity_level);
-    logging::LoggingSettings logging_settings;
-    logging::InitLogging(logging_settings);
-  }
-
-  // Create and register our global test data object.  It will handle
-  // retrieving an access token for the user and spinning up VMs.
-  // The GTest framework will own the lifetime of this object once
-  // it is registered below.
-  std::unique_ptr<remoting::test::AppRemotingTestDriverEnvironment> shared_data(
-      remoting::test::CreateAppRemotingTestDriverEnvironment(options));
-
-  if (!shared_data->Initialize(auth_code)) {
-    // If we failed to initialize our shared data object, then bail.
-    return -1;
-  }
-
-  if (command_line->HasSwitch(switches::kShowHostAvailabilitySwitchName)) {
-    // When this flag is specified, we will retrieve connection information
-    // for all known applications and report the status.  Tests can be skipped
-    // using a gtest_filter flag.
-    shared_data->ShowHostAvailability();
-  }
-
-  // Since we've successfully set up our shared_data object, we'll assign the
-  // value to our global* and transfer ownership to the framework.
-  remoting::test::AppRemotingSharedData = shared_data.release();
-  testing::AddGlobalTestEnvironment(remoting::test::AppRemotingSharedData);
-
-  // Because many tests may access the same remoting host(s), we need to run
-  // the tests sequentially so they do not interfere with each other.
-#if defined(OS_IOS)
-  return base::LaunchUnitTests(
-      argc, argv,
-      base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
-#else
-  return base::LaunchUnitTestsSerially(
-      argc, argv,
-      base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
-#endif
-}
diff --git a/remoting/test/app_remoting_test_driver_environment.cc b/remoting/test/app_remoting_test_driver_environment.cc
deleted file mode 100644
index c88cfa4..0000000
--- a/remoting/test/app_remoting_test_driver_environment.cc
+++ /dev/null
@@ -1,362 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/test/app_remoting_test_driver_environment.h"
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback_forward.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_current.h"
-#include "base/run_loop.h"
-#include "base/strings/stringprintf.h"
-#include "remoting/test/access_token_fetcher.h"
-#include "remoting/test/app_remoting_report_issue_request.h"
-#include "remoting/test/refresh_token_store.h"
-#include "remoting/test/remote_host_info.h"
-
-namespace remoting {
-namespace test {
-
-AppRemotingTestDriverEnvironment* AppRemotingSharedData;
-
-AppRemotingTestDriverEnvironment::EnvironmentOptions::EnvironmentOptions()
-    : refresh_token_file_path(base::FilePath()),
-      service_environment(kUnknownEnvironment),
-      release_hosts_when_done(false) {}
-
-AppRemotingTestDriverEnvironment::EnvironmentOptions::~EnvironmentOptions() =
-    default;
-
-AppRemotingTestDriverEnvironment::AppRemotingTestDriverEnvironment(
-    const EnvironmentOptions& options)
-    : user_name_(options.user_name),
-      service_environment_(options.service_environment),
-      release_hosts_when_done_(options.release_hosts_when_done),
-      refresh_token_file_path_(options.refresh_token_file_path),
-      test_access_token_fetcher_(nullptr),
-      test_app_remoting_report_issue_request_(nullptr),
-      test_refresh_token_store_(nullptr),
-      test_remote_host_info_fetcher_(nullptr) {
-  DCHECK(!user_name_.empty());
-  DCHECK(service_environment_ < kUnknownEnvironment);
-}
-
-AppRemotingTestDriverEnvironment::~AppRemotingTestDriverEnvironment() = default;
-
-bool AppRemotingTestDriverEnvironment::Initialize(
-    const std::string& auth_code) {
-  if (!access_token_.empty()) {
-    return true;
-  }
-
-  if (!base::MessageLoopCurrent::Get()) {
-    message_loop_.reset(new base::MessageLoopForIO);
-  }
-
-  // If a unit test has set |test_refresh_token_store_| then we should use it
-  // below.  Note that we do not want to destroy the test object.
-  std::unique_ptr<RefreshTokenStore> temporary_refresh_token_store;
-  RefreshTokenStore* refresh_token_store = test_refresh_token_store_;
-  if (!refresh_token_store) {
-    temporary_refresh_token_store =
-        RefreshTokenStore::OnDisk(user_name_, refresh_token_file_path_);
-    refresh_token_store = temporary_refresh_token_store.get();
-  }
-
-  // Check to see if we have a refresh token stored for this user.
-  refresh_token_ = refresh_token_store->FetchRefreshToken();
-  if (refresh_token_.empty()) {
-    // This isn't necessarily an error as this might be a first run scenario.
-    VLOG(2) << "No refresh token stored for " << user_name_;
-
-    if (auth_code.empty()) {
-      // No token and no Auth code means no service connectivity, bail!
-      LOG(ERROR) << "Cannot retrieve an access token without a stored refresh"
-                 << " token on disk or an auth_code passed into the tool";
-      return false;
-    }
-  }
-
-  if (!RetrieveAccessToken(auth_code)) {
-    // If we cannot retrieve an access token, then nothing is going to work and
-    // we should let the caller know that our object is not ready to be used.
-    return false;
-  }
-
-  return true;
-}
-
-bool AppRemotingTestDriverEnvironment::RefreshAccessToken() {
-  DCHECK(!refresh_token_.empty());
-
-  // Empty auth code is used when refreshing.
-  return RetrieveAccessToken(std::string());
-}
-
-bool AppRemotingTestDriverEnvironment::GetRemoteHostInfoForApplicationId(
-    const std::string& application_id,
-    RemoteHostInfo* remote_host_info) {
-  DCHECK(!application_id.empty());
-  DCHECK(remote_host_info);
-
-  if (access_token_.empty()) {
-    LOG(ERROR) << "RemoteHostInfo requested without a valid access token. "
-               << "Ensure the environment object has been initialized.";
-    return false;
-  }
-
-  base::RunLoop run_loop;
-
-  RemoteHostInfoCallback remote_host_info_fetch_callback = base::Bind(
-      &AppRemotingTestDriverEnvironment::OnRemoteHostInfoRetrieved,
-      base::Unretained(this), run_loop.QuitClosure(), remote_host_info);
-
-  // If a unit test has set |test_remote_host_info_fetcher_| then we should use
-  // it below.  Note that we do not want to destroy the test object at the end
-  // of the function which is why we have the dance below.
-  std::unique_ptr<RemoteHostInfoFetcher> temporary_remote_host_info_fetcher;
-  RemoteHostInfoFetcher* remote_host_info_fetcher =
-      test_remote_host_info_fetcher_;
-  if (!remote_host_info_fetcher) {
-    temporary_remote_host_info_fetcher.reset(new RemoteHostInfoFetcher());
-    remote_host_info_fetcher = temporary_remote_host_info_fetcher.get();
-  }
-
-  remote_host_info_fetcher->RetrieveRemoteHostInfo(
-      application_id, access_token_, service_environment_,
-      remote_host_info_fetch_callback);
-
-  run_loop.Run();
-
-  return remote_host_info->IsReadyForConnection();
-}
-
-void AppRemotingTestDriverEnvironment::AddHostToReleaseList(
-    const std::string& application_id,
-    const std::string& host_id) {
-  if (!release_hosts_when_done_) {
-    return;
-  }
-
-  auto map_iterator = host_ids_to_release_.find(application_id);
-  if (map_iterator == host_ids_to_release_.end()) {
-    std::vector<std::string> host_id_list(1, host_id);
-    host_ids_to_release_.insert(std::make_pair(application_id, host_id_list));
-  } else {
-    std::vector<std::string>* host_ids = &map_iterator->second;
-    if (std::find(host_ids->begin(), host_ids->end(), host_id) ==
-        host_ids->end()) {
-      host_ids->push_back(host_id);
-    }
-  }
-}
-
-void AppRemotingTestDriverEnvironment::ShowHostAvailability() {
-  const char kHostAvailabilityFormatString[] = "%-25s%-35s%-10s";
-
-  LOG(INFO) << base::StringPrintf(kHostAvailabilityFormatString,
-                                  "Application Name", "Application ID",
-                                  "Status");
-
-  for (const auto& application_name : application_names_) {
-    const RemoteApplicationDetails& application_details =
-        GetDetailsFromAppName(application_name);
-
-    RemoteHostInfo remote_host_info;
-    GetRemoteHostInfoForApplicationId(application_details.application_id,
-                                      &remote_host_info);
-
-    std::string status;
-    RemoteHostStatus remote_host_status = remote_host_info.remote_host_status;
-    if (remote_host_status == kRemoteHostStatusReady) {
-      status = "Ready :)";
-    } else if (remote_host_status == kRemoteHostStatusPending) {
-      status = "Pending :|";
-    } else {
-      status = "Unknown :(";
-    }
-
-    LOG(INFO) << base::StringPrintf(
-        kHostAvailabilityFormatString, application_name.c_str(),
-        application_details.application_id.c_str(), status.c_str());
-  }
-}
-
-const RemoteApplicationDetails&
-AppRemotingTestDriverEnvironment::GetDetailsFromAppName(
-    const std::string& application_name) {
-  const auto map_pair_iterator =
-      application_details_map_.find(application_name);
-  DCHECK(map_pair_iterator != application_details_map_.end());
-
-  return map_pair_iterator->second;
-}
-
-void AppRemotingTestDriverEnvironment::SetAccessTokenFetcherForTest(
-    AccessTokenFetcher* access_token_fetcher) {
-  DCHECK(access_token_fetcher);
-
-  test_access_token_fetcher_ = access_token_fetcher;
-}
-
-void AppRemotingTestDriverEnvironment::SetAppRemotingReportIssueRequestForTest(
-    AppRemotingReportIssueRequest* app_remoting_report_issue_request) {
-  DCHECK(app_remoting_report_issue_request);
-
-  test_app_remoting_report_issue_request_ = app_remoting_report_issue_request;
-}
-
-void AppRemotingTestDriverEnvironment::SetRefreshTokenStoreForTest(
-    RefreshTokenStore* refresh_token_store) {
-  DCHECK(refresh_token_store);
-
-  test_refresh_token_store_ = refresh_token_store;
-}
-
-void AppRemotingTestDriverEnvironment::SetRemoteHostInfoFetcherForTest(
-    RemoteHostInfoFetcher* remote_host_info_fetcher) {
-  DCHECK(remote_host_info_fetcher);
-
-  test_remote_host_info_fetcher_ = remote_host_info_fetcher;
-}
-
-void AppRemotingTestDriverEnvironment::TearDown() {
-  // If a unit test has set |test_app_remoting_report_issue_request_| then we
-  // should use it below.  Note that we do not want to destroy the test object
-  // at the end of the function which is why we have the dance below.
-  std::unique_ptr<AppRemotingReportIssueRequest> temporary_report_issue_request;
-  AppRemotingReportIssueRequest* report_issue_request =
-      test_app_remoting_report_issue_request_;
-  if (!report_issue_request) {
-    temporary_report_issue_request.reset(new AppRemotingReportIssueRequest());
-    report_issue_request = temporary_report_issue_request.get();
-  }
-
-  for (const auto& kvp : host_ids_to_release_) {
-    std::string application_id = kvp.first;
-    VLOG(1) << "Releasing hosts for application: " << application_id;
-
-    for (const auto& host_id : kvp.second) {
-      base::RunLoop run_loop;
-
-      VLOG(1) << "    Releasing host: " << host_id;
-      bool request_started = report_issue_request->Start(
-          application_id, host_id, access_token_, service_environment_, true,
-          run_loop.QuitClosure());
-
-      if (request_started) {
-        run_loop.Run();
-      } else {
-        LOG(ERROR) << "Failed to send ReportIssueRequest for: "
-                   << application_id << ", " << host_id;
-      }
-    }
-  }
-  temporary_report_issue_request.reset();
-
-  // Letting the MessageLoop tear down during the test destructor results in
-  // errors after test completion, when the MessageLoop dtor touches the
-  // registered AtExitManager. The AtExitManager is torn down before the test
-  // destructor is executed, so we tear down the MessageLoop here, while it is
-  // still valid.
-  message_loop_.reset();
-}
-
-bool AppRemotingTestDriverEnvironment::RetrieveAccessToken(
-    const std::string& auth_code) {
-  base::RunLoop run_loop;
-
-  access_token_.clear();
-
-  AccessTokenCallback access_token_callback =
-      base::Bind(&AppRemotingTestDriverEnvironment::OnAccessTokenRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
-
-  // If a unit test has set |test_access_token_fetcher_| then we should use it
-  // below.  Note that we do not want to destroy the test object at the end of
-  // the function which is why we have the dance below.
-  std::unique_ptr<AccessTokenFetcher> temporary_access_token_fetcher;
-  AccessTokenFetcher* access_token_fetcher = test_access_token_fetcher_;
-  if (!access_token_fetcher) {
-    temporary_access_token_fetcher.reset(new AccessTokenFetcher());
-    access_token_fetcher = temporary_access_token_fetcher.get();
-  }
-
-  if (!auth_code.empty()) {
-    // If the user passed in an authcode, then use it to retrieve an
-    // updated access/refresh token.
-    access_token_fetcher->GetAccessTokenFromAuthCode(auth_code,
-                                                     access_token_callback);
-  } else {
-    DCHECK(!refresh_token_.empty());
-
-    access_token_fetcher->GetAccessTokenFromRefreshToken(refresh_token_,
-                                                         access_token_callback);
-  }
-
-  run_loop.Run();
-
-  // If we were using an auth_code and received a valid refresh token,
-  // then we want to store it locally.  If we had an auth code and did not
-  // receive a refresh token, then we should let the user know and exit.
-  if (!auth_code.empty()) {
-    if (!refresh_token_.empty()) {
-      // If a unit test has set |test_refresh_token_store_| then we should use
-      // it below.  Note that we do not want to destroy the test object.
-      std::unique_ptr<RefreshTokenStore> temporary_refresh_token_store;
-      RefreshTokenStore* refresh_token_store = test_refresh_token_store_;
-      if (!refresh_token_store) {
-        temporary_refresh_token_store =
-            RefreshTokenStore::OnDisk(user_name_, refresh_token_file_path_);
-        refresh_token_store = temporary_refresh_token_store.get();
-      }
-
-      if (!refresh_token_store->StoreRefreshToken(refresh_token_)) {
-        // If we failed to persist the refresh token, then we should let the
-        // user sort out the issue before continuing.
-        return false;
-      }
-    } else {
-      LOG(ERROR) << "Failed to use AUTH CODE to retrieve a refresh token.\n"
-                 << "Was the one-time use AUTH CODE used more than once?";
-      return false;
-    }
-  }
-
-  if (access_token_.empty()) {
-    LOG(ERROR) << "Failed to retrieve access token.";
-    return false;
-  }
-
-  return true;
-}
-
-void AppRemotingTestDriverEnvironment::OnAccessTokenRetrieved(
-    base::Closure done_closure,
-    const std::string& access_token,
-    const std::string& refresh_token) {
-  access_token_ = access_token;
-  refresh_token_ = refresh_token;
-
-  done_closure.Run();
-}
-
-void AppRemotingTestDriverEnvironment::OnRemoteHostInfoRetrieved(
-    base::Closure done_closure,
-    RemoteHostInfo* remote_host_info,
-    const RemoteHostInfo& retrieved_remote_host_info) {
-  DCHECK(remote_host_info);
-
-  *remote_host_info = retrieved_remote_host_info;
-
-  done_closure.Run();
-}
-
-}  // namespace test
-}  // namespace remoting
diff --git a/remoting/test/app_remoting_test_driver_environment.h b/remoting/test/app_remoting_test_driver_environment.h
deleted file mode 100644
index 6bbb43f..0000000
--- a/remoting/test/app_remoting_test_driver_environment.h
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_TEST_APP_REMOTING_TEST_DRIVER_ENVIRONMENT_H_
-#define REMOTING_TEST_APP_REMOTING_TEST_DRIVER_ENVIRONMENT_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "remoting/test/remote_application_details.h"
-#include "remoting/test/remote_host_info_fetcher.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-class MessageLoopForIO;
-}
-
-namespace remoting {
-namespace test {
-
-class AccessTokenFetcher;
-class AppRemotingReportIssueRequest;
-class RefreshTokenStore;
-struct RemoteHostInfo;
-
-// Globally accessible to all test fixtures and cases and has its
-// lifetime managed by the GTest framework.  It is responsible for managing
-// access tokens and retrieving remote host connection information.
-class AppRemotingTestDriverEnvironment : public testing::Environment {
- public:
-  struct EnvironmentOptions {
-    EnvironmentOptions();
-    ~EnvironmentOptions();
-
-    std::string user_name;
-    base::FilePath refresh_token_file_path;
-    ServiceEnvironment service_environment;
-    bool release_hosts_when_done;
-  };
-
-  explicit AppRemotingTestDriverEnvironment(const EnvironmentOptions& options);
-  ~AppRemotingTestDriverEnvironment() override;
-
-  // Returns false if a valid access token cannot be retrieved.
-  bool Initialize(const std::string& auth_code);
-
-  // Synchronously request a new access token using |refresh_token_|.
-  // Returns true if a valid access token has been retrieved.
-  bool RefreshAccessToken();
-
-  // Synchronously request remote host information for |application_id|.
-  // Returns true if the request was successful and |remote_host_info| is valid.
-  bool GetRemoteHostInfoForApplicationId(const std::string& application_id,
-                                         RemoteHostInfo* remote_host_info);
-
-  // Adds the host_id to the list of hosts that will be released after the tests
-  // have all been run.
-  void AddHostToReleaseList(const std::string& application_id,
-                            const std::string& host_id);
-
-  // Retrieves connection information for all known applications and displays
-  // their availability to STDOUT.
-  void ShowHostAvailability();
-
-  // Provides the RemoteApplicationDetails for the specified |application_name|.
-  const RemoteApplicationDetails& GetDetailsFromAppName(
-      const std::string& application_name);
-
-  // Used to set fake/mock objects for AppRemotingTestDriverEnvironment tests.
-  // The caller retains ownership of the supplied objects, and must ensure that
-  // they remain valid until the AppRemotingTestDriverEnvironment instance has
-  // been destroyed.
-  void SetAccessTokenFetcherForTest(AccessTokenFetcher* access_token_fetcher);
-  void SetAppRemotingReportIssueRequestForTest(
-      AppRemotingReportIssueRequest* app_remoting_report_issue_request);
-  void SetRefreshTokenStoreForTest(RefreshTokenStore* refresh_token_store);
-  void SetRemoteHostInfoFetcherForTest(
-      RemoteHostInfoFetcher* remote_host_info_fetcher);
-
-  // Accessors for fields used by tests.
-  const std::string& access_token() const { return access_token_; }
-  const std::string& user_name() const { return user_name_; }
-
- protected:
-  // Contains the names of all supported remote applications.
-  // Once initialized, this vector is not modified.
-  std::vector<std::string> application_names_;
-
-  // Contains RemoteApplicationDetails for all supported remote applications.
-  // Once initialized, this map is not modified.
-  std::map<std::string, RemoteApplicationDetails> application_details_map_;
-
- private:
-  // testing::Environment interface.
-  void TearDown() override;
-
-  // Used to retrieve an access token.  If |auth_code| is empty, then the stored
-  // refresh_token will be used instead of |auth_code|.
-  // Returns true if a new, valid access token has been retrieved.
-  bool RetrieveAccessToken(const std::string& auth_code);
-
-  // Called after the access token fetcher completes.
-  // The tokens will be empty on failure.
-  void OnAccessTokenRetrieved(base::Closure done_closure,
-                              const std::string& access_token,
-                              const std::string& refresh_token);
-
-  // Called after the remote host info fetcher completes.
-  // |remote_host_info| is modified on failure.
-  void OnRemoteHostInfoRetrieved(
-      base::Closure done_closure,
-      RemoteHostInfo* remote_host_info,
-      const RemoteHostInfo& retrieved_remote_host_info);
-
-  // Used for authenticating with the app remoting service API.
-  std::string access_token_;
-
-  // Used to retrieve an access token.
-  std::string refresh_token_;
-
-  // Used for authentication.
-  std::string user_name_;
-
-  // Service API to target when retrieving remote host connection information.
-  ServiceEnvironment service_environment_;
-
-  // Specifies whether to tell the service to release the remote hosts we
-  // requested after the tests have completed.
-  bool release_hosts_when_done_;
-
-  // Path to a JSON file containing refresh tokens.
-  base::FilePath refresh_token_file_path_;
-
-  // Access token fetcher used by TestDriverEnvironment tests.
-  remoting::test::AccessTokenFetcher* test_access_token_fetcher_;
-
-  // AppRemotingReportIssueRequest used by TestDriverEnvironment tests.
-  remoting::test::AppRemotingReportIssueRequest*
-      test_app_remoting_report_issue_request_;
-
-  // RefreshTokenStore used by TestDriverEnvironment tests.
-  remoting::test::RefreshTokenStore* test_refresh_token_store_;
-
-  // RemoteHostInfoFetcher used by TestDriverEnvironment tests.
-  remoting::test::RemoteHostInfoFetcher* test_remote_host_info_fetcher_;
-
-  // Used for running network request tasks.
-  std::unique_ptr<base::MessageLoopForIO> message_loop_;
-
-  // Contains the host ids to release when the environment is torn down.
-  // The key is the application id and the value is a list of hosts.
-  std::map<std::string, std::vector<std::string>> host_ids_to_release_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppRemotingTestDriverEnvironment);
-};
-
-// Used to provide application specific instances of the
-// AppRemotingTestDriverEnvironment class.
-extern std::unique_ptr<AppRemotingTestDriverEnvironment>
-CreateAppRemotingTestDriverEnvironment(
-    const AppRemotingTestDriverEnvironment::EnvironmentOptions& options);
-
-// Unfortunately a global var is how the GTEST framework handles sharing data
-// between tests and keeping long-lived objects around.  Used to share auth
-// tokens and remote host connection information across tests.
-extern AppRemotingTestDriverEnvironment* AppRemotingSharedData;
-
-}  // namespace test
-}  // namespace remoting
-
-#endif  // REMOTING_TEST_APP_REMOTING_TEST_DRIVER_ENVIRONMENT_H_
diff --git a/remoting/test/app_remoting_test_driver_environment_unittest.cc b/remoting/test/app_remoting_test_driver_environment_unittest.cc
deleted file mode 100644
index fe84160..0000000
--- a/remoting/test/app_remoting_test_driver_environment_unittest.cc
+++ /dev/null
@@ -1,474 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/test/app_remoting_test_driver_environment.h"
-
-#include <stddef.h>
-
-#include <algorithm>
-#include <utility>
-
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "remoting/test/fake_access_token_fetcher.h"
-#include "remoting/test/fake_app_remoting_report_issue_request.h"
-#include "remoting/test/fake_refresh_token_store.h"
-#include "remoting/test/fake_remote_host_info_fetcher.h"
-#include "remoting/test/mock_access_token_fetcher.h"
-#include "remoting/test/refresh_token_store.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-const char kAuthCodeValue[] = "4/892379827345jkefvkdfbv";
-const char kUserNameValue[] = "remoting_user@gmail.com";
-const char kTestApplicationId[] = "sadlkjlsjgadjfgoajdfgagb";
-const char kAnotherTestApplicationId[] = "waklgoisdhfnvjkdsfbljn";
-const char kTestHostId1[] = "awesome_test_host_id";
-const char kTestHostId2[] = "super_awesome_test_host_id";
-const char kTestHostId3[] = "uber_awesome_test_host_id";
-}
-
-namespace remoting {
-namespace test {
-
-using testing::_;
-
-class AppRemotingTestDriverEnvironmentTest : public ::testing::Test {
- public:
-  AppRemotingTestDriverEnvironmentTest();
-  ~AppRemotingTestDriverEnvironmentTest() override;
-
-  FakeAccessTokenFetcher* fake_access_token_fetcher() const {
-    return fake_access_token_fetcher_;
-  }
-
- protected:
-  void Initialize();
-  void Initialize(
-      const AppRemotingTestDriverEnvironment::EnvironmentOptions& options);
-
-  FakeAccessTokenFetcher* fake_access_token_fetcher_;
-  FakeAppRemotingReportIssueRequest fake_report_issue_request_;
-  FakeRefreshTokenStore fake_token_store_;
-  FakeRemoteHostInfoFetcher fake_remote_host_info_fetcher_;
-  MockAccessTokenFetcher mock_access_token_fetcher_;
-
-  std::unique_ptr<AppRemotingTestDriverEnvironment> environment_object_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AppRemotingTestDriverEnvironmentTest);
-};
-
-AppRemotingTestDriverEnvironmentTest::AppRemotingTestDriverEnvironmentTest()
-    : fake_access_token_fetcher_(nullptr) {
-}
-
-AppRemotingTestDriverEnvironmentTest::~AppRemotingTestDriverEnvironmentTest() =
-    default;
-
-void AppRemotingTestDriverEnvironmentTest::Initialize() {
-  AppRemotingTestDriverEnvironment::EnvironmentOptions options;
-  options.user_name = kUserNameValue;
-  options.service_environment = kDeveloperEnvironment;
-
-  Initialize(options);
-}
-
-void AppRemotingTestDriverEnvironmentTest::Initialize(
-    const AppRemotingTestDriverEnvironment::EnvironmentOptions& options) {
-  environment_object_.reset(new AppRemotingTestDriverEnvironment(options));
-
-  std::unique_ptr<FakeAccessTokenFetcher> fake_access_token_fetcher(
-      new FakeAccessTokenFetcher());
-  fake_access_token_fetcher_ = fake_access_token_fetcher.get();
-  mock_access_token_fetcher_.SetAccessTokenFetcher(
-      std::move(fake_access_token_fetcher));
-
-  environment_object_->SetAccessTokenFetcherForTest(
-      &mock_access_token_fetcher_);
-  environment_object_->SetAppRemotingReportIssueRequestForTest(
-      &fake_report_issue_request_);
-  environment_object_->SetRefreshTokenStoreForTest(&fake_token_store_);
-  environment_object_->SetRemoteHostInfoFetcherForTest(
-      &fake_remote_host_info_fetcher_);
-}
-
-TEST_F(AppRemotingTestDriverEnvironmentTest, InitializeObjectWithAuthCode) {
-  Initialize();
-
-  EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _));
-
-  EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromRefreshToken(_, _))
-      .Times(0);
-
-  EXPECT_TRUE(environment_object_->Initialize(kAuthCodeValue));
-  EXPECT_TRUE(fake_token_store_.refresh_token_write_attempted());
-  EXPECT_EQ(fake_token_store_.stored_refresh_token_value(),
-            kFakeAccessTokenFetcherRefreshTokenValue);
-  EXPECT_EQ(environment_object_->user_name(), kUserNameValue);
-  EXPECT_EQ(environment_object_->access_token(),
-            kFakeAccessTokenFetcherAccessTokenValue);
-
-  // Attempt to init again, we should not see any additional calls or errors.
-  EXPECT_TRUE(environment_object_->Initialize(kAuthCodeValue));
-}
-
-TEST_F(AppRemotingTestDriverEnvironmentTest,
-       InitializeObjectWithAuthCodeFailed) {
-  Initialize();
-
-  fake_access_token_fetcher()->set_fail_access_token_from_auth_code(true);
-
-  EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _));
-
-  EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromRefreshToken(_, _))
-      .Times(0);
-
-  EXPECT_FALSE(environment_object_->Initialize(kAuthCodeValue));
-  EXPECT_FALSE(fake_token_store_.refresh_token_write_attempted());
-}
-
-TEST_F(AppRemotingTestDriverEnvironmentTest, InitializeObjectWithRefreshToken) {
-  Initialize();
-
-  EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromRefreshToken(_, _));
-
-  EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _))
-      .Times(0);
-
-  // Pass in an empty auth code since we are using a refresh token.
-  EXPECT_TRUE(environment_object_->Initialize(std::string()));
-
-  // We should not write the refresh token a second time if we read from the
-  // disk originally.
-  EXPECT_FALSE(fake_token_store_.refresh_token_write_attempted());
-
-  // Verify the object was initialized correctly.
-  EXPECT_EQ(environment_object_->user_name(), kUserNameValue);
-  EXPECT_EQ(environment_object_->access_token(),
-            kFakeAccessTokenFetcherAccessTokenValue);
-
-  // Attempt to init again, we should not see any additional calls or errors.
-  EXPECT_TRUE(environment_object_->Initialize(std::string()));
-}
-
-TEST_F(AppRemotingTestDriverEnvironmentTest, TearDownAfterInitializeSucceeds) {
-  Initialize();
-
-  EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromRefreshToken(_, _));
-
-  EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _))
-      .Times(0);
-
-  // Pass in an empty auth code since we are using a refresh token.
-  EXPECT_TRUE(environment_object_->Initialize(std::string()));
-
-  // Note: We are using a static cast here because the TearDown() method is
-  //       private as it is an interface method that we only want to call
-  //       directly in tests or by the GTEST framework.
-  static_cast<testing::Environment*>(environment_object_.get())->TearDown();
-}
-
-TEST_F(AppRemotingTestDriverEnvironmentTest,
-       InitializeObjectWithRefreshTokenFailed) {
-  Initialize();
-
-  fake_access_token_fetcher()->set_fail_access_token_from_refresh_token(true);
-
-  EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromRefreshToken(_, _));
-
-  EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _))
-      .Times(0);
-
-  // Pass in an empty auth code since we are using a refresh token.
-  EXPECT_FALSE(environment_object_->Initialize(std::string()));
-  EXPECT_FALSE(fake_token_store_.refresh_token_write_attempted());
-}
-
-TEST_F(AppRemotingTestDriverEnvironmentTest,
-       InitializeObjectNoAuthCodeOrRefreshToken) {
-  Initialize();
-
-  // Neither method should be called in this scenario.
-  EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _))
-      .Times(0);
-
-  EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromRefreshToken(_, _))
-      .Times(0);
-
-  // Clear out the 'stored' refresh token value.
-  fake_token_store_.set_refresh_token_value(std::string());
-
-  // With no auth code or refresh token, then the initialization should fail.
-  EXPECT_FALSE(environment_object_->Initialize(std::string()));
-  EXPECT_FALSE(fake_token_store_.refresh_token_write_attempted());
-}
-
-TEST_F(AppRemotingTestDriverEnvironmentTest,
-       InitializeObjectWithAuthCodeWriteFailed) {
-  Initialize();
-
-  EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _));
-
-  EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromRefreshToken(_, _))
-      .Times(0);
-
-  // Simulate a failure writing the token to the disk.
-  fake_token_store_.set_refresh_token_write_succeeded(false);
-
-  EXPECT_FALSE(environment_object_->Initialize(kAuthCodeValue));
-  EXPECT_TRUE(fake_token_store_.refresh_token_write_attempted());
-}
-
-TEST_F(AppRemotingTestDriverEnvironmentTest,
-       RefreshAccessTokenAfterUsingAuthCode) {
-  Initialize();
-
-  {
-    testing::InSequence call_sequence;
-
-    EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _));
-
-    EXPECT_CALL(mock_access_token_fetcher_,
-                GetAccessTokenFromRefreshToken(_, _));
-  }
-
-  EXPECT_TRUE(environment_object_->Initialize(kAuthCodeValue));
-  EXPECT_TRUE(fake_token_store_.refresh_token_write_attempted());
-  EXPECT_EQ(fake_token_store_.stored_refresh_token_value(),
-            kFakeAccessTokenFetcherRefreshTokenValue);
-  EXPECT_EQ(environment_object_->user_name(), kUserNameValue);
-  EXPECT_EQ(environment_object_->access_token(),
-            kFakeAccessTokenFetcherAccessTokenValue);
-
-  // Attempt to init again, we should not see any additional calls or errors.
-  EXPECT_TRUE(environment_object_->RefreshAccessToken());
-}
-
-TEST_F(AppRemotingTestDriverEnvironmentTest, RefreshAccessTokenFailure) {
-  Initialize();
-
-  {
-    testing::InSequence call_sequence;
-
-    // Mock is set up for this call to succeed.
-    EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _));
-
-    // Mock is set up for this call to fail.
-    EXPECT_CALL(mock_access_token_fetcher_,
-                GetAccessTokenFromRefreshToken(_, _));
-  }
-
-  EXPECT_TRUE(environment_object_->Initialize(kAuthCodeValue));
-  EXPECT_TRUE(fake_token_store_.refresh_token_write_attempted());
-  EXPECT_EQ(fake_token_store_.stored_refresh_token_value(),
-            kFakeAccessTokenFetcherRefreshTokenValue);
-  EXPECT_EQ(environment_object_->user_name(), kUserNameValue);
-  EXPECT_EQ(environment_object_->access_token(),
-            kFakeAccessTokenFetcherAccessTokenValue);
-
-  fake_access_token_fetcher()->set_fail_access_token_from_refresh_token(true);
-
-  // We expect the refresh to have failed, the user name to remain valid,
-  // and the access token to have been cleared.
-  EXPECT_FALSE(environment_object_->RefreshAccessToken());
-  EXPECT_TRUE(environment_object_->access_token().empty());
-  EXPECT_EQ(environment_object_->user_name(), kUserNameValue);
-}
-
-TEST_F(AppRemotingTestDriverEnvironmentTest, GetRemoteHostInfoSuccess) {
-  Initialize();
-
-  // Pass in an empty auth code since we are using a refresh token.
-  EXPECT_TRUE(environment_object_->Initialize(std::string()));
-
-  RemoteHostInfo remote_host_info;
-  EXPECT_TRUE(environment_object_->GetRemoteHostInfoForApplicationId(
-      kTestApplicationId, &remote_host_info));
-  EXPECT_TRUE(remote_host_info.IsReadyForConnection());
-}
-
-TEST_F(AppRemotingTestDriverEnvironmentTest, GetRemoteHostInfoFailure) {
-  Initialize();
-
-  // Pass in an empty auth code since we are using a refresh token.
-  EXPECT_TRUE(environment_object_->Initialize(std::string()));
-
-  fake_remote_host_info_fetcher_.set_fail_retrieve_remote_host_info(true);
-
-  RemoteHostInfo remote_host_info;
-  EXPECT_FALSE(environment_object_->GetRemoteHostInfoForApplicationId(
-      kTestApplicationId, &remote_host_info));
-}
-
-TEST_F(AppRemotingTestDriverEnvironmentTest,
-       GetRemoteHostInfoWithoutInitializing) {
-  Initialize();
-
-  RemoteHostInfo remote_host_info;
-  EXPECT_FALSE(environment_object_->GetRemoteHostInfoForApplicationId(
-      kTestApplicationId, &remote_host_info));
-}
-
-TEST_F(AppRemotingTestDriverEnvironmentTest, NoRemoteHostsReleasedOnTearDown) {
-  // Use the default options as the flag to release the remote hosts is not
-  // enabled by default.
-  Initialize();
-
-  // Pass in an empty auth code since we are using a refresh token.
-  EXPECT_TRUE(environment_object_->Initialize(std::string()));
-
-  RemoteHostInfo remote_host_info;
-  EXPECT_TRUE(environment_object_->GetRemoteHostInfoForApplicationId(
-      kTestApplicationId, &remote_host_info));
-  EXPECT_TRUE(remote_host_info.IsReadyForConnection());
-
-  EXPECT_EQ(fake_report_issue_request_.get_host_ids_released().size(), 0UL);
-
-  environment_object_->AddHostToReleaseList(kTestApplicationId, kTestHostId1);
-
-  // Note: We are using a static cast here because the TearDown() method is
-  //       private as it is an interface method that we only want to call
-  //       directly in tests or by the GTEST framework.
-  static_cast<testing::Environment*>(environment_object_.get())->TearDown();
-
-  // Verify no hosts were released via a report issue request.
-  EXPECT_EQ(fake_report_issue_request_.get_host_ids_released().size(), 0UL);
-}
-
-TEST_F(AppRemotingTestDriverEnvironmentTest, OneRemoteHostReleasedOnTearDown) {
-  AppRemotingTestDriverEnvironment::EnvironmentOptions options;
-  options.user_name = kUserNameValue;
-  options.release_hosts_when_done = true;
-  options.service_environment = kDeveloperEnvironment;
-  Initialize(options);
-
-  // Pass in an empty auth code since we are using a refresh token.
-  EXPECT_TRUE(environment_object_->Initialize(std::string()));
-
-  RemoteHostInfo remote_host_info;
-  EXPECT_TRUE(environment_object_->GetRemoteHostInfoForApplicationId(
-      kTestApplicationId, &remote_host_info));
-  EXPECT_TRUE(remote_host_info.IsReadyForConnection());
-
-  EXPECT_EQ(fake_report_issue_request_.get_host_ids_released().size(), 0UL);
-
-  environment_object_->AddHostToReleaseList(kTestApplicationId, kTestHostId1);
-
-  // Note: We are using a static cast here because the TearDown() method is
-  //       private as it is an interface method that we only want to call
-  //       directly in tests or by the GTEST framework.
-  static_cast<testing::Environment*>(environment_object_.get())->TearDown();
-
-  std::string expected_host(
-      MakeFormattedStringForReleasedHost(kTestApplicationId, kTestHostId1));
-  std::vector<std::string> actual_host_list =
-      fake_report_issue_request_.get_host_ids_released();
-
-  EXPECT_EQ(actual_host_list.size(), 1UL);
-  EXPECT_EQ(actual_host_list[0], expected_host);
-}
-
-TEST_F(AppRemotingTestDriverEnvironmentTest, RemoteHostsReleasedOnTearDown) {
-  AppRemotingTestDriverEnvironment::EnvironmentOptions options;
-  options.user_name = kUserNameValue;
-  options.release_hosts_when_done = true;
-  options.service_environment = kDeveloperEnvironment;
-  Initialize(options);
-
-  // Pass in an empty auth code since we are using a refresh token.
-  EXPECT_TRUE(environment_object_->Initialize(std::string()));
-
-  RemoteHostInfo remote_host_info;
-  EXPECT_TRUE(environment_object_->GetRemoteHostInfoForApplicationId(
-      kTestApplicationId, &remote_host_info));
-  EXPECT_TRUE(remote_host_info.IsReadyForConnection());
-
-  std::vector<std::string> expected_host_list;
-  environment_object_->AddHostToReleaseList(kTestApplicationId, kTestHostId1);
-  expected_host_list.push_back(
-      MakeFormattedStringForReleasedHost(kTestApplicationId, kTestHostId1));
-
-  environment_object_->AddHostToReleaseList(kAnotherTestApplicationId,
-                                            kTestHostId2);
-  expected_host_list.push_back(MakeFormattedStringForReleasedHost(
-      kAnotherTestApplicationId, kTestHostId2));
-
-  environment_object_->AddHostToReleaseList(kTestApplicationId, kTestHostId3);
-  expected_host_list.push_back(
-      MakeFormattedStringForReleasedHost(kTestApplicationId, kTestHostId3));
-
-  // Note: We are using a static cast here because the TearDown() method is
-  //       private as it is an interface method that we only want to call
-  //       directly in tests or by the GTEST framework.
-  static_cast<testing::Environment*>(environment_object_.get())->TearDown();
-
-  std::vector<std::string> actual_host_list =
-      fake_report_issue_request_.get_host_ids_released();
-
-  std::sort(actual_host_list.begin(), actual_host_list.end());
-  std::sort(expected_host_list.begin(), expected_host_list.end());
-
-  EXPECT_EQ(actual_host_list.size(), expected_host_list.size());
-  for (size_t i = 0; i < actual_host_list.size(); ++i) {
-    EXPECT_EQ(actual_host_list[i], expected_host_list[i]);
-  }
-}
-
-TEST_F(AppRemotingTestDriverEnvironmentTest, RemoteHostsReleasedOnce) {
-  AppRemotingTestDriverEnvironment::EnvironmentOptions options;
-  options.user_name = kUserNameValue;
-  options.release_hosts_when_done = true;
-  options.service_environment = kDeveloperEnvironment;
-  Initialize(options);
-
-  // Pass in an empty auth code since we are using a refresh token.
-  EXPECT_TRUE(environment_object_->Initialize(std::string()));
-
-  RemoteHostInfo remote_host_info;
-  EXPECT_TRUE(environment_object_->GetRemoteHostInfoForApplicationId(
-      kTestApplicationId, &remote_host_info));
-  EXPECT_TRUE(remote_host_info.IsReadyForConnection());
-
-  std::vector<std::string> expected_host_list;
-  environment_object_->AddHostToReleaseList(kTestApplicationId, kTestHostId1);
-  expected_host_list.push_back(
-      MakeFormattedStringForReleasedHost(kTestApplicationId, kTestHostId1));
-
-  environment_object_->AddHostToReleaseList(kAnotherTestApplicationId,
-                                            kTestHostId2);
-  expected_host_list.push_back(MakeFormattedStringForReleasedHost(
-      kAnotherTestApplicationId, kTestHostId2));
-
-  environment_object_->AddHostToReleaseList(kTestApplicationId, kTestHostId3);
-  expected_host_list.push_back(
-      MakeFormattedStringForReleasedHost(kTestApplicationId, kTestHostId3));
-
-  // Attempt to add the previous hosts again, they should not be added since
-  // they will already exist in the list of hosts to release.
-  environment_object_->AddHostToReleaseList(kTestApplicationId, kTestHostId1);
-  environment_object_->AddHostToReleaseList(kAnotherTestApplicationId,
-                                            kTestHostId2);
-  environment_object_->AddHostToReleaseList(kTestApplicationId, kTestHostId3);
-
-  // Note: We are using a static cast here because the TearDown() method is
-  //       private as it is an interface method that we only want to call
-  //       directly in tests or by the GTEST framework.
-  static_cast<testing::Environment*>(environment_object_.get())->TearDown();
-
-  std::vector<std::string> actual_host_list =
-      fake_report_issue_request_.get_host_ids_released();
-
-  std::sort(actual_host_list.begin(), actual_host_list.end());
-  std::sort(expected_host_list.begin(), expected_host_list.end());
-
-  EXPECT_EQ(actual_host_list.size(), expected_host_list.size());
-  for (size_t i = 0; i < actual_host_list.size(); ++i) {
-    EXPECT_EQ(actual_host_list[i], expected_host_list[i]);
-  }
-}
-
-}  // namespace test
-}  // namespace remoting
diff --git a/remoting/test/fake_app_remoting_report_issue_request.cc b/remoting/test/fake_app_remoting_report_issue_request.cc
deleted file mode 100644
index f2111dd..0000000
--- a/remoting/test/fake_app_remoting_report_issue_request.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/test/fake_app_remoting_report_issue_request.h"
-
-#include "base/location.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-
-namespace remoting {
-namespace test {
-
-std::string MakeFormattedStringForReleasedHost(
-    const std::string& application_id,
-    const std::string& host_id) {
-  return application_id + "::" + host_id;
-}
-
-FakeAppRemotingReportIssueRequest::FakeAppRemotingReportIssueRequest()
-    : fail_start_request_(false) {
-}
-
-FakeAppRemotingReportIssueRequest::~FakeAppRemotingReportIssueRequest() =
-    default;
-
-bool FakeAppRemotingReportIssueRequest::Start(
-    const std::string& application_id,
-    const std::string& host_id,
-    const std::string& access_token,
-    ServiceEnvironment service_environment,
-    bool abandon_host,
-    base::Closure done_callback) {
-  if (fail_start_request_) {
-    done_callback.Run();
-    return false;
-  }
-
-  if (abandon_host) {
-    std::string host_id_string(application_id + "::" + host_id);
-    host_ids_released_.push_back(MakeFormattedStringForReleasedHost(
-      application_id, host_id));
-  }
-
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
-      base::ThreadTaskRunnerHandle::Get();
-  task_runner->PostTask(FROM_HERE, done_callback);
-
-  return true;
-}
-
-}  // namespace test
-}  // namespace remoting
diff --git a/remoting/test/fake_app_remoting_report_issue_request.h b/remoting/test/fake_app_remoting_report_issue_request.h
deleted file mode 100644
index 11ecdccd..0000000
--- a/remoting/test/fake_app_remoting_report_issue_request.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_TEST_FAKE_APP_REMOTING_REPORT_ISSUE_REQUEST_H_
-#define REMOTING_TEST_FAKE_APP_REMOTING_REPORT_ISSUE_REQUEST_H_
-
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "remoting/test/app_remoting_report_issue_request.h"
-
-namespace remoting {
-namespace test {
-
-// Generates a string used to track the 'released' host id by the
-// FakeAppRemotingReportIssueRequest class.
-std::string MakeFormattedStringForReleasedHost(
-    const std::string& application_id,
-    const std::string& host_id);
-
-// Used for testing classes which rely on the AccessTokenFetcher and want to
-// simulate success and failure scenarios without using the actual class and
-// network connection.
-class FakeAppRemotingReportIssueRequest : public AppRemotingReportIssueRequest {
- public:
-  FakeAppRemotingReportIssueRequest();
-  ~FakeAppRemotingReportIssueRequest() override;
-
-  // AppRemotingReportIssueRequest interface.
-  bool Start(const std::string& application_id,
-             const std::string& host_id,
-             const std::string& access_token,
-             ServiceEnvironment service_environment,
-             bool abandon_host,
-             base::Closure done_callback) override;
-
-  void set_fail_start_request(bool fail) { fail_start_request_ = fail; }
-
-  const std::vector<std::string>& get_host_ids_released() {
-    return host_ids_released_;
-  }
-
- private:
-  // True if Start() should fail.
-  bool fail_start_request_;
-
-  // Contains the set of host ids which have been released, the string contained
-  // will be in the form "<application_id>::<host_id>";
-  std::vector<std::string> host_ids_released_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeAppRemotingReportIssueRequest);
-};
-
-}  // namespace test
-}  // namespace remoting
-
-#endif  // REMOTING_TEST_FAKE_APP_REMOTING_REPORT_ISSUE_REQUEST_H_
diff --git a/remoting/test/fake_remote_host_info_fetcher.cc b/remoting/test/fake_remote_host_info_fetcher.cc
deleted file mode 100644
index 0cd1a4c..0000000
--- a/remoting/test/fake_remote_host_info_fetcher.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/test/fake_remote_host_info_fetcher.h"
-
-namespace remoting {
-namespace test {
-
-FakeRemoteHostInfoFetcher::FakeRemoteHostInfoFetcher()
-    : fail_retrieve_remote_host_info_(false) {
-}
-
-FakeRemoteHostInfoFetcher::~FakeRemoteHostInfoFetcher() = default;
-
-bool FakeRemoteHostInfoFetcher::RetrieveRemoteHostInfo(
-    const std::string& application_id,
-    const std::string& access_token,
-    ServiceEnvironment service_environment,
-    const RemoteHostInfoCallback& callback) {
-  RemoteHostInfo remote_host_info;
-
-  if (fail_retrieve_remote_host_info_) {
-    remote_host_info.remote_host_status = kRemoteHostStatusPending;
-  } else {
-    remote_host_info.remote_host_status = kRemoteHostStatusReady;
-    remote_host_info.application_id = application_id;
-  }
-
-  callback.Run(remote_host_info);
-
-  return !fail_retrieve_remote_host_info_;
-}
-
-}  // namespace test
-}  // namespace remoting
diff --git a/remoting/test/fake_remote_host_info_fetcher.h b/remoting/test/fake_remote_host_info_fetcher.h
deleted file mode 100644
index bdabbe4..0000000
--- a/remoting/test/fake_remote_host_info_fetcher.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_TEST_FAKE_REMOTE_HOST_INFO_FETCHER_H_
-#define REMOTING_TEST_FAKE_REMOTE_HOST_INFO_FETCHER_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "remoting/test/remote_host_info_fetcher.h"
-
-namespace remoting {
-namespace test {
-
-// Used for testing classes which rely on the RemoteHostInfoFetcher and want to
-// simulate success and failure scenarios without using the actual class and
-// network connection.
-class FakeRemoteHostInfoFetcher : public RemoteHostInfoFetcher {
- public:
-  FakeRemoteHostInfoFetcher();
-  ~FakeRemoteHostInfoFetcher() override;
-
-  // RemoteHostInfoFetcher interface.
-  bool RetrieveRemoteHostInfo(const std::string& application_id,
-                              const std::string& access_token,
-                              ServiceEnvironment service_environment,
-                              const RemoteHostInfoCallback& callback) override;
-
-  void set_fail_retrieve_remote_host_info(bool fail) {
-    fail_retrieve_remote_host_info_ = fail;
-  }
-
- private:
-  // True if RetrieveRemoteHostInfo() should fail.
-  bool fail_retrieve_remote_host_info_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeRemoteHostInfoFetcher);
-};
-
-}  // namespace test
-}  // namespace remoting
-
-#endif  // REMOTING_TEST_FAKE_REMOTE_HOST_INFO_FETCHER_H_
diff --git a/remoting/test/remote_application_details.h b/remoting/test/remote_application_details.h
deleted file mode 100644
index 711b210..0000000
--- a/remoting/test/remote_application_details.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_TEST_REMOTE_APPLICATION_DETAILS_H_
-#define REMOTING_TEST_REMOTE_APPLICATION_DETAILS_H_
-
-#include <string>
-
-namespace remoting {
-namespace test {
-
-// Container for application details used for testing.
-struct RemoteApplicationDetails {
-  RemoteApplicationDetails(const std::string& app_id,
-                           const std::string& window_title)
-      : application_id(app_id), main_window_title(window_title) {}
-
-  std::string application_id;
-  std::string main_window_title;
-};
-
-}  // namespace test
-}  // namespace remoting
-
-#endif  // REMOTING_TEST_REMOTE_APPLICATION_DETAILS_H_
diff --git a/remoting/test/remote_host_info_fetcher.cc b/remoting/test/remote_host_info_fetcher.cc
deleted file mode 100644
index 8a19223..0000000
--- a/remoting/test/remote_host_info_fetcher.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/test/remote_host_info_fetcher.h"
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/json/json_reader.h"
-#include "base/logging.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/values.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_status_code.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "net/url_request/url_fetcher.h"
-#include "remoting/base/url_request_context_getter.h"
-
-namespace {
-const char kRequestTestOrigin[] =
-    "Origin: chrome-extension://ljacajndfccfgnfohlgkdphmbnpkjflk";
-}
-
-namespace remoting {
-namespace test {
-
-RemoteHostInfoFetcher::RemoteHostInfoFetcher() = default;
-
-RemoteHostInfoFetcher::~RemoteHostInfoFetcher() = default;
-
-bool RemoteHostInfoFetcher::RetrieveRemoteHostInfo(
-    const std::string& application_id,
-    const std::string& access_token,
-    ServiceEnvironment service_environment,
-    const RemoteHostInfoCallback& callback) {
-  DCHECK(!application_id.empty());
-  DCHECK(!access_token.empty());
-  DCHECK(!callback.is_null());
-  DCHECK(remote_host_info_callback_.is_null());
-
-  VLOG(2) << "RemoteHostInfoFetcher::RetrieveRemoteHostInfo() called";
-
-  std::string service_url(
-      GetRunApplicationUrl(application_id, service_environment));
-  if (service_url.empty()) {
-    LOG(ERROR) << "Unrecognized service type: " << service_environment;
-    return false;
-  }
-  VLOG(1) << "Using remote host service request url: " << service_url;
-
-  remote_host_info_callback_ = callback;
-
-  request_context_getter_ = new remoting::URLRequestContextGetter(
-      base::ThreadTaskRunnerHandle::Get());
-
-  request_ = net::URLFetcher::Create(GURL(service_url), net::URLFetcher::POST,
-                                     this, TRAFFIC_ANNOTATION_FOR_TESTS);
-  request_->SetRequestContext(request_context_getter_.get());
-  request_->AddExtraRequestHeader("Authorization: OAuth " + access_token);
-  request_->AddExtraRequestHeader(kRequestTestOrigin);
-  request_->SetUploadData("application/json; charset=UTF-8", "{}");
-  request_->Start();
-
-  return true;
-}
-
-void RemoteHostInfoFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
-  DCHECK(source);
-  VLOG(2) << "URL Fetch Completed for: " << source->GetOriginalURL();
-
-  RemoteHostInfo remote_host_info;
-  int response_code = request_->GetResponseCode();
-  if (response_code != net::HTTP_OK) {
-    LOG(ERROR) << "RemoteHostInfo request failed with error code: "
-               << response_code;
-    base::ResetAndReturn(&remote_host_info_callback_).Run(remote_host_info);
-    return;
-  }
-
-  std::string response_string;
-  if (!request_->GetResponseAsString(&response_string)) {
-    LOG(ERROR) << "Failed to retrieve RemoteHostInfo response data";
-    base::ResetAndReturn(&remote_host_info_callback_).Run(remote_host_info);
-    return;
-  }
-
-  std::unique_ptr<base::Value> response_value(
-      base::JSONReader::Read(response_string));
-  if (!response_value || !response_value->is_dict()) {
-    LOG(ERROR) << "Failed to parse response string to JSON";
-    base::ResetAndReturn(&remote_host_info_callback_).Run(remote_host_info);
-    return;
-  }
-
-  std::string remote_host_status;
-  const base::DictionaryValue* response;
-  if (response_value->GetAsDictionary(&response)) {
-    response->GetString("status", &remote_host_status);
-  } else {
-    LOG(ERROR) << "Failed to convert parsed JSON to a dictionary object";
-    base::ResetAndReturn(&remote_host_info_callback_).Run(remote_host_info);
-    return;
-  }
-
-  remote_host_info.SetRemoteHostStatusFromString(remote_host_status);
-
-  if (remote_host_info.IsReadyForConnection()) {
-    response->GetString("host.applicationId", &remote_host_info.application_id);
-    response->GetString("host.hostId", &remote_host_info.host_id);
-    response->GetString("hostJid", &remote_host_info.host_jid);
-    response->GetString("authorizationCode",
-                        &remote_host_info.authorization_code);
-    response->GetString("sharedSecret", &remote_host_info.shared_secret);
-  }
-
-  base::ResetAndReturn(&remote_host_info_callback_).Run(remote_host_info);
-}
-
-}  // namespace test
-}  // namespace remoting
diff --git a/remoting/test/remote_host_info_fetcher.h b/remoting/test/remote_host_info_fetcher.h
deleted file mode 100644
index a5dadf66..0000000
--- a/remoting/test/remote_host_info_fetcher.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_TEST_REMOTE_HOST_INFO_FETCHER_H_
-#define REMOTING_TEST_REMOTE_HOST_INFO_FETCHER_H_
-
-#include <memory>
-#include <string>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "net/url_request/url_fetcher_delegate.h"
-#include "remoting/test/app_remoting_service_urls.h"
-#include "remoting/test/remote_host_info.h"
-
-namespace remoting {
-class URLRequestContextGetter;
-}
-
-namespace remoting {
-namespace test {
-
-// Supplied by the client for each remote host info request and returns a valid,
-// initialized RemoteHostInfo object on success.
-typedef base::Callback<void(const RemoteHostInfo& remote_host_info)>
-    RemoteHostInfoCallback;
-
-// Calls the App Remoting service API to request connection info for a remote
-// host.  Destroying the RemoteHostInfoFetcher while a request is outstanding
-// will cancel the request. It is safe to delete the fetcher from within a
-// completion callback.  Must be used from a thread running an IO message loop.
-// The public method is virtual to allow for mocking and fakes.
-class RemoteHostInfoFetcher : public net::URLFetcherDelegate {
- public:
-  RemoteHostInfoFetcher();
-  ~RemoteHostInfoFetcher() override;
-
-  // Makes a service call to retrieve the details for a remote host.  The
-  // callback will be called once the HTTP request has completed.
-  virtual bool RetrieveRemoteHostInfo(const std::string& application_id,
-                                      const std::string& access_token,
-                                      ServiceEnvironment service_environment,
-                                      const RemoteHostInfoCallback& callback);
-
- private:
-  // net::URLFetcherDelegate interface.
-  void OnURLFetchComplete(const net::URLFetcher* source) override;
-
-  // Holds the URLFetcher for the RemoteHostInfo request.
-  std::unique_ptr<net::URLFetcher> request_;
-
-  // Provides application-specific context for the network request.
-  scoped_refptr<remoting::URLRequestContextGetter> request_context_getter_;
-
-  // Caller-supplied callback used to return remote host info on success.
-  RemoteHostInfoCallback remote_host_info_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(RemoteHostInfoFetcher);
-};
-
-}  // namespace test
-}  // namespace remoting
-
-#endif  // REMOTING_TEST_REMOTE_HOST_INFO_FETCHER_H_
diff --git a/remoting/test/remote_host_info_fetcher_unittest.cc b/remoting/test/remote_host_info_fetcher_unittest.cc
deleted file mode 100644
index 5a18fc5..0000000
--- a/remoting/test/remote_host_info_fetcher_unittest.cc
+++ /dev/null
@@ -1,303 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/test/remote_host_info_fetcher.h"
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-const char kTestApplicationId[] = "klasdfjlkasdfjklasjfdkljsadf";
-const char kTestApplicationId2[] = "klasdfjlkasdfjklasjfdkljsadf2";
-const char kAccessTokenValue[] = "test_access_token_value";
-const char kRemoteHostInfoReadyResponse[] =
-    "{"
-    "  \"status\": \"done\","
-    "  \"host\": {"
-    "    \"kind\": \"test_kind\","
-    "    \"applicationId\": \"klasdfjlkasdfjklasjfdkljsadf\","
-    "    \"hostId\": \"test_host_id\""
-    "  },"
-    "  \"hostJid\": \"test_host_jid\","
-    "  \"authorizationCode\": \"test_authorization_code\","
-    "  \"sharedSecret\": \"test_shared_secret\""
-    "}";
-const char kRemoteHostInfoReadyResponse2[] =
-    "{"
-    "  \"status\": \"done\","
-    "  \"host\": {"
-    "    \"kind\": \"test_kind\","
-    "    \"applicationId\": \"klasdfjlkasdfjklasjfdkljsadf2\","
-    "    \"hostId\": \"test_host_id\""
-    "  },"
-    "  \"hostJid\": \"test_host_jid\","
-    "  \"authorizationCode\": \"test_authorization_code\","
-    "  \"sharedSecret\": \"test_shared_secret\""
-    "}";
-const char kRemoteHostInfoPendingResponse[] =
-    "{"
-    "  \"status\": \"pending\""
-    "}";
-const char kRemoteHostInfoEmptyResponse[] = "{}";
-}  // namespace
-
-namespace remoting {
-namespace test {
-
-// Provides base functionality for the RemoteHostInfoFetcher Tests below.  The
-// FakeURLFetcherFactory allows us to override the response data and payload for
-// specified URLs.  We use this to stub out network calls made by the
-// RemoteHostInfoFetcher.  This fixture also creates an IO MessageLoop, if
-// necessary, for use by the RemoteHostInfoFetcher.
-class RemoteHostInfoFetcherTest : public ::testing::Test {
- public:
-  RemoteHostInfoFetcherTest() : url_fetcher_factory_(nullptr) {}
-  ~RemoteHostInfoFetcherTest() override = default;
-
-  // Used as a RemoteHostInfoCallback for testing.
-  void OnRemoteHostInfoRetrieved(
-      base::Closure done_closure,
-      const RemoteHostInfo& retrieved_remote_host_info);
-
- protected:
-  // testing::Test interface.
-  void SetUp() override;
-
-  // Sets the HTTP status and data returned for a specified URL.
-  void SetFakeResponse(const GURL& url,
-                       const std::string& data,
-                       net::HttpStatusCode code,
-                       net::URLRequestStatus::Status status);
-
-  // Used for result verification.
-  RemoteHostInfo remote_host_info_;
-
-  std::string dev_service_environment_url_;
-  std::string dev_service_environment_url_2_;
-
- private:
-  net::FakeURLFetcherFactory url_fetcher_factory_;
-  std::unique_ptr<base::MessageLoopForIO> message_loop_;
-
-  DISALLOW_COPY_AND_ASSIGN(RemoteHostInfoFetcherTest);
-};
-
-void RemoteHostInfoFetcherTest::OnRemoteHostInfoRetrieved(
-    base::Closure done_closure,
-    const RemoteHostInfo& retrieved_remote_host_info) {
-  remote_host_info_ = retrieved_remote_host_info;
-
-  done_closure.Run();
-}
-
-void RemoteHostInfoFetcherTest::SetUp() {
-  DCHECK(!message_loop_);
-  message_loop_.reset(new base::MessageLoopForIO);
-
-  dev_service_environment_url_ =
-      GetRunApplicationUrl(kTestApplicationId, kDeveloperEnvironment);
-  SetFakeResponse(GURL(dev_service_environment_url_),
-                  kRemoteHostInfoEmptyResponse, net::HTTP_NOT_FOUND,
-                  net::URLRequestStatus::FAILED);
-
-  dev_service_environment_url_2_ =
-      GetRunApplicationUrl(kTestApplicationId2, kDeveloperEnvironment);
-  SetFakeResponse(GURL(dev_service_environment_url_2_),
-                  kRemoteHostInfoEmptyResponse, net::HTTP_NOT_FOUND,
-                  net::URLRequestStatus::FAILED);
-}
-
-void RemoteHostInfoFetcherTest::SetFakeResponse(
-    const GURL& url,
-    const std::string& data,
-    net::HttpStatusCode code,
-    net::URLRequestStatus::Status status) {
-  url_fetcher_factory_.SetFakeResponse(url, data, code, status);
-}
-
-TEST_F(RemoteHostInfoFetcherTest, RetrieveRemoteHostInfoFromDev) {
-  SetFakeResponse(GURL(dev_service_environment_url_),
-                  kRemoteHostInfoReadyResponse, net::HTTP_OK,
-                  net::URLRequestStatus::SUCCESS);
-
-  base::RunLoop run_loop;
-  RemoteHostInfoCallback remote_host_info_callback =
-      base::Bind(&RemoteHostInfoFetcherTest::OnRemoteHostInfoRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
-
-  RemoteHostInfoFetcher remote_host_info_fetcher;
-  bool request_started = remote_host_info_fetcher.RetrieveRemoteHostInfo(
-      kTestApplicationId, kAccessTokenValue, kDeveloperEnvironment,
-      remote_host_info_callback);
-
-  run_loop.Run();
-
-  EXPECT_TRUE(request_started);
-  EXPECT_TRUE(remote_host_info_.IsReadyForConnection());
-  EXPECT_EQ(remote_host_info_.application_id.compare(kTestApplicationId), 0);
-  EXPECT_TRUE(!remote_host_info_.host_id.empty());
-  EXPECT_TRUE(!remote_host_info_.host_jid.empty());
-  EXPECT_TRUE(!remote_host_info_.authorization_code.empty());
-  EXPECT_TRUE(!remote_host_info_.shared_secret.empty());
-}
-
-TEST_F(RemoteHostInfoFetcherTest, RetrieveRemoteHostInfoInvalidEnvironment) {
-  base::RunLoop run_loop;
-  RemoteHostInfoCallback remote_host_info_callback =
-      base::Bind(&RemoteHostInfoFetcherTest::OnRemoteHostInfoRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
-
-  RemoteHostInfoFetcher remote_host_info_fetcher;
-  bool request_started = remote_host_info_fetcher.RetrieveRemoteHostInfo(
-      kTestApplicationId, kAccessTokenValue, kUnknownEnvironment,
-      remote_host_info_callback);
-
-  EXPECT_FALSE(request_started);
-}
-
-TEST_F(RemoteHostInfoFetcherTest, RetrieveRemoteHostInfoNetworkError) {
-  base::RunLoop run_loop;
-  RemoteHostInfoCallback remote_host_info_callback =
-      base::Bind(&RemoteHostInfoFetcherTest::OnRemoteHostInfoRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
-
-  RemoteHostInfoFetcher remote_host_info_fetcher;
-  bool request_started = remote_host_info_fetcher.RetrieveRemoteHostInfo(
-      kTestApplicationId, kAccessTokenValue, kDeveloperEnvironment,
-      remote_host_info_callback);
-
-  run_loop.Run();
-
-  EXPECT_TRUE(request_started);
-  EXPECT_FALSE(remote_host_info_.IsReadyForConnection());
-
-  // If there was a network error retrieving the remote host info, then none of
-  // the connection details should be populated.
-  EXPECT_TRUE(remote_host_info_.application_id.empty());
-  EXPECT_TRUE(remote_host_info_.host_id.empty());
-  EXPECT_TRUE(remote_host_info_.host_jid.empty());
-  EXPECT_TRUE(remote_host_info_.authorization_code.empty());
-  EXPECT_TRUE(remote_host_info_.shared_secret.empty());
-}
-
-TEST_F(RemoteHostInfoFetcherTest, RetrieveRemoteHostInfoPendingResponse) {
-  SetFakeResponse(GURL(dev_service_environment_url_),
-                  kRemoteHostInfoPendingResponse, net::HTTP_OK,
-                  net::URLRequestStatus::SUCCESS);
-
-  base::RunLoop run_loop;
-  RemoteHostInfoCallback remote_host_info_callback =
-      base::Bind(&RemoteHostInfoFetcherTest::OnRemoteHostInfoRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
-
-  RemoteHostInfoFetcher remote_host_info_fetcher;
-  bool request_started = remote_host_info_fetcher.RetrieveRemoteHostInfo(
-      kTestApplicationId, kAccessTokenValue, kDeveloperEnvironment,
-      remote_host_info_callback);
-
-  run_loop.Run();
-
-  EXPECT_TRUE(request_started);
-  EXPECT_FALSE(remote_host_info_.IsReadyForConnection());
-
-  // If the remote host request is pending, then none of the connection details
-  // should be populated.
-  EXPECT_TRUE(remote_host_info_.application_id.empty());
-  EXPECT_TRUE(remote_host_info_.host_id.empty());
-  EXPECT_TRUE(remote_host_info_.host_jid.empty());
-  EXPECT_TRUE(remote_host_info_.authorization_code.empty());
-  EXPECT_TRUE(remote_host_info_.shared_secret.empty());
-}
-
-TEST_F(RemoteHostInfoFetcherTest, RetrieveRemoteHostInfoEmptyResponse) {
-  SetFakeResponse(GURL(dev_service_environment_url_),
-                  kRemoteHostInfoEmptyResponse, net::HTTP_OK,
-                  net::URLRequestStatus::SUCCESS);
-
-  base::RunLoop run_loop;
-  RemoteHostInfoCallback remote_host_info_callback =
-      base::Bind(&RemoteHostInfoFetcherTest::OnRemoteHostInfoRetrieved,
-                 base::Unretained(this), run_loop.QuitClosure());
-
-  RemoteHostInfoFetcher remote_host_info_fetcher;
-  bool request_started = remote_host_info_fetcher.RetrieveRemoteHostInfo(
-      kTestApplicationId, kAccessTokenValue, kDeveloperEnvironment,
-      remote_host_info_callback);
-
-  run_loop.Run();
-
-  EXPECT_TRUE(request_started);
-  EXPECT_FALSE(remote_host_info_.IsReadyForConnection());
-
-  // If we received an empty response, then none of the connection details
-  // should be populated.
-  EXPECT_TRUE(remote_host_info_.application_id.empty());
-  EXPECT_TRUE(remote_host_info_.host_id.empty());
-  EXPECT_TRUE(remote_host_info_.host_jid.empty());
-  EXPECT_TRUE(remote_host_info_.authorization_code.empty());
-  EXPECT_TRUE(remote_host_info_.shared_secret.empty());
-}
-
-TEST_F(RemoteHostInfoFetcherTest, MultipleRetrieveRemoteHostInfoRequests) {
-  // First, we will fetch info from the development service environment.
-  SetFakeResponse(GURL(dev_service_environment_url_),
-                  kRemoteHostInfoReadyResponse, net::HTTP_OK,
-                  net::URLRequestStatus::SUCCESS);
-
-  base::RunLoop dev_run_loop;
-  RemoteHostInfoCallback dev_remote_host_info_callback =
-      base::Bind(&RemoteHostInfoFetcherTest::OnRemoteHostInfoRetrieved,
-                 base::Unretained(this), dev_run_loop.QuitClosure());
-
-  RemoteHostInfoFetcher remote_host_info_fetcher;
-  bool dev_request_started = remote_host_info_fetcher.RetrieveRemoteHostInfo(
-      kTestApplicationId, kAccessTokenValue, kDeveloperEnvironment,
-      dev_remote_host_info_callback);
-
-  dev_run_loop.Run();
-
-  EXPECT_TRUE(dev_request_started);
-  EXPECT_TRUE(remote_host_info_.IsReadyForConnection());
-  EXPECT_EQ(remote_host_info_.application_id.compare(kTestApplicationId), 0);
-  EXPECT_TRUE(!remote_host_info_.host_id.empty());
-  EXPECT_TRUE(!remote_host_info_.host_jid.empty());
-  EXPECT_TRUE(!remote_host_info_.authorization_code.empty());
-  EXPECT_TRUE(!remote_host_info_.shared_secret.empty());
-
-  // Next, we will fetch a different application info block from the dev
-  // service environment.
-  SetFakeResponse(GURL(dev_service_environment_url_2_),
-                  kRemoteHostInfoReadyResponse2, net::HTTP_OK,
-                  net::URLRequestStatus::SUCCESS);
-
-  base::RunLoop test_run_loop;
-  RemoteHostInfoCallback test_remote_host_info_callback =
-      base::Bind(&RemoteHostInfoFetcherTest::OnRemoteHostInfoRetrieved,
-                 base::Unretained(this), test_run_loop.QuitClosure());
-
-  // Reset the state of our internal |remote_host_info_| object.
-  remote_host_info_ = RemoteHostInfo();
-  EXPECT_FALSE(remote_host_info_.IsReadyForConnection());
-
-  bool test_request_started = remote_host_info_fetcher.RetrieveRemoteHostInfo(
-      kTestApplicationId2, kAccessTokenValue, kDeveloperEnvironment,
-      test_remote_host_info_callback);
-
-  test_run_loop.Run();
-
-  EXPECT_TRUE(test_request_started);
-  EXPECT_TRUE(remote_host_info_.IsReadyForConnection());
-  EXPECT_EQ(remote_host_info_.application_id.compare(kTestApplicationId2), 0);
-  EXPECT_TRUE(!remote_host_info_.host_id.empty());
-  EXPECT_TRUE(!remote_host_info_.host_jid.empty());
-  EXPECT_TRUE(!remote_host_info_.authorization_code.empty());
-  EXPECT_TRUE(!remote_host_info_.shared_secret.empty());
-}
-
-}  // namespace test
-}  // namespace remoting
diff --git a/services/catalog/DEPS b/services/catalog/DEPS
deleted file mode 100644
index 25aecc83..0000000
--- a/services/catalog/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+components/services/filesystem"
-]
diff --git a/services/catalog/public/cpp/BUILD.gn b/services/catalog/public/cpp/BUILD.gn
deleted file mode 100644
index 6145b2f..0000000
--- a/services/catalog/public/cpp/BUILD.gn
+++ /dev/null
@@ -1,20 +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.
-
-source_set("cpp") {
-  sources = [
-    "resource_loader.cc",
-    "resource_loader.h",
-  ]
-
-  configs += [ "//build/config/compiler:wexit_time_destructors" ]
-
-  deps = [
-    "//base",
-    "//components/services/filesystem/public/interfaces",
-    "//mojo/public/cpp/bindings",
-    "//mojo/public/cpp/system",
-    "//services/service_manager/public/cpp",
-  ]
-}
diff --git a/services/catalog/public/cpp/resource_loader.cc b/services/catalog/public/cpp/resource_loader.cc
deleted file mode 100644
index 2c106417..0000000
--- a/services/catalog/public/cpp/resource_loader.cc
+++ /dev/null
@@ -1,52 +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 "services/catalog/public/cpp/resource_loader.h"
-
-#include <stddef.h>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/files/file.h"
-#include "components/services/filesystem/public/interfaces/directory.mojom.h"
-#include "mojo/public/cpp/system/platform_handle.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/service_manager/public/mojom/interface_provider.mojom.h"
-
-namespace catalog {
-
-ResourceLoader::ResourceLoader() {}
-ResourceLoader::~ResourceLoader() {}
-
-bool ResourceLoader::OpenFiles(filesystem::mojom::DirectoryPtr directory,
-                               const std::set<std::string>& paths) {
-  std::vector<filesystem::mojom::FileOpenDetailsPtr> details(paths.size());
-  size_t i = 0;
-  for (const auto& path : paths) {
-    filesystem::mojom::FileOpenDetailsPtr open_details(
-        filesystem::mojom::FileOpenDetails::New());
-    open_details->path = path;
-    open_details->open_flags =
-        filesystem::mojom::kFlagOpen | filesystem::mojom::kFlagRead;
-    details[i++] = std::move(open_details);
-  }
-
-  std::vector<filesystem::mojom::FileOpenResultPtr> results;
-  if (!directory->OpenFileHandles(std::move(details), &results))
-    return false;
-
-  for (const auto& result : results) {
-    resource_map_[result->path].reset(
-        new base::File(std::move(result->file_handle)));
-  }
-  return true;
-}
-
-base::File ResourceLoader::TakeFile(const std::string& path) {
-  std::unique_ptr<base::File> file_wrapper(std::move(resource_map_[path]));
-  resource_map_.erase(path);
-  return std::move(*file_wrapper);
-}
-
-}  // namespace catalog
diff --git a/services/catalog/public/cpp/resource_loader.h b/services/catalog/public/cpp/resource_loader.h
deleted file mode 100644
index 2ff3221..0000000
--- a/services/catalog/public/cpp/resource_loader.h
+++ /dev/null
@@ -1,49 +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 SERVICES_CATALOG_PUBLIC_CPP_RESOURCE_LOADER_H_
-#define SERVICES_CATALOG_PUBLIC_CPP_RESOURCE_LOADER_H_
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-
-#include "base/macros.h"
-#include "components/services/filesystem/public/interfaces/directory.mojom.h"
-
-namespace base {
-class File;
-}
-
-namespace catalog {
-
-// ResourceLoader asks the catalog (synchronously) to open the provided paths
-// and return the file handles. Use TakeFile() to retrieve a base::File to use
-// in client code.
-class ResourceLoader {
- public:
-  ResourceLoader();
-  ~ResourceLoader();
-
-  // (Synchronously) opens all of the files in |paths| for reading. Use
-  // TakeFile() subsequently to obtain base::Files to use. Returns true if the
-  // sync operation completed, false if it did not.
-  bool OpenFiles(filesystem::mojom::DirectoryPtr directory,
-                 const std::set<std::string>& paths);
-
-  // Releases and returns the file wrapping the handle.
-  base::File TakeFile(const std::string& path);
-
- private:
-  using ResourceMap = std::map<std::string, std::unique_ptr<base::File>>;
-
-  ResourceMap resource_map_;
-
-  DISALLOW_COPY_AND_ASSIGN(ResourceLoader);
-};
-
-}  // namespace
-
-#endif  // SERVICES_CATALOG_PUBLIC_CPP_RESOURCE_LOADER_H_
diff --git a/services/catalog/public/mojom/BUILD.gn b/services/catalog/public/mojom/BUILD.gn
deleted file mode 100644
index 097a968..0000000
--- a/services/catalog/public/mojom/BUILD.gn
+++ /dev/null
@@ -1,22 +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.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("mojom") {
-  sources = [
-    "catalog.mojom",
-  ]
-
-  public_deps = [
-    ":constants",
-    "//mojo/public/mojom/base",
-  ]
-}
-
-mojom("constants") {
-  sources = [
-    "constants.mojom",
-  ]
-}
diff --git a/services/catalog/public/mojom/OWNERS b/services/catalog/public/mojom/OWNERS
deleted file mode 100644
index 08850f4..0000000
--- a/services/catalog/public/mojom/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/services/catalog/public/mojom/catalog.mojom b/services/catalog/public/mojom/catalog.mojom
deleted file mode 100644
index d115946..0000000
--- a/services/catalog/public/mojom/catalog.mojom
+++ /dev/null
@@ -1,23 +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.
-
-module catalog.mojom;
-
-import "mojo/public/mojom/base/file_path.mojom";
-
-struct Entry {
-  string name;
-  string display_name;
-};
-
-interface Catalog {
-  // Returns the catalog entries for the specified mojo names.
-  // If |names| is null, all available entries are returned.
-  [Sync]
-  GetEntries(array<string>? names) => (array<Entry> entries);
-
-  // Returns the entry(ies) for applications that export to the caller the
-  // specified capability.
-  GetEntriesProvidingCapability(string capability) => (array<Entry> entries);
-};
diff --git a/services/catalog/public/mojom/constants.mojom b/services/catalog/public/mojom/constants.mojom
deleted file mode 100644
index 51294a87c..0000000
--- a/services/catalog/public/mojom/constants.mojom
+++ /dev/null
@@ -1,7 +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.
-
-module catalog.mojom;
-
-const string kServiceName = "catalog";
diff --git a/services/identity/public/cpp/accounts_mutator_unittest.cc b/services/identity/public/cpp/accounts_mutator_unittest.cc
index 6c3cce1..dea93819 100644
--- a/services/identity/public/cpp/accounts_mutator_unittest.cc
+++ b/services/identity/public/cpp/accounts_mutator_unittest.cc
@@ -88,6 +88,10 @@
   bool is_token_updator_refresh_token_valid() {
     return is_token_updator_refresh_token_valid_;
   }
+  const std::string& token_remover_account_id() {
+    return token_remover_account_id_;
+  }
+  const std::string& token_remover_source() { return token_remover_source_; }
 
  private:
   // identity::IdentityManager::DiagnosticsObserver:
@@ -100,9 +104,18 @@
     token_updator_source_ = source;
   }
 
+  void OnRefreshTokenRemovedForAccountFromSource(
+      const std::string& account_id,
+      const std::string& source) override {
+    token_remover_account_id_ = account_id;
+    token_remover_source_ = source;
+  }
+
   identity::IdentityManager* identity_manager_;
   std::string token_updator_account_id_;
   std::string token_updator_source_;
+  std::string token_remover_account_id_;
+  std::string token_remover_source_;
   bool is_token_updator_refresh_token_valid_;
 };
 
@@ -719,4 +732,22 @@
             identity_manager_diagnostics_observer()->token_updator_source());
 }
 
+TEST_F(AccountsMutatorTest, RemoveRefreshTokenFromSource) {
+  // Abort the test if the current platform does not support accounts mutation.
+  if (!accounts_mutator())
+    return;
+
+  // Add a default account.
+  std::string account_id = accounts_mutator()->AddOrUpdateAccount(
+      kTestGaiaId, kTestEmail, "refresh_token", false,
+      signin_metrics::SourceForRefreshTokenOperation::kSettings_Signout);
+
+  // Remove the default account.
+  accounts_mutator()->RemoveAccount(
+      kTestGaiaId,
+      signin_metrics::SourceForRefreshTokenOperation::kSettings_Signout);
+  EXPECT_EQ("Settings::Signout",
+            identity_manager_diagnostics_observer()->token_remover_source());
+}
+
 }  // namespace identity
diff --git a/services/identity/public/cpp/identity_manager.cc b/services/identity/public/cpp/identity_manager.cc
index 14090bb..af9fff8 100644
--- a/services/identity/public/cpp/identity_manager.cc
+++ b/services/identity/public/cpp/identity_manager.cc
@@ -488,6 +488,13 @@
         account_id, is_refresh_token_valid, source);
 }
 
+void IdentityManager::OnRefreshTokenRevokedFromSource(
+    const std::string& account_id,
+    const std::string& source) {
+  for (auto& observer : diagnostics_observer_list_)
+    observer.OnRefreshTokenRemovedForAccountFromSource(account_id, source);
+}
+
 void IdentityManager::OnAccountUpdated(const AccountInfo& info) {
   for (auto& observer : observer_list_) {
     observer.OnExtendedAccountInfoUpdated(info);
diff --git a/services/identity/public/cpp/identity_manager.h b/services/identity/public/cpp/identity_manager.h
index 50b2434..3f43070 100644
--- a/services/identity/public/cpp/identity_manager.h
+++ b/services/identity/public/cpp/identity_manager.h
@@ -182,6 +182,12 @@
         const std::string& account_id,
         bool is_refresh_token_valid,
         const std::string& source) {}
+
+    // Called when a refreh token is removed. Contains diagnostic information
+    // about the source that initiated the revokation operation.
+    virtual void OnRefreshTokenRemovedForAccountFromSource(
+        const std::string& account_id,
+        const std::string& source) {}
   };
 
   // Possible values for the account ID migration state, needs to be kept in
@@ -524,6 +530,8 @@
   void OnRefreshTokenAvailableFromSource(const std::string& account_id,
                                          bool is_refresh_token_valid,
                                          const std::string& source) override;
+  void OnRefreshTokenRevokedFromSource(const std::string& account_id,
+                                       const std::string& source) override;
 
   // AccountTrackerService::Observer:
   void OnAccountUpdated(const AccountInfo& info) override;
diff --git a/services/media_session/public/cpp/android/java/src/org/chromium/services/media_session/MediaImage.java b/services/media_session/public/cpp/android/java/src/org/chromium/services/media_session/MediaImage.java
index 60d6d0d..ec19914c 100644
--- a/services/media_session/public/cpp/android/java/src/org/chromium/services/media_session/MediaImage.java
+++ b/services/media_session/public/cpp/android/java/src/org/chromium/services/media_session/MediaImage.java
@@ -12,6 +12,7 @@
 import org.chromium.base.annotations.JNINamespace;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -106,16 +107,18 @@
      * Create a new {@link MediaImage} from the C++ code.
      * @param src The URL of the image.
      * @param type The MIME type of the image.
-     * @param flattenedSizes The flattened array of image sizes. In native code, it is of type
-     *         `std::vector<gfx::Size>` before flattening.
+     * @param sizes The array of image sizes.
      */
     @CalledByNative
-    private static MediaImage create(String src, String type, int[] flattenedSizes) {
-        assert (flattenedSizes.length % 2) == 0;
-        List<Rect> sizes = new ArrayList<Rect>();
-        for (int i = 0; (i + 1) < flattenedSizes.length; i += 2) {
-            sizes.add(new Rect(0, 0, flattenedSizes[i], flattenedSizes[i + 1]));
-        }
-        return new MediaImage(src, type, sizes);
+    private static MediaImage create(String src, String type, Rect[] sizes) {
+        return new MediaImage(src, type, Arrays.asList(sizes));
+    }
+
+    /**
+     * Create a new {@link Rect} from the C++ code.
+     */
+    @CalledByNative
+    private static Rect createRect(int width, int height) {
+        return new Rect(0, 0, width, height);
     }
 }
diff --git a/services/media_session/public/cpp/android/java/src/org/chromium/services/media_session/MediaMetadata.java b/services/media_session/public/cpp/android/java/src/org/chromium/services/media_session/MediaMetadata.java
index f8754d3..0359d7a 100644
--- a/services/media_session/public/cpp/android/java/src/org/chromium/services/media_session/MediaMetadata.java
+++ b/services/media_session/public/cpp/android/java/src/org/chromium/services/media_session/MediaMetadata.java
@@ -10,9 +10,6 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * The MediaMetadata class carries information related to a media session. It is
  * the Java counterpart of media_session::MediaMetadata.
@@ -28,9 +25,6 @@
     @NonNull
     private String mAlbum;
 
-    @NonNull
-    private List<MediaImage> mArtwork = new ArrayList<MediaImage>();
-
     /**
      * Returns the title associated with the media session.
      */
@@ -52,10 +46,6 @@
         return mAlbum;
     }
 
-    public List<MediaImage> getArtwork() {
-        return mArtwork;
-    }
-
     /**
      * Sets the title associated with the media session.
      * @param title The title to use for the media session.
@@ -81,14 +71,6 @@
     }
 
     /**
-     * Adds an image to the MediaMetadata. This is called from the C++ code.
-     */
-    @CalledByNative
-    private void addImage(MediaImage image) {
-        mArtwork.add(image);
-    }
-
-    /**
      * Creates a new MediaMetadata from the C++ code. This is exactly like the
      * constructor below apart that it can be called by native code.
      */
@@ -116,7 +98,7 @@
 
         MediaMetadata other = (MediaMetadata) obj;
         return TextUtils.equals(mTitle, other.mTitle) && TextUtils.equals(mArtist, other.mArtist)
-                && TextUtils.equals(mAlbum, other.mAlbum) && mArtwork.equals(other.mArtwork);
+                && TextUtils.equals(mAlbum, other.mAlbum);
     }
 
     /**
@@ -128,7 +110,6 @@
         int result = mTitle.hashCode();
         result = 31 * result + mArtist.hashCode();
         result = 31 * result + mAlbum.hashCode();
-        result = 31 * result + mArtwork.hashCode();
         return result;
     }
 }
diff --git a/services/media_session/public/cpp/media_image.h b/services/media_session/public/cpp/media_image.h
index 8ed0462..e2f3892 100644
--- a/services/media_session/public/cpp/media_image.h
+++ b/services/media_session/public/cpp/media_image.h
@@ -33,7 +33,12 @@
   bool operator==(const MediaImage& other) const;
 
 #if defined(OS_ANDROID)
-  // Creates a Java MediaMetadata instance and returns the JNI ref.
+  // Creates a Java array of MediaImage instances and returns the JNI ref.
+  static base::android::ScopedJavaLocalRef<jobjectArray> ToJavaArray(
+      JNIEnv* env,
+      const std::vector<MediaImage>& images);
+
+  // Creates a Java MediaImage instance and returns the JNI ref.
   base::android::ScopedJavaLocalRef<jobject> CreateJavaObject(
       JNIEnv* env) const;
 #endif
diff --git a/services/media_session/public/cpp/media_image_android.cc b/services/media_session/public/cpp/media_image_android.cc
index 15a0633c..0cf7967f 100644
--- a/services/media_session/public/cpp/media_image_android.cc
+++ b/services/media_session/public/cpp/media_image_android.cc
@@ -5,9 +5,8 @@
 #include "services/media_session/public/cpp/media_image.h"
 
 #include <string>
-#include <vector>
 
-#include "base/android/jni_array.h"
+#include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "jni/MediaImage_jni.h"
 
@@ -15,31 +14,46 @@
 
 namespace media_session {
 
-namespace {
+// static
+ScopedJavaLocalRef<jobjectArray> MediaImage::ToJavaArray(
+    JNIEnv* env,
+    const std::vector<MediaImage>& images) {
+  ScopedJavaLocalRef<jclass> string_clazz = base::android::GetClass(
+      env, "org/chromium/services/media_session/MediaImage");
+  jobjectArray joa =
+      env->NewObjectArray(images.size(), string_clazz.obj(), NULL);
+  base::android::CheckException(env);
 
-std::vector<int> GetFlattenedSizeArray(const std::vector<gfx::Size>& sizes) {
-  std::vector<int> flattened_array;
-  flattened_array.reserve(2 * sizes.size());
-  for (const auto& size : sizes) {
-    flattened_array.push_back(size.width());
-    flattened_array.push_back(size.height());
+  for (size_t i = 0; i < images.size(); ++i) {
+    ScopedJavaLocalRef<jobject> item = images[i].CreateJavaObject(env);
+    env->SetObjectArrayElement(joa, i, item.obj());
   }
-  return flattened_array;
+  return ScopedJavaLocalRef<jobjectArray>(env, joa);
 }
 
-}  // anonymous namespace
-
-base::android::ScopedJavaLocalRef<jobject> MediaImage::CreateJavaObject(
-    JNIEnv* env) const {
+ScopedJavaLocalRef<jobject> MediaImage::CreateJavaObject(JNIEnv* env) const {
   std::string src_spec = src.spec();
   ScopedJavaLocalRef<jstring> j_src(
       base::android::ConvertUTF8ToJavaString(env, src_spec));
   ScopedJavaLocalRef<jstring> j_type(
       base::android::ConvertUTF16ToJavaString(env, type));
-  ScopedJavaLocalRef<jintArray> j_sizes(
-      base::android::ToJavaIntArray(env, GetFlattenedSizeArray(sizes)));
 
-  return Java_MediaImage_create(env, j_src, j_type, j_sizes);
+  // Create a Java array to store the sizes in.
+  ScopedJavaLocalRef<jclass> string_clazz =
+      base::android::GetClass(env, "android/graphics/Rect");
+  jobjectArray joa =
+      env->NewObjectArray(sizes.size(), string_clazz.obj(), NULL);
+  base::android::CheckException(env);
+
+  // Create an Android Rect for each size and store it in the array.
+  for (size_t i = 0; i < sizes.size(); ++i) {
+    ScopedJavaLocalRef<jobject> item =
+        Java_MediaImage_createRect(env, sizes[i].width(), sizes[i].height());
+    env->SetObjectArrayElement(joa, i, item.obj());
+  }
+
+  return Java_MediaImage_create(env, j_src, j_type,
+                                ScopedJavaLocalRef<jobjectArray>(env, joa));
 }
 
 }  // namespace media_session
diff --git a/services/media_session/public/cpp/media_metadata.cc b/services/media_session/public/cpp/media_metadata.cc
index 8dff765..7aff157 100644
--- a/services/media_session/public/cpp/media_metadata.cc
+++ b/services/media_session/public/cpp/media_metadata.cc
@@ -16,8 +16,7 @@
 
 bool MediaMetadata::operator==(const MediaMetadata& other) const {
   return title == other.title && artist == other.artist &&
-         album == other.album && artwork == other.artwork &&
-         source_title == other.source_title;
+         album == other.album && source_title == other.source_title;
 }
 
 bool MediaMetadata::operator!=(const MediaMetadata& other) const {
@@ -26,7 +25,7 @@
 
 bool MediaMetadata::IsEmpty() const {
   return title.empty() && artist.empty() && album.empty() &&
-         source_title.empty() && artwork.empty();
+         source_title.empty();
 }
 
 }  // namespace media_session
diff --git a/services/media_session/public/cpp/media_metadata.h b/services/media_session/public/cpp/media_metadata.h
index ae24bca..7e1f3de 100644
--- a/services/media_session/public/cpp/media_metadata.h
+++ b/services/media_session/public/cpp/media_metadata.h
@@ -22,8 +22,6 @@
 
 namespace media_session {
 
-struct MediaImage;
-
 // The MediaMetadata is a structure carrying information associated to a
 // MediaSession.
 struct COMPONENT_EXPORT(MEDIA_SESSION_CPP) MediaMetadata {
@@ -50,9 +48,6 @@
   // Album associated to the MediaSession.
   base::string16 album;
 
-  // Artwork associated to the MediaSession.
-  std::vector<MediaImage> artwork;
-
   // The |source_title| is a human readable title for the source of the media
   // session. This could be the name of the app or the name of the site playing
   // media.
diff --git a/services/media_session/public/cpp/media_metadata_android.cc b/services/media_session/public/cpp/media_metadata_android.cc
index 20b69f4..45152aa 100644
--- a/services/media_session/public/cpp/media_metadata_android.cc
+++ b/services/media_session/public/cpp/media_metadata_android.cc
@@ -21,16 +21,7 @@
       base::android::ConvertUTF16ToJavaString(env, artist));
   ScopedJavaLocalRef<jstring> j_album(
       base::android::ConvertUTF16ToJavaString(env, album));
-
-  ScopedJavaLocalRef<jobject> j_metadata =
-      Java_MediaMetadata_create(env, j_title, j_artist, j_album);
-
-  for (const auto& image : artwork) {
-    ScopedJavaLocalRef<jobject> j_image = image.CreateJavaObject(env);
-    Java_MediaMetadata_addImage(env, j_metadata, j_image);
-  }
-
-  return j_metadata;
+  return Java_MediaMetadata_create(env, j_title, j_artist, j_album);
 }
 
 }  // namespace media_session
diff --git a/services/media_session/public/cpp/media_session_mojom_traits.cc b/services/media_session/public/cpp/media_session_mojom_traits.cc
index bdbf0b4..ae4d1a4 100644
--- a/services/media_session/public/cpp/media_session_mojom_traits.cc
+++ b/services/media_session/public/cpp/media_session_mojom_traits.cc
@@ -39,9 +39,6 @@
   if (!data.ReadAlbum(&out->album))
     return false;
 
-  if (!data.ReadArtwork(&out->artwork))
-    return false;
-
   if (!data.ReadSourceTitle(&out->source_title))
     return false;
 
diff --git a/services/media_session/public/cpp/media_session_mojom_traits.h b/services/media_session/public/cpp/media_session_mojom_traits.h
index a877f50f..9d82bab 100644
--- a/services/media_session/public/cpp/media_session_mojom_traits.h
+++ b/services/media_session/public/cpp/media_session_mojom_traits.h
@@ -49,11 +49,6 @@
     return metadata.album;
   }
 
-  static const std::vector<media_session::MediaImage>& artwork(
-      const media_session::MediaMetadata& metadata) {
-    return metadata.artwork;
-  }
-
   static const base::string16& source_title(
       const media_session::MediaMetadata& metadata) {
     return metadata.source_title;
diff --git a/services/media_session/public/mojom/media_session.mojom b/services/media_session/public/mojom/media_session.mojom
index f854209..eb748ae 100644
--- a/services/media_session/public/mojom/media_session.mojom
+++ b/services/media_session/public/mojom/media_session.mojom
@@ -50,9 +50,6 @@
   mojo_base.mojom.String16 artist;
   mojo_base.mojom.String16 album;
 
-  // TODO(beccahughes): Remove this
-  array<MediaImage> artwork;
-
   // The |source_title| is a human readable title for the source of the media
   // session. This could be the name of the app or the name of the site playing
   // media.
diff --git a/services/proxy_resolver/host_resolver_mojo.cc b/services/proxy_resolver/host_resolver_mojo.cc
index a502e82..b32c1c2 100644
--- a/services/proxy_resolver/host_resolver_mojo.cc
+++ b/services/proxy_resolver/host_resolver_mojo.cc
@@ -29,10 +29,10 @@
 
 net::HostCache::Key CacheKeyForRequest(
     const std::string& hostname,
-    net::ProxyResolverV8::JSBindings::ResolveDnsOperation operation) {
+    net::ProxyResolveDnsOperation operation) {
   net::AddressFamily address_family = net::ADDRESS_FAMILY_UNSPECIFIED;
-  if (operation == net::ProxyResolverV8::JSBindings::MY_IP_ADDRESS ||
-      operation == net::ProxyResolverV8::JSBindings::DNS_RESOLVE) {
+  if (operation == net::ProxyResolveDnsOperation::MY_IP_ADDRESS ||
+      operation == net::ProxyResolveDnsOperation::DNS_RESOLVE) {
     address_family = net::ADDRESS_FAMILY_IPV4;
   }
 
@@ -46,7 +46,7 @@
                                       public mojom::HostResolverRequestClient {
  public:
   RequestImpl(const std::string& hostname,
-              net::ProxyResolverV8::JSBindings::ResolveDnsOperation operation,
+              net::ProxyResolveDnsOperation operation,
               base::WeakPtr<net::HostCache> host_cache,
               Impl* impl)
       : hostname_(hostname),
@@ -131,7 +131,7 @@
   }
 
   const std::string hostname_;
-  const net::ProxyResolverV8::JSBindings::ResolveDnsOperation operation_;
+  const net::ProxyResolveDnsOperation operation_;
 
   mojo::Binding<mojom::HostResolverRequestClient> binding_;
   net::CompletionOnceCallback callback_;
@@ -151,9 +151,8 @@
 HostResolverMojo::~HostResolverMojo() = default;
 
 std::unique_ptr<net::ProxyHostResolver::Request>
-HostResolverMojo::CreateRequest(
-    const std::string& hostname,
-    net::ProxyResolverV8::JSBindings::ResolveDnsOperation operation) {
+HostResolverMojo::CreateRequest(const std::string& hostname,
+                                net::ProxyResolveDnsOperation operation) {
   DCHECK(thread_checker_.CalledOnValidThread());
   return std::make_unique<RequestImpl>(
       hostname, operation, host_cache_weak_factory_.GetWeakPtr(), impl_);
diff --git a/services/proxy_resolver/host_resolver_mojo.h b/services/proxy_resolver/host_resolver_mojo.h
index 98990bf..07e0e5e 100644
--- a/services/proxy_resolver/host_resolver_mojo.h
+++ b/services/proxy_resolver/host_resolver_mojo.h
@@ -13,7 +13,7 @@
 #include "base/threading/thread_checker.h"
 #include "net/dns/host_cache.h"
 #include "net/proxy_resolution/proxy_host_resolver.h"
-#include "net/proxy_resolution/proxy_resolver_v8.h"
+#include "net/proxy_resolution/proxy_resolve_dns_operation.h"
 #include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
 
 namespace proxy_resolver {
@@ -25,10 +25,9 @@
   class Impl {
    public:
     virtual ~Impl() = default;
-    virtual void ResolveDns(
-        const std::string& hostname,
-        net::ProxyResolverV8::JSBindings::ResolveDnsOperation operation,
-        mojom::HostResolverRequestClientPtr) = 0;
+    virtual void ResolveDns(const std::string& hostname,
+                            net::ProxyResolveDnsOperation operation,
+                            mojom::HostResolverRequestClientPtr) = 0;
   };
 
   // |impl| must outlive |this|.
@@ -38,7 +37,7 @@
   // ProxyHostResolver overrides.
   std::unique_ptr<Request> CreateRequest(
       const std::string& hostname,
-      net::ProxyResolverV8::JSBindings::ResolveDnsOperation operation) override;
+      net::ProxyResolveDnsOperation operation) override;
 
  private:
   class Job;
diff --git a/services/proxy_resolver/host_resolver_mojo_unittest.cc b/services/proxy_resolver/host_resolver_mojo_unittest.cc
index c1e6e8a..6575cd8 100644
--- a/services/proxy_resolver/host_resolver_mojo_unittest.cc
+++ b/services/proxy_resolver/host_resolver_mojo_unittest.cc
@@ -102,10 +102,9 @@
 
   const std::vector<std::string>& requests() { return requests_received_; }
 
-  void ResolveDns(
-      const std::string& hostname,
-      net::ProxyResolverV8::JSBindings::ResolveDnsOperation operation,
-      mojom::HostResolverRequestClientPtr) override;
+  void ResolveDns(const std::string& hostname,
+                  net::ProxyResolveDnsOperation operation,
+                  mojom::HostResolverRequestClientPtr) override;
 
  private:
   std::vector<HostResolverAction> actions_;
@@ -129,7 +128,7 @@
 
 void MockMojoHostResolver::ResolveDns(
     const std::string& hostname,
-    net::ProxyResolverV8::JSBindings::ResolveDnsOperation operation,
+    net::ProxyResolveDnsOperation operation,
     mojom::HostResolverRequestClientPtr client) {
   requests_received_.push_back(hostname);
   ASSERT_LE(results_returned_, actions_.size());
@@ -169,8 +168,7 @@
               std::vector<net::IPAddress>* out_addresses) {
     std::unique_ptr<net::ProxyHostResolver::Request> request =
         resolver_->CreateRequest(hostname,
-                                 net::ProxyResolverV8::JSBindings::
-                                     ResolveDnsOperation::DNS_RESOLVE_EX);
+                                 net::ProxyResolveDnsOperation::DNS_RESOLVE_EX);
 
     net::TestCompletionCallback callback;
     int result = callback.GetResult(request->Start(callback.callback()));
@@ -240,12 +238,10 @@
 
   std::unique_ptr<net::ProxyHostResolver::Request> request1 =
       resolver_->CreateRequest("example.com",
-                               net::ProxyResolverV8::JSBindings::
-                                   ResolveDnsOperation::DNS_RESOLVE_EX);
+                               net::ProxyResolveDnsOperation::DNS_RESOLVE_EX);
   std::unique_ptr<net::ProxyHostResolver::Request> request2 =
       resolver_->CreateRequest("example.org",
-                               net::ProxyResolverV8::JSBindings::
-                                   ResolveDnsOperation::DNS_RESOLVE_EX);
+                               net::ProxyResolveDnsOperation::DNS_RESOLVE_EX);
   net::TestCompletionCallback callback1;
   net::TestCompletionCallback callback2;
   ASSERT_EQ(net::ERR_IO_PENDING, request1->Start(callback1.callback()));
@@ -290,8 +286,7 @@
 
   std::unique_ptr<net::ProxyHostResolver::Request> request =
       resolver_->CreateRequest("example.com",
-                               net::ProxyResolverV8::JSBindings::
-                                   ResolveDnsOperation::DNS_RESOLVE_EX);
+                               net::ProxyResolveDnsOperation::DNS_RESOLVE_EX);
   request->Start(base::BindOnce(&Fail));
 
   request.reset();
diff --git a/services/proxy_resolver/mojo_proxy_resolver_v8_tracing_bindings.h b/services/proxy_resolver/mojo_proxy_resolver_v8_tracing_bindings.h
index 0cb87cc..6c92678 100644
--- a/services/proxy_resolver/mojo_proxy_resolver_v8_tracing_bindings.h
+++ b/services/proxy_resolver/mojo_proxy_resolver_v8_tracing_bindings.h
@@ -17,7 +17,7 @@
 #include "net/dns/host_resolver.h"
 #include "net/log/net_log_with_source.h"
 #include "net/proxy_resolution/proxy_host_resolver.h"
-#include "net/proxy_resolution/proxy_resolver_v8.h"
+#include "net/proxy_resolution/proxy_resolve_dns_operation.h"
 #include "net/proxy_resolution/proxy_resolver_v8_tracing.h"
 #include "services/proxy_resolver/host_resolver_mojo.h"
 #include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
@@ -62,23 +62,22 @@
 
  private:
   // HostResolverMojo::Impl override.
-  void ResolveDns(
-      const std::string& hostname,
-      net::ProxyResolverV8::JSBindings::ResolveDnsOperation operation,
-      mojom::HostResolverRequestClientPtr client) override {
+  void ResolveDns(const std::string& hostname,
+                  net::ProxyResolveDnsOperation operation,
+                  mojom::HostResolverRequestClientPtr client) override {
     DCHECK(thread_checker_.CalledOnValidThread());
 
     net::HostPortPair host_port = net::HostPortPair(hostname, 80);
     auto info = std::make_unique<net::HostResolver::RequestInfo>(host_port);
 
     // Flag myIpAddress requests.
-    if (operation == net::ProxyResolverV8::JSBindings::MY_IP_ADDRESS ||
-        operation == net::ProxyResolverV8::JSBindings::MY_IP_ADDRESS_EX)
+    if (operation == net::ProxyResolveDnsOperation::MY_IP_ADDRESS ||
+        operation == net::ProxyResolveDnsOperation::MY_IP_ADDRESS_EX)
       info->set_is_my_ip_address(true);
 
     // The non-ex flavors are limited to IPv4 results.
-    if (operation == net::ProxyResolverV8::JSBindings::MY_IP_ADDRESS ||
-        operation == net::ProxyResolverV8::JSBindings::DNS_RESOLVE) {
+    if (operation == net::ProxyResolveDnsOperation::MY_IP_ADDRESS ||
+        operation == net::ProxyResolveDnsOperation::DNS_RESOLVE) {
       info->set_address_family(net::ADDRESS_FAMILY_IPV4);
     }
 
diff --git a/services/service_manager/BUILD.gn b/services/service_manager/BUILD.gn
index 8709a062..9fe38eb5 100644
--- a/services/service_manager/BUILD.gn
+++ b/services/service_manager/BUILD.gn
@@ -46,7 +46,6 @@
   public_deps = [
     "//base",
     "//mojo/public/cpp/bindings",
-    "//services/catalog/public/mojom",
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/mojom",
     "//services/service_manager/sandbox",
diff --git a/services/service_manager/DEPS b/services/service_manager/DEPS
index eac54bc..ec69c8f 100644
--- a/services/service_manager/DEPS
+++ b/services/service_manager/DEPS
@@ -1,5 +1,3 @@
 include_rules = [
-  "+components/services/filesystem",
   "+sandbox",
-  "+services/catalog",
 ]
diff --git a/services/service_manager/catalog.cc b/services/service_manager/catalog.cc
index e656a30..f9f7742c 100644
--- a/services/service_manager/catalog.cc
+++ b/services/service_manager/catalog.cc
@@ -4,28 +4,8 @@
 
 #include "services/service_manager/catalog.h"
 
-#include <string>
-#include <utility>
 #include <vector>
 
-#include "base/base_paths.h"
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/lazy_instance.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted_delete_on_sequence.h"
-#include "base/path_service.h"
-#include "base/sequenced_task_runner.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/task/post_task.h"
-#include "components/services/filesystem/directory_impl.h"
-#include "components/services/filesystem/lock_table.h"
-#include "components/services/filesystem/public/interfaces/types.mojom.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-
 namespace service_manager {
 
 namespace {
@@ -55,50 +35,13 @@
 
 }  // namespace
 
-// Wraps state needed for servicing directory requests on a separate thread.
-// filesystem::LockTable is not thread safe, so it's wrapped in
-// DirectoryThreadState.
-class Catalog::DirectoryThreadState
-    : public base::RefCountedDeleteOnSequence<DirectoryThreadState> {
- public:
-  explicit DirectoryThreadState(
-      scoped_refptr<base::SequencedTaskRunner> task_runner)
-      : base::RefCountedDeleteOnSequence<DirectoryThreadState>(
-            std::move(task_runner)) {}
-
-  scoped_refptr<filesystem::LockTable> lock_table() {
-    if (!lock_table_)
-      lock_table_ = new filesystem::LockTable;
-    return lock_table_;
-  }
-
- private:
-  friend class base::DeleteHelper<DirectoryThreadState>;
-  friend class base::RefCountedDeleteOnSequence<DirectoryThreadState>;
-
-  ~DirectoryThreadState() = default;
-
-  scoped_refptr<filesystem::LockTable> lock_table_;
-
-  DISALLOW_COPY_AND_ASSIGN(DirectoryThreadState);
-};
-
 Catalog::Catalog(const std::vector<Manifest>& manifests)
     : manifests_(manifests),
       manifest_map_(CreateManifestMap(manifests_)),
-      parent_manifest_map_(CreateParentManifestMap(manifests_)) {
-  registry_.AddInterface<catalog::mojom::Catalog>(base::BindRepeating(
-      &Catalog::BindCatalogRequest, base::Unretained(this)));
-  registry_.AddInterface<filesystem::mojom::Directory>(base::BindRepeating(
-      &Catalog::BindDirectoryRequest, base::Unretained(this)));
-}
+      parent_manifest_map_(CreateParentManifestMap(manifests_)) {}
 
 Catalog::~Catalog() = default;
 
-void Catalog::BindServiceRequest(mojom::ServiceRequest request) {
-  service_binding_.Bind(std::move(request));
-}
-
 const Manifest* Catalog::GetManifest(
     const Manifest::ServiceName& service_name) {
   const auto it = manifest_map_.find(service_name);
@@ -116,79 +59,4 @@
   return it->second;
 }
 
-void Catalog::BindCatalogRequest(catalog::mojom::CatalogRequest request) {
-  catalog_bindings_.AddBinding(this, std::move(request));
-}
-
-void Catalog::BindDirectoryRequest(
-    filesystem::mojom::DirectoryRequest request) {
-  if (!directory_task_runner_) {
-    directory_task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
-        {base::MayBlock(),
-         // Use USER_BLOCKING as this gates showing UI during startup.
-         base::TaskPriority::USER_BLOCKING,
-         base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
-    directory_thread_state_ = new DirectoryThreadState(directory_task_runner_);
-  }
-  directory_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&Catalog::BindDirectoryRequestOnBackgroundThread,
-                     directory_thread_state_, std::move(request)));
-}
-
-// static
-void Catalog::BindDirectoryRequestOnBackgroundThread(
-    scoped_refptr<DirectoryThreadState> thread_state,
-    filesystem::mojom::DirectoryRequest request) {
-  base::FilePath resources_path;
-  base::PathService::Get(base::DIR_MODULE, &resources_path);
-  mojo::MakeStrongBinding(
-      std::make_unique<filesystem::DirectoryImpl>(
-          resources_path, scoped_refptr<filesystem::SharedTempDir>(),
-          thread_state->lock_table()),
-      std::move(request));
-}
-
-void Catalog::OnBindInterface(const BindSourceInfo& source_info,
-                              const std::string& interface_name,
-                              mojo::ScopedMessagePipeHandle interface_pipe) {
-  registry_.BindInterface(interface_name, std::move(interface_pipe));
-}
-
-void Catalog::GetEntries(const base::Optional<std::vector<std::string>>& names,
-                         GetEntriesCallback callback) {
-  std::vector<catalog::mojom::EntryPtr> entries;
-  if (!names.has_value()) {
-    for (const auto& entry : manifest_map_) {
-      const auto* manifest = entry.second;
-      entries.push_back(catalog::mojom::Entry::New(
-          manifest->service_name, manifest->display_name.raw_string));
-    }
-  } else {
-    for (const std::string& name : names.value()) {
-      const auto* manifest = GetManifest(name);
-      if (manifest) {
-        entries.push_back(catalog::mojom::Entry::New(
-            manifest->service_name, manifest->display_name.raw_string));
-      }
-    }
-  }
-  std::move(callback).Run(std::move(entries));
-}
-
-void Catalog::GetEntriesProvidingCapability(
-    const std::string& capability,
-    GetEntriesProvidingCapabilityCallback callback) {
-  std::vector<catalog::mojom::EntryPtr> entries;
-  for (const auto& entry : manifest_map_) {
-    const auto* manifest = entry.second;
-    if (manifest->exposed_capabilities.find(capability) !=
-        manifest->exposed_capabilities.end()) {
-      entries.push_back(catalog::mojom::Entry::New(
-          manifest->service_name, manifest->display_name.raw_string));
-    }
-  }
-  std::move(callback).Run(std::move(entries));
-}
-
 }  // namespace service_manager
diff --git a/services/service_manager/catalog.h b/services/service_manager/catalog.h
index 908c76af..64bacd8e 100644
--- a/services/service_manager/catalog.h
+++ b/services/service_manager/catalog.h
@@ -6,40 +6,20 @@
 #define SERVICES_SERVICE_MANAGER_CATALOG_H_
 
 #include <map>
-#include <string>
 #include <vector>
 
 #include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/token.h"
-#include "components/services/filesystem/public/interfaces/directory.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/catalog/public/mojom/catalog.mojom.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/manifest.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/cpp/service_binding.h"
-#include "services/service_manager/public/mojom/service.mojom.h"
-
-namespace base {
-class SequencedTaskRunner;
-}
 
 namespace service_manager {
 
-// Creates and owns an instance of the catalog and hosts a ServiceBinding to
-// bind interface requests targeting the Catalog service.
-//
-// TODO(https://crbug.com/904240): Get rid of the Service implementation.
-// This doesn't need to be a separate service from the Service Manager.
-class Catalog : public Service, public catalog::mojom::Catalog {
+// Owns the Service Manager's collections of Manifests and provides convenient
+// indexes for fast lookup by name and resolution of parent-child relationships.
+class Catalog {
  public:
   // Constructs a catalog over a set of Manifests to use for lookup.
   explicit Catalog(const std::vector<Manifest>& manifests);
-  ~Catalog() override;
-
-  void BindServiceRequest(mojom::ServiceRequest request);
+  ~Catalog();
 
   // Returns manifest data for the service named by |service_name|. If no
   // service is known by that name, this returns null.
@@ -51,33 +31,6 @@
   const Manifest* GetParentManifest(const Manifest::ServiceName& service_name);
 
  private:
-  class DirectoryThreadState;
-
-  void BindCatalogRequest(catalog::mojom::CatalogRequest request);
-  void BindDirectoryRequest(filesystem::mojom::DirectoryRequest request);
-
-  static void BindDirectoryRequestOnBackgroundThread(
-      scoped_refptr<DirectoryThreadState> thread_state,
-      filesystem::mojom::DirectoryRequest request);
-
-  // Service:
-  void OnBindInterface(const BindSourceInfo& source_info,
-                       const std::string& interface_name,
-                       mojo::ScopedMessagePipeHandle interface_pipe) override;
-
-  // mojom::Catalog:
-  void GetEntries(const base::Optional<std::vector<std::string>>& names,
-                  GetEntriesCallback callback) override;
-  void GetEntriesProvidingCapability(
-      const std::string& capability,
-      GetEntriesProvidingCapabilityCallback callback) override;
-
-  ServiceBinding service_binding_{this};
-  BinderRegistry registry_;
-
-  // Bindings for consumers of the Catalog interface.
-  mojo::BindingSet<catalog::mojom::Catalog> catalog_bindings_;
-
   // The set of all top-level manifests known to the Service Manager.
   const std::vector<Manifest> manifests_;
 
@@ -91,13 +44,6 @@
   // refer to objects owned by |manifests_| above.
   const std::map<Manifest::ServiceName, const Manifest*> parent_manifest_map_;
 
-  // The TaskRunner used for directory requests. Directory requests run on a
-  // separate thread as they run file io, which is not allowed on the thread the
-  // service manager runs on. Additionally we shouldn't block the service
-  // manager while doing file io.
-  scoped_refptr<base::SequencedTaskRunner> directory_task_runner_;
-  scoped_refptr<DirectoryThreadState> directory_thread_state_;
-
   DISALLOW_COPY_AND_ASSIGN(Catalog);
 };
 
diff --git a/services/service_manager/public/cpp/service_executable/BUILD.gn b/services/service_manager/public/cpp/service_executable/BUILD.gn
index 6d4b312..3dff0e5 100644
--- a/services/service_manager/public/cpp/service_executable/BUILD.gn
+++ b/services/service_manager/public/cpp/service_executable/BUILD.gn
@@ -55,6 +55,10 @@
     "main.cc",
   ]
 
+  public_deps = [
+    "//services/service_manager/public/mojom",
+  ]
+
   deps = [
     ":support",
     "//base",
diff --git a/services/service_manager/public/cpp/test/DEPS b/services/service_manager/public/cpp/test/DEPS
deleted file mode 100644
index c5e51f22..0000000
--- a/services/service_manager/public/cpp/test/DEPS
+++ /dev/null
@@ -1,5 +0,0 @@
-specific_include_rules = {
-  "run_all_service_tests.cc": [
-    "+services/catalog",
-  ]
-}
diff --git a/services/service_manager/service_manager.cc b/services/service_manager/service_manager.cc
index b61ce39..c9949b5 100644
--- a/services/service_manager/service_manager.cc
+++ b/services/service_manager/service_manager.cc
@@ -32,7 +32,6 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/catalog/public/mojom/constants.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/constants.h"
 #include "services/service_manager/public/cpp/manifest_builder.h"
@@ -90,15 +89,6 @@
 #endif
 }
 
-bool RequiresCapability(const Manifest& manifest,
-                        const Manifest::ServiceName& from_service_name,
-                        const Manifest::CapabilityName& capability) {
-  auto it = manifest.required_capabilities.find(from_service_name);
-  if (it == manifest.required_capabilities.end())
-    return false;
-  return it->second.find(capability) != it->second.end();
-}
-
 void ReportBlockedInterface(const Manifest::ServiceName& source_service_name,
                             const Manifest::ServiceName& target_service_name,
                             const std::string& target_interface_name) {
@@ -170,7 +160,6 @@
 class ServiceManager::Instance
     : public mojom::Connector,
       public mojom::PIDReceiver,
-      public Service,
       public mojom::ServiceManager,
       public mojom::ServiceControl {
  public:
@@ -186,10 +175,8 @@
         control_binding_(this),
         state_(mojom::InstanceState::kCreated),
         weak_factory_(this) {
-    if (identity_.name() == service_manager::mojom::kServiceName ||
-        identity_.name() == catalog::mojom::kServiceName) {
+    if (identity_.name() == service_manager::mojom::kServiceName)
       pid_ = GetCurrentPid();
-    }
     DCHECK(identity_.IsValid());
   }
 
@@ -327,20 +314,8 @@
     identity_ = identity;
   }
 
-  // Service:
-  void OnBindInterface(const BindSourceInfo& source_info,
-                       const std::string& interface_name,
-                       mojo::ScopedMessagePipeHandle interface_pipe) override {
-    Instance* source =
-        service_manager_->GetExistingInstance(source_info.identity);
-    DCHECK(source);
-    if (interface_name == mojom::ServiceManager::Name_ &&
-        RequiresCapability(source->manifest(), mojom::kServiceName,
-                           kCapability_ServiceManager)) {
-      mojom::ServiceManagerRequest request =
-          mojom::ServiceManagerRequest(std::move(interface_pipe));
-      service_manager_bindings_.AddBinding(this, std::move(request));
-    }
+  void BindServiceManager(mojom::ServiceManagerRequest request) {
+    service_manager_bindings_.AddBinding(this, std::move(request));
   }
 
  private:
@@ -973,21 +948,6 @@
   mojom::ServicePtr service;
   service_binding_.Bind(mojo::MakeRequest(&service));
   service_manager_instance_->StartWithService(std::move(service));
-
-  Manifest catalog_manifest =
-      ManifestBuilder()
-          .ExposeCapability("directory", {"filesystem.mojom.Directory"})
-          .ExposeCapability("catalog:catalog", {"catalog.mojom.Catalog"})
-          .Build();
-
-  Identity id{catalog::mojom::kServiceName, kSystemInstanceGroup, base::Token{},
-              base::Token::CreateRandom()};
-  Instance* instance =
-      CreateInstance(id, InstanceType::kSingleton, catalog_manifest);
-
-  mojom::ServicePtr catalog_service;
-  catalog_.BindServiceRequest(mojo::MakeRequest(&catalog_service));
-  instance->StartWithService(std::move(catalog_service));
 }
 
 ServiceManager::~ServiceManager() {
@@ -1365,14 +1325,12 @@
     const BindSourceInfo& source_info,
     const std::string& interface_name,
     mojo::ScopedMessagePipeHandle interface_pipe) {
-  // The only interface ServiceManager exposes is mojom::ServiceManager, and
-  // access to this interface is brokered by a policy specific to each caller,
-  // managed by the caller's instance. Here we look to see who's calling,
-  // and forward to the caller's instance to continue.
   Instance* instance = GetExistingInstance(source_info.identity);
   DCHECK(instance);
-  instance->OnBindInterface(source_info, interface_name,
-                            std::move(interface_pipe));
+  if (interface_name == mojom::ServiceManager::Name_) {
+    instance->BindServiceManager(
+        mojom::ServiceManagerRequest(std::move(interface_pipe)));
+  }
 }
 
 }  // namespace service_manager
diff --git a/services/viz/public/cpp/manifest.cc b/services/viz/public/cpp/manifest.cc
index f0c7f8a..0ef92ef 100644
--- a/services/viz/public/cpp/manifest.cc
+++ b/services/viz/public/cpp/manifest.cc
@@ -44,7 +44,6 @@
         .ExposeCapability(
             "viz_host",
             service_manager::Manifest::InterfaceList<mojom::VizMain>())
-        .RequireCapability("catalog", "directory")
         .RequireCapability("metrics", "url_keyed_metrics")
         .RequireCapability("ui", "ozone")
         .Build()
diff --git a/services/ws/client_root.cc b/services/ws/client_root.cc
index 4e4d284..394392b 100644
--- a/services/ws/client_root.cc
+++ b/services/ws/client_root.cc
@@ -252,6 +252,12 @@
       window_->GetFrameSinkId(),
       proxy_window->local_surface_id_allocation()->local_surface_id());
   client_surface_embedder_->SetSurfaceId(surface_id);
+
+  // This triggers holding events until the frame has been activated. This
+  // ensures smooth resizes.
+  if (ShouldAssignLocalSurfaceId() && window_->GetHost())
+    window_->GetHost()->compositor()->OnChildResizing();
+
   if (fallback_surface_info_) {
     client_surface_embedder_->SetFallbackSurfaceInfo(*fallback_surface_info_);
     fallback_surface_info_.reset();
@@ -408,6 +414,8 @@
 
 void ClientRoot::OnFirstSurfaceActivation(
     const viz::SurfaceInfo& surface_info) {
+  // TODO(sky): saman says the SetFallbackSurfaceInfo() should not be needed
+  // anymore.
   ProxyWindow* proxy_window = ProxyWindow::GetMayBeNull(window_);
   if (proxy_window->local_surface_id_allocation().has_value()) {
     DCHECK(!fallback_surface_info_);
diff --git a/services/ws/public/cpp/manifest.cc b/services/ws/public/cpp/manifest.cc
index c0d53c8..0a1dfee 100644
--- a/services/ws/public/cpp/manifest.cc
+++ b/services/ws/public/cpp/manifest.cc
@@ -93,10 +93,9 @@
                           service_manager::Manifest::InterfaceList<
                               mojom::InputDeviceController>())
 #endif
-        .RequireCapability("viz", "viz_host")
-        .RequireCapability("catalog", "directory")
         .RequireCapability("*", "app")
         .RequireCapability("ui", "ozone")
+        .RequireCapability("viz", "viz_host")
 
         .Build()
   };
diff --git a/services/ws/window_service_test_setup.cc b/services/ws/window_service_test_setup.cc
index f85658b..e5bc89c4 100644
--- a/services/ws/window_service_test_setup.cc
+++ b/services/ws/window_service_test_setup.cc
@@ -140,6 +140,9 @@
   ui::InitializeContextFactoryForTests(enable_pixel_output, &context_factory,
                                        &context_factory_private);
   aura_test_helper_.SetUp(context_factory, context_factory_private);
+  // The resize throttle may interfere with tests, so disable it. If specific
+  // tests want the throttle, they can enable it.
+  aura::Env::GetInstance()->set_throttle_input_on_resize_for_testing(false);
   scoped_capture_client_ = std::make_unique<wm::ScopedCaptureClient>(
       aura_test_helper_.root_window());
   service_ =
diff --git a/storage/browser/blob/blob_builder_from_stream_unittest.cc b/storage/browser/blob/blob_builder_from_stream_unittest.cc
index aacc841c..184f2b7 100644
--- a/storage/browser/blob/blob_builder_from_stream_unittest.cc
+++ b/storage/browser/blob/blob_builder_from_stream_unittest.cc
@@ -429,12 +429,12 @@
   EXPECT_GE(progress_client.call_count, 2);
 }
 
-INSTANTIATE_TEST_CASE_P(BlobBuilderFromStreamTest,
-                        BlobBuilderFromStreamTest,
-                        ::testing::Values(LengthHintTestType::kUnknownSize,
-                                          LengthHintTestType::kCorrectSize,
-                                          LengthHintTestType::kTooLargeSize,
-                                          LengthHintTestType::kTooSmallSize));
+INSTANTIATE_TEST_SUITE_P(BlobBuilderFromStreamTest,
+                         BlobBuilderFromStreamTest,
+                         ::testing::Values(LengthHintTestType::kUnknownSize,
+                                           LengthHintTestType::kCorrectSize,
+                                           LengthHintTestType::kTooLargeSize,
+                                           LengthHintTestType::kTooSmallSize));
 
 TEST_F(BlobBuilderFromStreamTestWithDelayedLimits, LargeStream) {
   const std::string kData =
diff --git a/storage/browser/blob/blob_transport_strategy_unittest.cc b/storage/browser/blob/blob_transport_strategy_unittest.cc
index 63e67f5..0132cc7e 100644
--- a/storage/browser/blob/blob_transport_strategy_unittest.cc
+++ b/storage/browser/blob/blob_transport_strategy_unittest.cc
@@ -203,11 +203,11 @@
   }
 }
 
-INSTANTIATE_TEST_CASE_P(BlobTransportStrategyTest,
-                        BasicTests,
-                        testing::Values(MemoryStrategy::NONE_NEEDED,
-                                        MemoryStrategy::IPC,
-                                        MemoryStrategy::SHARED_MEMORY));
+INSTANTIATE_TEST_SUITE_P(BlobTransportStrategyTest,
+                         BasicTests,
+                         testing::Values(MemoryStrategy::NONE_NEEDED,
+                                         MemoryStrategy::IPC,
+                                         MemoryStrategy::SHARED_MEMORY));
 
 class BasicErrorTests : public BlobTransportStrategyTest,
                         public testing::WithParamInterface<MemoryStrategy> {};
@@ -273,10 +273,10 @@
   }
 }
 
-INSTANTIATE_TEST_CASE_P(BlobTransportStrategyTest,
-                        BasicErrorTests,
-                        testing::Values(MemoryStrategy::IPC,
-                                        MemoryStrategy::SHARED_MEMORY));
+INSTANTIATE_TEST_SUITE_P(BlobTransportStrategyTest,
+                         BasicErrorTests,
+                         testing::Values(MemoryStrategy::IPC,
+                                         MemoryStrategy::SHARED_MEMORY));
 
 TEST_F(BlobTransportStrategyTest, DataStreamChunksData) {
   BlobDataBuilder builder(kId);
diff --git a/storage/browser/fileapi/file_writer_impl_unittest.cc b/storage/browser/fileapi/file_writer_impl_unittest.cc
index e7162cfb5..18541ef 100644
--- a/storage/browser/fileapi/file_writer_impl_unittest.cc
+++ b/storage/browser/fileapi/file_writer_impl_unittest.cc
@@ -176,9 +176,9 @@
   bool WriteUsingBlobs() override { return GetParam(); }
 };
 
-INSTANTIATE_TEST_CASE_P(FileWriterImplTest,
-                        FileWriterImplWriteTest,
-                        ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(FileWriterImplTest,
+                         FileWriterImplWriteTest,
+                         ::testing::Bool());
 
 TEST_F(FileWriterImplTest, WriteInvalidBlob) {
   blink::mojom::BlobPtr blob;
diff --git a/storage/browser/quota/quota_client.cc b/storage/browser/quota/quota_client.cc
index 0927efb..9f0cd40 100644
--- a/storage/browser/quota/quota_client.cc
+++ b/storage/browser/quota/quota_client.cc
@@ -11,5 +11,5 @@
 void QuotaClient::PerformStorageCleanup(blink::mojom::StorageType type,
                                         base::OnceClosure callback) {
   std::move(callback).Run();
-};
+}
 }  // namespace storage
diff --git a/styleguide/web/web.md b/styleguide/web/web.md
index 56230a7..3544dd5 100644
--- a/styleguide/web/web.md
+++ b/styleguide/web/web.md
@@ -351,11 +351,7 @@
     * DO: `Object<T>`
     * DON'T: `Object<string, T>`
 
-### Events
 
-* Use Polymer's `on-tap` for click events instead of `on-click`
-    * `on-tap` handlers should use `stopPropagation()` to prevent parents from
-      handling the event where appropriate.
 
 <div class="note">
 Calling <code>stopPropagation()</code> from an <code>on-tap</code> handler will
@@ -384,6 +380,10 @@
   This makes changing the type of `this.foo` easier (as the `@type` is
   duplicated in less places, i.e. `@param`).
 
+* Use native `on-click` for click events instead of `on-tap`. 'tap' is a
+  synthetic event provided by Polymer for backward compatibility with some
+  browsers and is not needed by Chrome.
+
 ```js
 properties: {
   foo: {type: Number, observer: 'fooChanged_'}
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 91d40d92..6b363ca 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -4013,6 +4013,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "angle_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "base_unittests"
       },
       {
@@ -4166,6 +4172,17 @@
             }
           ]
         },
+        "test": "angle_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1"
+            }
+          ]
+        },
         "test": "base_unittests"
       },
       {
@@ -4424,6 +4441,17 @@
             }
           ]
         },
+        "test": "angle_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1"
+            }
+          ]
+        },
         "test": "base_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index e7fa42d..b51612b 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -663,6 +663,20 @@
             }
           ]
         },
+        "test": "angle_unittests"
+      },
+      {
+        "args": [
+          "--qemu-require-kvm"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1"
+            }
+          ]
+        },
         "test": "base_unittests"
       },
       {
diff --git a/testing/buildbot/filters/webui_polymer2_browser_tests.filter b/testing/buildbot/filters/webui_polymer2_browser_tests.filter
index d87acad..2e00972f 100644
--- a/testing/buildbot/filters/webui_polymer2_browser_tests.filter
+++ b/testing/buildbot/filters/webui_polymer2_browser_tests.filter
@@ -91,6 +91,7 @@
 CrExtensionsActivityLogTest.*
 CrExtensionsActivityLogHistoryTest.*
 CrExtensionsActivityLogItemTest.*
+CrExtensionsActivityLogStreamTest.*
 CrExtensionsA11yTest.*
 CrExtensionsA11yTestWithMultipleExensions.*
 CrExtensionsCodeSectionTest.*
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 037ee32..d769530 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -2741,6 +2741,7 @@
     },
 
     'fuchsia_gtests': {
+      'angle_unittests': {},
       'base_unittests': {},
       'cast_runner_browsertests': {},
       'cast_runner_integration_tests': {},
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 0593469..229c6dc9 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1184,22 +1184,6 @@
             ]
         }
     ],
-    "CCTModulePhase1": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled_With_Cache",
-                    "enable_features": [
-                        "CCTModule",
-                        "CCTModuleCache"
-                    ]
-                }
-            ]
-        }
-    ],
     "CertificateTransparencyLogAuditing": [
         {
             "platforms": [
@@ -3661,7 +3645,7 @@
             ],
             "experiments": [
                 {
-                    "name": "PredictivePrefetchingAllowedOnAllConnectionTypes",
+                    "name": "Enabled",
                     "enable_features": [
                         "PredictivePrefetchingAllowedOnAllConnectionTypes"
                     ]
@@ -4533,8 +4517,7 @@
                     "name": "PrefetchTrailerHint2",
                     "params": {
                         "FullPrefetchBytes": "0",
-                        "TrailerPrefetchHint": "true",
-                        "TrailerPrefetchSpeculativeBytes": "0"
+                        "TrailerPrefetchHint": "true"
                     },
                     "enable_features": [
                         "SimpleCachePrefetchExperiment2"
@@ -4554,11 +4537,13 @@
                     "name": "ExperimentNoTrailerPrefetchHint4",
                     "params": {
                         "FullPrefetchBytes": "0",
-                        "TrailerPrefetchInt": "true",
-                        "TrailerPrefetchSpeculativeBytes": "0"
+                        "TrailerPrefetchHint": "true"
                     },
                     "enable_features": [
                         "SimpleCachePrefetchExperiment2"
+                    ],
+                    "disable_features": [
+                        "HttpCacheForceBackend"
                     ]
                 }
             ]
diff --git a/third_party/blink/public/platform/web_rtc_peer_connection_handler.h b/third_party/blink/public/platform/web_rtc_peer_connection_handler.h
index 815b730..76f73c66c 100644
--- a/third_party/blink/public/platform/web_rtc_peer_connection_handler.h
+++ b/third_party/blink/public/platform/web_rtc_peer_connection_handler.h
@@ -32,6 +32,7 @@
 #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_RTC_PEER_CONNECTION_HANDLER_H_
 
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "third_party/blink/public/platform/web_rtc_ice_candidate.h"
@@ -144,6 +145,13 @@
 
   // Returns a pointer to the underlying native PeerConnection object.
   virtual webrtc::PeerConnectionInterface* NativePeerConnection() = 0;
+
+  virtual void RunSynchronousOnceClosureOnSignalingThread(
+      base::OnceClosure closure,
+      const char* trace_event_name) = 0;
+  virtual void RunSynchronousRepeatingClosureOnSignalingThread(
+      const base::RepeatingClosure& closure,
+      const char* trace_event_name) = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index b49208f..5000d9c 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -2783,8 +2783,14 @@
   // wouldn't be fired.
   network_state_observer_ = MakeGarbageCollected<NetworkStateObserver>(*this);
 
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-    AttachCompositorAnimationTimeline();
+  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+    CompositorAnimationTimeline* animation_timeline =
+        Timeline().CompositorTimeline();
+    if (animation_timeline) {
+      GetPage()->GetChromeClient().AttachCompositorAnimationTimeline(
+          animation_timeline, frame_.Get());
+    }
+  }
 }
 
 void Document::Shutdown() {
@@ -7287,14 +7293,6 @@
   return *(result.stored_value->value);
 }
 
-void Document::AttachCompositorAnimationTimeline() {
-  DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
-  if (auto* compositor_timeline = Timeline().CompositorTimeline()) {
-    GetPage()->GetChromeClient().AttachCompositorAnimationTimeline(
-        compositor_timeline, frame_.Get());
-  }
-}
-
 AnimationClock& Document::GetAnimationClock() {
   DCHECK(GetPage());
   return GetPage()->Animator().Clock();
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 13e9412f..473529a 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -1252,11 +1252,6 @@
   // Return a Locale for the default locale if the argument is null or empty.
   Locale& GetCachedLocale(const AtomicString& locale = g_null_atom);
 
-  // For CompositeAfterPaint. This is called internally from Initialize(), but
-  // for the local frame root, the frame widget may be not set at the time,
-  // so this is also called from WebLocalFrameImpl::SetFrameWidget().
-  void AttachCompositorAnimationTimeline();
-
   AnimationClock& GetAnimationClock();
   DocumentTimeline& Timeline() const { return *timeline_; }
   PendingAnimations& GetPendingAnimations() { return *pending_animations_; }
diff --git a/third_party/blink/renderer/core/dom/layout_tree_builder.cc b/third_party/blink/renderer/core/dom/layout_tree_builder.cc
index 28d64ae1..c6cc46b 100644
--- a/third_party/blink/renderer/core/dom/layout_tree_builder.cc
+++ b/third_party/blink/renderer/core/dom/layout_tree_builder.cc
@@ -78,6 +78,7 @@
     : LayoutTreeBuilder(element, nullptr), style_(style) {
   DCHECK(element.CanParticipateInFlatTree());
   DCHECK(style_);
+  DCHECK(!style_->IsEnsuredInDisplayNone());
   // TODO(ecobos): Move the first-letter logic inside ParentLayoutObject too?
   // It's an extra (unnecessary) check for text nodes, though.
   if (element.IsFirstLetterPseudoElement()) {
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
index f6065a4..3706b37 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
@@ -68,16 +68,15 @@
                           kContentSecurityPolicyHeaderSourceHTTP);
     EXPECT_EQ(test.expected_policy, csp->GetInsecureRequestPolicy());
 
-    execution_context = CreateExecutionContext();
-    execution_context->SetSecurityOrigin(secure_origin);
-    execution_context->SetURL(secure_url);
-    csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
-    EXPECT_EQ(test.expected_policy,
-              execution_context->GetInsecureRequestPolicy());
+    Document* document = Document::CreateForTest();
+    document->SetSecurityOrigin(secure_origin);
+    document->SetURL(secure_url);
+    csp->BindToDelegate(document->GetContentSecurityPolicyDelegate());
+    EXPECT_EQ(test.expected_policy, document->GetInsecureRequestPolicy());
     bool expect_upgrade = test.expected_policy & kUpgradeInsecureRequests;
     EXPECT_EQ(expect_upgrade,
-              execution_context->InsecureNavigationsToUpgrade()->Contains(
-                  execution_context->Url().Host().Impl()->GetHash()));
+              document->InsecureNavigationsToUpgrade()->Contains(
+                  document->Url().Host().Impl()->GetHash()));
   }
 
   // Report-Only
diff --git a/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc b/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc
index 9fa20c7..46a0201 100644
--- a/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc
+++ b/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc
@@ -75,11 +75,14 @@
     // Step 4. Insert tuple into settings’s upgrade insecure navigations set.
     // [spec text]
     Count(WebFeature::kUpgradeInsecureRequestsEnabled);
-    if (!Url().Host().IsEmpty()) {
+    // We don't add the hash if |document| is null, to prevent
+    // WorkerGlobalScope::Url() before it's ready. https://crbug.com/861564
+    // This should be safe, because the insecure navigations set is not used
+    // in non-Document contexts.
+    if (document && !Url().Host().IsEmpty()) {
       uint32_t hash = Url().Host().Impl()->GetHash();
       security_context.AddInsecureNavigationUpgrade(hash);
-      if (document)
-        document->DidEnforceInsecureNavigationsSet();
+      document->DidEnforceInsecureNavigationsSet();
     }
   }
 }
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index d0b604d9..ae240d4 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -2306,14 +2306,6 @@
 
 void WebLocalFrameImpl::SetFrameWidget(WebFrameWidgetBase* frame_widget) {
   frame_widget_ = frame_widget;
-
-  // This is needed because the local frame root's widget may not be set when
-  // Document::Initialize() called AttachmentCompositorAnimationTimeline()
-  // (which requires frame widget to be effective).
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() && frame_widget) {
-    if (auto* document = GetFrame()->GetDocument())
-      document->AttachCompositorAnimationTimeline();
-  }
 }
 
 WebFrameWidget* WebLocalFrameImpl::FrameWidget() const {
diff --git a/third_party/blink/renderer/core/html/html_script_element.cc b/third_party/blink/renderer/core/html/html_script_element.cc
index 748dfed..a888f0b 100644
--- a/third_party/blink/renderer/core/html/html_script_element.cc
+++ b/third_party/blink/renderer/core/html/html_script_element.cc
@@ -107,11 +107,10 @@
 
 Node::InsertionNotificationRequest HTMLScriptElement::InsertedInto(
     ContainerNode& insertion_point) {
-  mojom::ScriptType script_type = mojom::ScriptType::kClassic;
   if (insertion_point.isConnected() && HasSourceAttribute() &&
       !ScriptLoader::IsValidScriptTypeAndLanguage(
           TypeAttributeValue(), LanguageAttributeValue(),
-          ScriptLoader::kDisallowLegacyTypeInTypeAttribute, script_type)) {
+          ScriptLoader::kDisallowLegacyTypeInTypeAttribute)) {
     UseCounter::Count(GetDocument(),
                       WebFeature::kScriptElementWithInvalidTypeHasSrc);
   }
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser.cc b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
index b955f8c..c5bf723c 100644
--- a/third_party/blink/renderer/core/html/parser/html_document_parser.cc
+++ b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
@@ -1242,8 +1242,10 @@
   if (documentElement->hasAttribute(u"\u26A1") ||
       documentElement->hasAttribute("amp") ||
       documentElement->hasAttribute("i-amphtml-layout")) {
-    GetDocument()->Loader()->DidObserveLoadingBehavior(
-        kWebLoadingBehaviorAmpDocumentLoaded);
+    if (document->Loader()) {
+      document->Loader()->DidObserveLoadingBehavior(
+          kWebLoadingBehaviorAmpDocumentLoaded);
+    }
   }
   FetchQueuedPreloads();
 }
diff --git a/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc b/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
index 365db5fa..d496fb0 100644
--- a/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
+++ b/third_party/blink/renderer/core/html/parser/html_preload_scanner.cc
@@ -613,9 +613,15 @@
       return false;
     if (Match(tag_impl_, kScriptTag)) {
       mojom::ScriptType script_type = mojom::ScriptType::kClassic;
+      bool is_import_map = false;
       if (!ScriptLoader::IsValidScriptTypeAndLanguage(
               type_attribute_value_, language_attribute_value_,
-              ScriptLoader::kAllowLegacyTypeInTypeAttribute, script_type)) {
+              ScriptLoader::kAllowLegacyTypeInTypeAttribute, &script_type,
+              &is_import_map)) {
+        return false;
+      }
+      if (is_import_map) {
+        // External import maps are not yet supported. https://crbug.com/922212
         return false;
       }
       if (ScriptLoader::BlockForNoModule(script_type,
diff --git a/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc b/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc
index 73e44eb7..f20d9a8 100644
--- a/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc
+++ b/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc
@@ -173,10 +173,9 @@
           language_attribute_value = item->Value();
         }
 
-        mojom::ScriptType script_type;
         if (ScriptLoader::IsValidScriptTypeAndLanguage(
                 type_attribute_value, language_attribute_value,
-                ScriptLoader::kAllowLegacyTypeInTypeAttribute, script_type)) {
+                ScriptLoader::kAllowLegacyTypeInTypeAttribute)) {
           simulated_token = kValidScriptStart;
         }
       } else if (ThreadSafeMatch(tag_name, kLinkTag)) {
diff --git a/third_party/blink/renderer/core/inspector/devtools_session.cc b/third_party/blink/renderer/core/inspector/devtools_session.cc
index 6accbffe..3eb4292 100644
--- a/third_party/blink/renderer/core/inspector/devtools_session.cc
+++ b/third_party/blink/renderer/core/inspector/devtools_session.cc
@@ -52,9 +52,18 @@
 }
 
 protocol::ProtocolMessage ToProtocolMessage(
-    const v8_inspector::StringView& string) {
+    std::unique_ptr<v8_inspector::StringBuffer> buffer,
+    bool binary) {
   protocol::ProtocolMessage message;
-  message.json = ToCoreString(string);
+  if (binary) {
+    const auto& string = buffer->string();
+    DCHECK(string.is8Bit());
+    // TODO: add StringBuffer::takeBytes().
+    message.binary = std::vector<uint8_t>(
+        string.characters8(), string.characters8() + string.length());
+  } else {
+    message.json = ToCoreString(buffer->string());
+  }
   return message;
 }
 
@@ -192,21 +201,10 @@
 void DevToolsSession::DispatchProtocolCommandImpl(int call_id,
                                                   const String& method,
                                                   std::vector<uint8_t> data) {
-  // At this point, message is either a UTF8 string or a binary message.
-  protocol::ProtocolMessage message;
-  if (data.size()) {
-    if (data[0] == '{') {
-      // JSON format.
-      message.json = WTF::String::FromUTF8(
-          reinterpret_cast<const char*>(data.data()), data.size());
-    } else {
-      // Binary format.
-    }
-  } else {
-    message.json = g_empty_string;
-  }
+  bool binary_protocol = data.size() && data[0] == 0xD8;
+  if (binary_protocol)
+    uses_binary_protocol_ = true;
 
-  //
   // IOSession does not provide ordering guarantees relative to
   // Session, so a command may come to IOSession after Session is detached,
   // and get posted to main thread to this method.
@@ -222,9 +220,27 @@
   agent_->client_->DebuggerTaskStarted();
   if (v8_inspector::V8InspectorSession::canDispatchMethod(
           ToV8InspectorStringView(method))) {
-    v8_session_->dispatchProtocolMessage(ToV8InspectorStringView(message.json));
+    if (binary_protocol) {
+      // Binary protocol messages are passed using 8-bit StringView.
+      v8_session_->dispatchProtocolMessage(
+          v8_inspector::StringView(data.data(), data.size()));
+    } else {
+      String message = WTF::String::FromUTF8(
+          reinterpret_cast<const char*>(data.data()), data.size());
+      v8_session_->dispatchProtocolMessage(ToV8InspectorStringView(message));
+    }
   } else {
-    inspector_backend_dispatcher_->dispatch(call_id, method, message);
+    std::unique_ptr<protocol::Value> value;
+    if (binary_protocol) {
+      value = protocol::Value::parseBinary(data.data(), data.size());
+    } else {
+      String message = WTF::String::FromUTF8(
+          reinterpret_cast<const char*>(data.data()), data.size());
+      value = protocol::StringUtil::parseJSON(message);
+    }
+    // Don't pass protocol message further - there is no passthrough.
+    inspector_backend_dispatcher_->dispatch(call_id, method, std::move(value),
+                                            protocol::ProtocolMessage());
   }
   agent_->client_->DebuggerTaskFinished();
 }
@@ -251,7 +267,7 @@
 void DevToolsSession::sendProtocolResponse(
     int call_id,
     std::unique_ptr<protocol::Serializable> message) {
-  SendProtocolResponse(call_id, message->serialize());
+  SendProtocolResponse(call_id, message->serialize(uses_binary_protocol_));
 }
 
 void DevToolsSession::fallThrough(int call_id,
@@ -267,7 +283,8 @@
   // We can potentially avoid copies if WebString would convert to utf8 right
   // from StringView, but it uses StringImpl itself, so we don't create any
   // extra copies here.
-  SendProtocolResponse(call_id, ToProtocolMessage(message->string()));
+  SendProtocolResponse(
+      call_id, ToProtocolMessage(std::move(message), uses_binary_protocol_));
 }
 
 void DevToolsSession::SendProtocolResponse(
@@ -307,13 +324,13 @@
       std::unique_ptr<v8_inspector::StringBuffer> notification)
       : v8_notification_(std::move(notification)) {}
 
-  mojom::blink::DevToolsMessagePtr Serialize() {
+  mojom::blink::DevToolsMessagePtr Serialize(bool binary) {
     protocol::ProtocolMessage serialized;
     if (blink_notification_) {
-      serialized = blink_notification_->serialize();
+      serialized = blink_notification_->serialize(binary);
       blink_notification_.reset();
     } else if (v8_notification_) {
-      serialized = ToProtocolMessage(v8_notification_->string());
+      serialized = ToProtocolMessage(std::move(v8_notification_), binary);
       v8_notification_.reset();
     }
     return WrapMessage(serialized);
@@ -350,8 +367,9 @@
   if (v8_session_)
     v8_session_state_json_.Set(ToCoreString(v8_session_->stateJSON()));
   for (wtf_size_t i = 0; i < notification_queue_.size(); ++i) {
-    host_ptr_->DispatchProtocolNotification(notification_queue_[i]->Serialize(),
-                                            session_state_.TakeUpdates());
+    host_ptr_->DispatchProtocolNotification(
+        notification_queue_[i]->Serialize(uses_binary_protocol_),
+        session_state_.TakeUpdates());
   }
   notification_queue_.clear();
 }
diff --git a/third_party/blink/renderer/core/inspector/devtools_session.h b/third_party/blink/renderer/core/inspector/devtools_session.h
index 8b91b32..efd265c 100644
--- a/third_party/blink/renderer/core/inspector/devtools_session.h
+++ b/third_party/blink/renderer/core/inspector/devtools_session.h
@@ -97,6 +97,7 @@
   Vector<std::unique_ptr<Notification>> notification_queue_;
   InspectorAgentState v8_session_state_;
   InspectorAgentState::String v8_session_state_json_;
+  bool uses_binary_protocol_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(DevToolsSession);
 };
diff --git a/third_party/blink/renderer/core/inspector/protocol_parser_test.cc b/third_party/blink/renderer/core/inspector/protocol_parser_test.cc
index e23fc773..259f6778 100644
--- a/third_party/blink/renderer/core/inspector/protocol_parser_test.cc
+++ b/third_party/blink/renderer/core/inspector/protocol_parser_test.cc
@@ -333,7 +333,7 @@
       "  \"S\":\"str\"\n"
       "}\n");
   ASSERT_TRUE(root2.get());
-  EXPECT_EQ(root->serialize().json, root2->serialize().json);
+  EXPECT_EQ(root->serializeToJSON(), root2->serializeToJSON());
 
   root2 = ParseJSON(
       "{\r\n"
@@ -342,7 +342,7 @@
       "  \"S\":\"str\"\r\n"
       "}\r\n");
   ASSERT_TRUE(root2.get());
-  EXPECT_EQ(root->serialize().json, root2->serialize().json);
+  EXPECT_EQ(root->serializeToJSON(), root2->serializeToJSON());
 
   // Test nesting
   root = ParseJSON("{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}");
diff --git a/third_party/blink/renderer/core/inspector/v8_inspector_string.cc b/third_party/blink/renderer/core/inspector/v8_inspector_string.cc
index 78231f5..d05cd38 100644
--- a/third_party/blink/renderer/core/inspector/v8_inspector_string.cc
+++ b/third_party/blink/renderer/core/inspector/v8_inspector_string.cc
@@ -59,31 +59,20 @@
 }
 
 // static
-std::unique_ptr<protocol::Value> StringUtil::parseProtocolMessage(
-    const ProtocolMessage& message) {
-  return parseJSON(message.json);
-}
-
-// static
-ProtocolMessage StringUtil::toProtocolMessage(const Value& value) {
-  ProtocolMessage message;
-  message.json = value.toJSONString();
-  return message;
-}
-
-// static
-String StringUtil::jsonComponent(const ProtocolMessage& message) {
-  return message.json;
-}
-
-// static
-ProtocolMessage StringUtil::fromJsonComponent(const String& message) {
+ProtocolMessage StringUtil::jsonToMessage(const String& message) {
   ProtocolMessage result;
   result.json = message;
   return result;
 }
 
 // static
+ProtocolMessage StringUtil::binaryToMessage(std::vector<uint8_t> message) {
+  ProtocolMessage result;
+  result.binary = std::move(message);
+  return result;
+}
+
+// static
 void StringUtil::builderAppendQuotedString(StringBuilder& builder,
                                            const String& str) {
   builder.Append('"');
diff --git a/third_party/blink/renderer/core/inspector/v8_inspector_string.h b/third_party/blink/renderer/core/inspector/v8_inspector_string.h
index 3f68510c..4cdc312 100644
--- a/third_party/blink/renderer/core/inspector/v8_inspector_string.h
+++ b/third_party/blink/renderer/core/inspector/v8_inspector_string.h
@@ -17,6 +17,7 @@
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_to_number.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_view.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "v8/include/v8-inspector.h"
@@ -82,11 +83,16 @@
     return builder.ToString();
   }
   static std::unique_ptr<protocol::Value> parseJSON(const String&);
-  static std::unique_ptr<protocol::Value> parseProtocolMessage(
-      const ProtocolMessage&);
-  static ProtocolMessage toProtocolMessage(const Value& value);
-  static String jsonComponent(const ProtocolMessage& message);
-  static ProtocolMessage fromJsonComponent(const String& message);
+  static ProtocolMessage jsonToMessage(const String& message);
+  static ProtocolMessage binaryToMessage(std::vector<uint8_t> message);
+
+  static String fromUTF8(const uint8_t* data, size_t length) {
+    return String::FromUTF8(reinterpret_cast<const char*>(data), length);
+  }
+  static void writeUTF8(const String& string, std::vector<uint8_t>* out) {
+    StringUTF8Adaptor adaptor(string);
+    out->insert(out->end(), adaptor.Data(), adaptor.Data() + adaptor.length());
+  }
 };
 
 // A read-only sequence of uninterpreted bytes with reference-counted storage.
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
index 8cb06d3..9f66a53 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -1236,20 +1236,6 @@
   }
 }
 
-bool LayoutFlexibleBox::ChildLogicalHeightStretchesToFlexboxSize(
-    FlexItem& item) const {
-  if (IsMultiline())
-    return false;
-  if (!NeedToStretchChildLogicalHeight(*item.box))
-    return false;
-  if (HasAutoMarginsInCrossAxis(*item.box))
-    return false;
-  if (item.box->IntrinsicContentLogicalHeight() == -1)
-    return false;
-
-  return HasDefiniteLogicalHeight();
-}
-
 LayoutUnit LayoutFlexibleBox::StaticMainAxisPositionForPositionedChild(
     const LayoutBox& child) {
   const LayoutUnit available_space =
@@ -1408,35 +1394,6 @@
     child->SetShouldCheckForPaintInvalidation();
 
     SetOverrideMainAxisContentSizeForChild(flex_item);
-
-    // We may have already forced relayout for orthogonal flowing children in
-    // computeInnerFlexBaseSizeForChild.
-    bool force_child_relayout =
-        relayout_children && !relaid_out_children_.Contains(child);
-
-    // Apply optimization 1 from section 9.8 for row flexboxes by overriding
-    // the logical height of stretchable children to the parent's definite
-    // height, if present (https://crbug.com/703512).
-    if (ChildLogicalHeightStretchesToFlexboxSize(flex_item)) {
-      LogicalExtentComputedValues computed_values;
-      ComputeLogicalHeight(computed_values);
-      LayoutUnit cross_axis_extent = computed_values.extent_;
-      DCHECK_NE(cross_axis_extent, LayoutUnit(-1));
-
-      // Compute the maximum possible cross axis extent available, since we
-      // don't optimize for intrinsically sized children.
-      LayoutUnit stretched_logical_height =
-          std::max(child->BorderAndPaddingLogicalHeight(),
-                   cross_axis_extent - flex_item.CrossAxisMarginExtent());
-      LayoutUnit clamped_logical_height = child->ConstrainLogicalHeightByMinMax(
-          stretched_logical_height, child->IntrinsicContentLogicalHeight());
-
-      child->SetOverrideLogicalHeight(clamped_logical_height);
-      if (clamped_logical_height != child->LogicalHeight()) {
-        force_child_relayout = true;
-      }
-    }
-
     // The flexed content size and the override size include the scrollbar
     // width, so we need to compare to the size including the scrollbar.
     if (flex_item.flexed_content_size !=
@@ -1447,6 +1404,10 @@
       // updateAutoMarginsInCrossAxis, we reset the margins here.
       ResetAutoMarginsAndLogicalTopInCrossAxis(*child);
     }
+    // We may have already forced relayout for orthogonal flowing children in
+    // computeInnerFlexBaseSizeForChild.
+    bool force_child_relayout =
+        relayout_children && !relaid_out_children_.Contains(child);
     // TODO(dgrogan): Broaden the NG part of this check once NG types other
     // than Mixin derivatives are cached.
     if (child->IsLayoutBlock() &&
@@ -1655,7 +1616,7 @@
         flex_item.cross_axis_size != child.LogicalHeight();
     if (child.IsLayoutBlock() &&
         ToLayoutBlock(child).HasPercentHeightDescendants() &&
-        !CanAvoidLayoutForNGChild(child) && !child.HasOverrideLogicalHeight()) {
+        !CanAvoidLayoutForNGChild(child)) {
       // Have to force another relayout even though the child is sized
       // correctly, because its descendants are not sized correctly yet. Our
       // previous layout of the child was done without an override height set.
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.h b/third_party/blink/renderer/core/layout/layout_flexible_box.h
index 0d340bb..d1ad9b9 100644
--- a/third_party/blink/renderer/core/layout/layout_flexible_box.h
+++ b/third_party/blink/renderer/core/layout/layout_flexible_box.h
@@ -189,7 +189,6 @@
 
   void ResetAutoMarginsAndLogicalTopInCrossAxis(LayoutBox& child);
   void SetOverrideMainAxisContentSizeForChild(FlexItem&);
-  bool ChildLogicalHeightStretchesToFlexboxSize(FlexItem&) const;
   void PrepareChildForPositionedLayout(LayoutBox& child);
   void LayoutLineItems(FlexLine*, bool relayout_children, SubtreeLayoutScope&);
   void ApplyLineItemsPosition(FlexLine*);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index ab4f5ee..ad5b990 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -394,7 +394,7 @@
   border_scrollbar_padding_ += intrinsic_padding;
 
   if (ConstraintSpace().HasBlockFragmentation())
-    container_builder_.SetNeedsFinishedBreakToken();
+    container_builder_.SetHasBlockFragmentation();
   container_builder_.SetInlineSize(border_box_size.inline_size);
   container_builder_.SetBfcLineOffset(
       ConstraintSpace().BfcOffset().line_offset);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
index 5e6f59fb..42f6d12 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -81,6 +81,7 @@
 
 NGBoxFragmentBuilder& NGBoxFragmentBuilder::AddBreakBeforeChild(
     NGLayoutInputNode child) {
+  DCHECK(has_block_fragmentation_);
   if (child.IsInline()) {
     if (inline_break_tokens_.IsEmpty()) {
       // In some cases we may want to break before the first line, as a last
@@ -101,6 +102,7 @@
 
 NGBoxFragmentBuilder& NGBoxFragmentBuilder::AddBreakBeforeLine(
     int line_number) {
+  DCHECK(has_block_fragmentation_);
   DCHECK_GT(line_number, 0);
   DCHECK_LE(unsigned(line_number), inline_break_tokens_.size());
   int lines_to_remove = inline_break_tokens_.size() - line_number;
@@ -134,6 +136,8 @@
 
 NGBoxFragmentBuilder& NGBoxFragmentBuilder::PropagateBreak(
     const NGLayoutResult& child_layout_result) {
+  if (!has_block_fragmentation_)
+    return *this;
   if (!did_break_)
     PropagateBreak(*child_layout_result.PhysicalFragment());
   if (child_layout_result.HasForcedBreak())
@@ -145,6 +149,7 @@
 
 NGBoxFragmentBuilder& NGBoxFragmentBuilder::PropagateBreak(
     const NGPhysicalFragment& child_fragment) {
+  DCHECK(has_block_fragmentation_);
   if (!did_break_) {
     const auto* token = child_fragment.BreakToken();
     did_break_ = token && !token->IsFinished();
@@ -228,7 +233,7 @@
 
 scoped_refptr<NGLayoutResult> NGBoxFragmentBuilder::ToBoxFragment(
     WritingMode block_or_line_writing_mode) {
-  if (node_) {
+  if (node_ && has_block_fragmentation_) {
     if (!inline_break_tokens_.IsEmpty()) {
       if (auto token = inline_break_tokens_.back()) {
         if (!token->IsFinished())
@@ -238,7 +243,7 @@
     if (did_break_) {
       break_token_ = NGBlockBreakToken::Create(
           node_, used_block_size_, child_break_tokens_, has_last_resort_break_);
-    } else if (needs_finished_break_token_) {
+    } else {
       break_token_ = NGBlockBreakToken::Create(node_, used_block_size_,
                                                has_last_resort_break_);
     }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
index 7280a74..ffdf755 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -102,11 +102,6 @@
     return *this;
   }
 
-  NGBoxFragmentBuilder& SetNeedsFinishedBreakToken() {
-    needs_finished_break_token_ = true;
-    return *this;
-  }
-
   // Specify that we broke.
   //
   // This will result in a fragment which has an unfinished break token.
@@ -235,7 +230,6 @@
   NGPhysicalFragment::NGBoxType box_type_;
   bool is_fieldset_container_ = false;
   bool is_old_layout_root_;
-  bool needs_finished_break_token_ = false;
   bool did_break_;
   bool has_forced_break_ = false;
   bool is_new_fc_ = false;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_break_token.h b/third_party/blink/renderer/core/layout/ng/ng_break_token.h
index 62e4d49..da22a3b 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_break_token.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_break_token.h
@@ -100,7 +100,7 @@
   unsigned has_last_resort_break_ : 1;
 };
 
-typedef Vector<scoped_refptr<NGBreakToken>, 16> NGBreakTokenVector;
+typedef Vector<scoped_refptr<NGBreakToken>> NGBreakTokenVector;
 
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
index cccbaabe..800f0ad 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
@@ -199,22 +199,7 @@
   }
 
   LayoutUnit ReplacedPercentageResolutionInlineSize() const {
-    switch (static_cast<NGPercentageStorage>(
-        bitfields_.replaced_percentage_inline_storage)) {
-      case kSameAsAvailable:
-        return available_size_.inline_size;
-      case kZero:
-        return LayoutUnit();
-      case kIndefinite:
-        return NGSizeIndefinite;
-      case kRareDataPercentage:
-        DCHECK(HasRareData());
-        return rare_data_->replaced_percentage_resolution_size.inline_size;
-      default:
-        NOTREACHED();
-    }
-
-    return available_size_.inline_size;
+    return PercentageResolutionInlineSize();
   }
 
   LayoutUnit ReplacedPercentageResolutionBlockSize() const {
@@ -228,7 +213,7 @@
         return NGSizeIndefinite;
       case kRareDataPercentage:
         DCHECK(HasRareData());
-        return rare_data_->replaced_percentage_resolution_size.block_size;
+        return rare_data_->replaced_percentage_resolution_block_size;
       default:
         NOTREACHED();
     }
@@ -488,18 +473,11 @@
             other.rare_data_->percentage_resolution_size.block_size)
       return false;
 
-    if (bitfields_.replaced_percentage_inline_storage == kRareDataPercentage &&
-        other.bitfields_.replaced_percentage_inline_storage ==
-            kRareDataPercentage &&
-        rare_data_->replaced_percentage_resolution_size.inline_size !=
-            other.rare_data_->replaced_percentage_resolution_size.inline_size)
-      return false;
-
     if (bitfields_.replaced_percentage_block_storage == kRareDataPercentage &&
         other.bitfields_.replaced_percentage_block_storage ==
             kRareDataPercentage &&
-        rare_data_->replaced_percentage_resolution_size.block_size !=
-            other.rare_data_->replaced_percentage_resolution_size.block_size)
+        rare_data_->replaced_percentage_resolution_block_size !=
+            other.rare_data_->replaced_percentage_resolution_block_size)
       return false;
 
     return true;
@@ -539,7 +517,7 @@
     ~RareData() = default;
 
     NGLogicalSize percentage_resolution_size;
-    NGLogicalSize replaced_percentage_resolution_size;
+    LayoutUnit replaced_percentage_resolution_block_size;
 
     NGBfcOffset bfc_offset;
     NGMarginStrut margin_strut;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc
index 25f6b5b8..23eed90 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc
@@ -78,41 +78,33 @@
   DCHECK(is_available_size_set_);
 #endif
   if (LIKELY(is_in_parallel_flow_)) {
-    space_.bitfields_.replaced_percentage_inline_storage =
-        GetPercentageStorage(replaced_percentage_resolution_size.inline_size,
-                             space_.available_size_.inline_size);
-    if (UNLIKELY(space_.bitfields_.replaced_percentage_inline_storage ==
-                 kRareDataPercentage)) {
-      space_.EnsureRareData()->replaced_percentage_resolution_size.inline_size =
-          replaced_percentage_resolution_size.inline_size;
-    }
+    // We don't store the replaced percentage resolution inline size, so we need
+    // it to be the same as the regular percentage resolution inline size.
+    DCHECK_EQ(replaced_percentage_resolution_size.inline_size,
+              space_.PercentageResolutionInlineSize());
 
     space_.bitfields_.replaced_percentage_block_storage =
         GetPercentageStorage(replaced_percentage_resolution_size.block_size,
                              space_.available_size_.block_size);
     if (space_.bitfields_.replaced_percentage_block_storage ==
         kRareDataPercentage) {
-      space_.EnsureRareData()->replaced_percentage_resolution_size.block_size =
+      space_.EnsureRareData()->replaced_percentage_resolution_block_size =
           replaced_percentage_resolution_size.block_size;
     }
   } else {
     AdjustInlineSizeIfNeeded(&replaced_percentage_resolution_size.block_size);
 
-    space_.bitfields_.replaced_percentage_inline_storage =
-        GetPercentageStorage(replaced_percentage_resolution_size.block_size,
-                             space_.available_size_.inline_size);
-    if (space_.bitfields_.replaced_percentage_inline_storage ==
-        kRareDataPercentage) {
-      space_.EnsureRareData()->replaced_percentage_resolution_size.inline_size =
-          replaced_percentage_resolution_size.block_size;
-    }
+    // We don't store the replaced percentage resolution inline size, so we need
+    // it to be the same as the regular percentage resolution inline size.
+    DCHECK_EQ(replaced_percentage_resolution_size.block_size,
+              space_.PercentageResolutionInlineSize());
 
     space_.bitfields_.replaced_percentage_block_storage =
         GetPercentageStorage(replaced_percentage_resolution_size.inline_size,
                              space_.available_size_.block_size);
     if (space_.bitfields_.replaced_percentage_block_storage ==
         kRareDataPercentage) {
-      space_.EnsureRareData()->replaced_percentage_resolution_size.block_size =
+      space_.EnsureRareData()->replaced_percentage_resolution_block_size =
           replaced_percentage_resolution_size.inline_size;
     }
   }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
index 9c35f94..1831b7b 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
@@ -70,10 +70,12 @@
     scoped_refptr<const NGPhysicalFragment> child,
     const NGLogicalOffset& child_offset) {
   NGBreakToken* child_break_token = child->BreakToken();
-  if (child_break_token) {
+  if (child_break_token && has_block_fragmentation_) {
     switch (child->Type()) {
       case NGPhysicalFragment::kFragmentBox:
       case NGPhysicalFragment::kFragmentRenderedLegend:
+        if (ToNGBlockBreakToken(child_break_token)->HasLastResortBreak())
+          has_last_resort_break_ = true;
         child_break_tokens_.push_back(child_break_token);
         break;
       case NGPhysicalFragment::kFragmentLineBox:
@@ -97,13 +99,6 @@
   if (child->IsOldLayoutRoot())
     has_depends_on_percentage_block_size_child_ = true;
 
-  if (!has_last_resort_break_) {
-    if (const auto* token = child->BreakToken()) {
-      if (token->IsBlockType() &&
-          ToNGBlockBreakToken(token)->HasLastResortBreak())
-        has_last_resort_break_ = true;
-    }
-  }
   children_.emplace_back(std::move(child));
   offsets_.push_back(child_offset);
   return *this;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
index 4439244..4835030 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
@@ -159,6 +159,11 @@
   }
   NGFloatTypes AdjoiningFloatTypes() const { return adjoining_floats_; }
 
+  NGContainerFragmentBuilder& SetHasBlockFragmentation() {
+    has_block_fragmentation_ = true;
+    return *this;
+  }
+
 #ifndef NDEBUG
   String ToString() const;
 #endif
@@ -230,6 +235,7 @@
 
   bool has_orthogonal_flow_roots_ = false;
   bool has_depends_on_percentage_block_size_child_ = false;
+  bool has_block_fragmentation_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
index aebd90f..ae3c3bdc 100644
--- a/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
+++ b/third_party/blink/renderer/core/paint/pre_paint_tree_walk.cc
@@ -365,14 +365,18 @@
       }
 
       if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-        const auto* paint_invalidation_layer =
-            paint_invalidator_context.paint_invalidation_container->Layer();
-        if (!paint_invalidation_layer->NeedsRepaint()) {
-          auto* mapping = paint_invalidation_layer->GetCompositedLayerMapping();
-          if (!mapping)
-            mapping = paint_invalidation_layer->GroupedMapping();
-          if (mapping)
-            mapping->SetNeedsCheckRasterInvalidation();
+        if (property_changed >
+            PaintPropertyChangedState::kChangedOnlyDueToAnimations) {
+          const auto* paint_invalidation_layer =
+              paint_invalidator_context.paint_invalidation_container->Layer();
+          if (!paint_invalidation_layer->NeedsRepaint()) {
+            auto* mapping =
+                paint_invalidation_layer->GetCompositedLayerMapping();
+            if (!mapping)
+              mapping = paint_invalidation_layer->GroupedMapping();
+            if (mapping)
+              mapping->SetNeedsCheckRasterInvalidation();
+          }
         }
       } else if (!context.tree_builder_context
                       ->supports_composited_raster_invalidation) {
diff --git a/third_party/blink/renderer/core/script/BUILD.gn b/third_party/blink/renderer/core/script/BUILD.gn
index d552200..3eecb063c 100644
--- a/third_party/blink/renderer/core/script/BUILD.gn
+++ b/third_party/blink/renderer/core/script/BUILD.gn
@@ -24,6 +24,8 @@
     "html_parser_script_runner.h",
     "html_parser_script_runner_host.h",
     "ignore_destructive_write_count_incrementer.h",
+    "import_map.cc",
+    "import_map.h",
     "layered_api.cc",
     "layered_api.h",
     "layered_api_resources.h",
diff --git a/third_party/blink/renderer/core/script/import_map.cc b/third_party/blink/renderer/core/script/import_map.cc
new file mode 100644
index 0000000..4f9da28
--- /dev/null
+++ b/third_party/blink/renderer/core/script/import_map.cc
@@ -0,0 +1,239 @@
+// 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/core/script/import_map.h"
+
+#include <memory>
+#include <utility>
+#include "third_party/blink/renderer/core/script/layered_api.h"
+#include "third_party/blink/renderer/core/script/parsed_specifier.h"
+#include "third_party/blink/renderer/platform/json/json_parser.h"
+#include "third_party/blink/renderer/platform/json/json_values.h"
+#include "third_party/blink/renderer/platform/loader/fetch/console_logger.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+
+namespace blink {
+
+namespace {
+
+// TODO(https://crbug.com/928549): Audit and improve error messages throughout
+// this file.
+
+void AddIgnoredKeyMessage(ConsoleLogger& logger,
+                          const String& key,
+                          const String& reason) {
+  logger.AddWarningMessage(
+      ConsoleLogger::Source::kOther,
+      "Ignored an import map key \"" + key + "\": " + reason);
+}
+
+void AddIgnoredValueMessage(ConsoleLogger& logger,
+                            const String& key,
+                            const String& reason) {
+  logger.AddWarningMessage(
+      ConsoleLogger::Source::kOther,
+      "Ignored an import map value of \"" + key + "\": " + reason);
+}
+
+// GetKey() and GetValue() returns null String/KURL if the given ParsedSpecifier
+// is not valid as keys/values of import maps.
+String GetKey(const String& key_string,
+              const KURL& base_url,
+              ConsoleLogger& logger) {
+  ParsedSpecifier key = ParsedSpecifier::Create(key_string, base_url);
+  switch (key.GetType()) {
+    case ParsedSpecifier::Type::kInvalid:
+      AddIgnoredKeyMessage(logger, key_string, "Invalid key (invalid URL)");
+      return String();
+
+    case ParsedSpecifier::Type::kBare:
+      return key.GetImportMapKeyString();
+
+    case ParsedSpecifier::Type::kURL:
+      return key.GetImportMapKeyString();
+  }
+}
+
+KURL GetValue(const String& key,
+              const String& value_string,
+              const KURL& base_url,
+              ConsoleLogger& logger) {
+  ParsedSpecifier value = ParsedSpecifier::Create(value_string, base_url);
+  switch (value.GetType()) {
+    case ParsedSpecifier::Type::kInvalid:
+      AddIgnoredValueMessage(logger, key, "Invalid URL: " + value_string);
+      return NullURL();
+
+    case ParsedSpecifier::Type::kBare:
+      if (value.GetImportMapKeyString().StartsWith("@std/"))
+        return KURL("import:" + value.GetImportMapKeyString());
+
+      // Do not allow bare specifiers except for @std/.
+      AddIgnoredValueMessage(logger, key, "Bare specifier: " + value_string);
+      return NullURL();
+
+    case ParsedSpecifier::Type::kURL:
+      return value.GetUrl();
+  }
+}
+
+}  // namespace
+
+// Parse |text| as an import map.
+// Errors (e.g. json parsing error, invalid keys/values, etc.) are basically
+// ignored, except that they are reported to the console |logger|.
+// TODO(hiroshige): Handle errors in a spec-conformant way once specified.
+// https://github.com/WICG/import-maps/issues/100
+ImportMap* ImportMap::Create(const String& text,
+                             const KURL& base_url,
+                             ConsoleLogger& logger) {
+  HashMap<String, Vector<KURL>> modules_map;
+
+  std::unique_ptr<JSONValue> root = ParseJSON(text);
+  if (!root) {
+    logger.AddErrorMessage(ConsoleLogger::Source::kOther,
+                           "Failed to parse import map: invalid JSON");
+    return MakeGarbageCollected<ImportMap>(modules_map);
+  }
+
+  std::unique_ptr<JSONObject> root_object = JSONObject::From(std::move(root));
+  if (!root_object) {
+    logger.AddErrorMessage(ConsoleLogger::Source::kOther,
+                           "Failed to parse import map: not an object");
+    return MakeGarbageCollected<ImportMap>(modules_map);
+  }
+
+  JSONObject* modules = root_object->GetJSONObject("imports");
+  if (!modules) {
+    logger.AddErrorMessage(ConsoleLogger::Source::kOther,
+                           "Failed to parse import map: no \"imports\" entry.");
+    return MakeGarbageCollected<ImportMap>(modules_map);
+  }
+
+  for (wtf_size_t i = 0; i < modules->size(); ++i) {
+    const JSONObject::Entry& entry = modules->at(i);
+
+    const String key = GetKey(entry.first, base_url, logger);
+    if (key.IsEmpty())
+      continue;
+
+    Vector<KURL> values;
+    switch (entry.second->GetType()) {
+      case JSONValue::ValueType::kTypeNull:
+        break;
+
+      case JSONValue::ValueType::kTypeBoolean:
+      case JSONValue::ValueType::kTypeInteger:
+      case JSONValue::ValueType::kTypeDouble:
+      case JSONValue::ValueType::kTypeObject:
+        AddIgnoredValueMessage(logger, entry.first, "Invalid value type.");
+        break;
+
+      case JSONValue::ValueType::kTypeString: {
+        String value_string;
+        if (!modules->GetString(entry.first, &value_string)) {
+          AddIgnoredValueMessage(logger, entry.first,
+                                 "Internal error in GetString().");
+          break;
+        }
+        KURL value = GetValue(entry.first, value_string, base_url, logger);
+        if (value.IsValid())
+          values.push_back(value);
+        break;
+      }
+
+      case JSONValue::ValueType::kTypeArray: {
+        JSONArray* array = modules->GetArray(entry.first);
+        if (!array) {
+          AddIgnoredValueMessage(logger, entry.first,
+                                 "Internal error in GetArray().");
+          break;
+        }
+
+        for (wtf_size_t j = 0; j < array->size(); ++j) {
+          String value_string;
+          if (!array->at(j)->AsString(&value_string)) {
+            AddIgnoredValueMessage(logger, entry.first,
+                                   "Non-string in the value.");
+            continue;
+          }
+          KURL value = GetValue(entry.first, value_string, base_url, logger);
+          if (value.IsValid())
+            values.push_back(value);
+        }
+        break;
+      }
+    }
+
+    if (values.size() > 2) {
+      AddIgnoredValueMessage(logger, entry.first,
+                             "An array of length > 2 is not yet supported.");
+      values.clear();
+    }
+    if (values.size() == 2) {
+      if (blink::layered_api::GetBuiltinPath(values[0]).IsNull()) {
+        AddIgnoredValueMessage(
+            logger, entry.first,
+            "Fallback from a non-builtin URL is not yet supported.");
+        values.clear();
+      } else if (key != values[1]) {
+        AddIgnoredValueMessage(logger, entry.first,
+                               "Fallback URL should match the original URL.");
+        values.clear();
+      }
+    }
+
+    modules_map.Set(key, values);
+  }
+
+  // TODO(crbug.com/927181): Process "scopes" entry.
+
+  return MakeGarbageCollected<ImportMap>(modules_map);
+}
+
+base::Optional<KURL> ImportMap::Resolve(const ParsedSpecifier& parsed_specifier,
+                                        String* debug_message) const {
+  DCHECK(debug_message);
+  const String key = parsed_specifier.GetImportMapKeyString();
+  auto it = imports_.find(key);
+  if (it == imports_.end()) {
+    *debug_message = "Import Map: \"" + key +
+                     "\" matches with no entries and thus is not mapped.";
+    return base::nullopt;
+  }
+
+  for (const auto& candidate_url : it->value) {
+    if (blink::layered_api::ResolveFetchingURL(candidate_url).IsValid()) {
+      *debug_message = "Import Map: \"" + key + "\" matches with \"" + it->key +
+                       "\" and is mapped to " + candidate_url.ElidedString();
+      return candidate_url;
+    }
+  }
+
+  *debug_message = "Import Map: \"" + key + "\" matches with \"" + it->key +
+                   "\" but fails to be mapped (no viable URLs)";
+  return NullURL();
+}
+
+String ImportMap::ToString() const {
+  StringBuilder builder;
+  builder.Append("{\n");
+  for (const auto& it : imports_) {
+    builder.Append("  \"");
+    builder.Append(it.key);
+    builder.Append("\": [\n");
+    for (const auto& v : it.value) {
+      builder.Append("    \"");
+      builder.Append(v.GetString());
+      builder.Append("\",\n");
+    }
+    builder.Append("  ]\n");
+  }
+  builder.Append("}\n");
+  return builder.ToString();
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/script/import_map.h b/third_party/blink/renderer/core/script/import_map.h
new file mode 100644
index 0000000..040b332a
--- /dev/null
+++ b/third_party/blink/renderer/core/script/import_map.h
@@ -0,0 +1,48 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_IMPORT_MAP_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_SCRIPT_IMPORT_MAP_H_
+
+#include "base/macros.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl_hash.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
+
+namespace blink {
+
+class ConsoleLogger;
+class ParsedSpecifier;
+
+// Import maps.
+// https://wicg.github.io/import-maps/
+// https://github.com/WICG/import-maps/blob/master/spec.md
+class ImportMap final : public GarbageCollectedFinalized<ImportMap> {
+ public:
+  static ImportMap* Create(const String& text,
+                           const KURL& base_url,
+                           ConsoleLogger& logger);
+
+  explicit ImportMap(const HashMap<String, Vector<KURL>>& imports)
+      : imports_(imports) {}
+
+  // Returns nullopt when not mapped by |this| import map (i.e. the import map
+  // doesn't have corresponding keys).
+  // Returns a null URL when resolution fails.
+  base::Optional<KURL> Resolve(const ParsedSpecifier&,
+                               String* debug_message) const;
+
+  String ToString() const;
+
+  void Trace(Visitor*) {}
+
+ private:
+  HashMap<String, Vector<KURL>> imports_;
+};
+
+}  // namespace blink
+
+#endif
diff --git a/third_party/blink/renderer/core/script/modulator.h b/third_party/blink/renderer/core/script/modulator.h
index 2926e97..b24393c 100644
--- a/third_party/blink/renderer/core/script/modulator.h
+++ b/third_party/blink/renderer/core/script/modulator.h
@@ -26,6 +26,7 @@
 class ModuleScript;
 class ModuleScriptFetchRequest;
 class ModuleScriptFetcher;
+class ImportMap;
 class ReferrerScriptInfo;
 class ResourceFetcher;
 class ScriptModuleResolver;
@@ -165,6 +166,9 @@
                                   const ReferrerScriptInfo&,
                                   ScriptPromiseResolver*) = 0;
 
+  // Import maps. https://github.com/WICG/import-maps
+  virtual void RegisterImportMap(const ImportMap*) = 0;
+
   // https://html.spec.whatwg.org/C/#hostgetimportmetaproperties
   virtual ModuleImportMeta HostGetImportMetaProperties(ScriptModule) const = 0;
 
diff --git a/third_party/blink/renderer/core/script/modulator_impl_base.cc b/third_party/blink/renderer/core/script/modulator_impl_base.cc
index f7f975c..ad130f7 100644
--- a/third_party/blink/renderer/core/script/modulator_impl_base.cc
+++ b/third_party/blink/renderer/core/script/modulator_impl_base.cc
@@ -12,7 +12,7 @@
 #include "third_party/blink/renderer/core/loader/modulescript/module_tree_linker.h"
 #include "third_party/blink/renderer/core/loader/modulescript/module_tree_linker_registry.h"
 #include "third_party/blink/renderer/core/script/dynamic_module_resolver.h"
-#include "third_party/blink/renderer/core/script/layered_api.h"
+#include "third_party/blink/renderer/core/script/import_map.h"
 #include "third_party/blink/renderer/core/script/module_map.h"
 #include "third_party/blink/renderer/core/script/module_script.h"
 #include "third_party/blink/renderer/core/script/parsed_specifier.h"
@@ -123,6 +123,37 @@
     return KURL();
   }
 
+  // If |logger| is non-null, outputs detailed logs.
+  // The detailed log should be useful for debugging particular import maps
+  // errors, but should be supressed (i.e. |logger| should be null) in normal
+  // cases.
+
+  base::Optional<KURL> mapped_url;
+  if (import_map_) {
+    String import_map_debug_message;
+    mapped_url =
+        import_map_->Resolve(parsed_specifier, &import_map_debug_message);
+
+    // Output the resolution log. This is too verbose to be always shown, but
+    // will be helpful for Web developers (and also Chromium developers) for
+    // debugging import maps.
+    LOG(INFO) << import_map_debug_message;
+
+    if (mapped_url) {
+      KURL url = *mapped_url;
+      if (!url.IsValid()) {
+        if (failure_reason)
+          *failure_reason = import_map_debug_message;
+        return KURL();
+      }
+      return url;
+    }
+  }
+
+  // The specifier is not mapped by import maps, either because
+  // - There are no import maps, or
+  // - The import map doesn't have an entry for |parsed_specifier|.
+
   switch (parsed_specifier.GetType()) {
     case ParsedSpecifier::Type::kInvalid:
       NOTREACHED();
@@ -149,6 +180,25 @@
   }
 }
 
+void ModulatorImplBase::RegisterImportMap(const ImportMap* import_map) {
+  if (import_map_) {
+    // Only one import map is allowed.
+    // TODO(crbug.com/927119): Implement merging.
+    GetExecutionContext()->AddErrorMessage(
+        ConsoleLogger::Source::kOther,
+        "Multiple import maps are not yet supported. https://crbug.com/927119");
+    return;
+  }
+
+  if (!RuntimeEnabledFeatures::LayeredAPIEnabled()) {
+    GetExecutionContext()->AddErrorMessage(
+        ConsoleLogger::Source::kOther,
+        "Import maps are disabled when LayeredAPI is disabled.");
+    return;
+  }
+  import_map_ = import_map;
+}
+
 bool ModulatorImplBase::HasValidContext() {
   return script_state_->ContextIsValid();
 }
@@ -279,6 +329,7 @@
   visitor->Trace(tree_linker_registry_);
   visitor->Trace(script_module_resolver_);
   visitor->Trace(dynamic_module_resolver_);
+  visitor->Trace(import_map_);
 
   Modulator::Trace(visitor);
 }
diff --git a/third_party/blink/renderer/core/script/modulator_impl_base.h b/third_party/blink/renderer/core/script/modulator_impl_base.h
index 8a71af5..ba84721 100644
--- a/third_party/blink/renderer/core/script/modulator_impl_base.h
+++ b/third_party/blink/renderer/core/script/modulator_impl_base.h
@@ -74,6 +74,7 @@
                           const KURL&,
                           const ReferrerScriptInfo&,
                           ScriptPromiseResolver*) override;
+  void RegisterImportMap(const ImportMap*) final;
   ModuleImportMeta HostGetImportMetaProperties(ScriptModule) const override;
   ScriptValue InstantiateModule(ScriptModule) override;
   Vector<ModuleRequest> ModuleRequestsFromScriptModule(ScriptModule) override;
@@ -92,6 +93,7 @@
   TraceWrapperMember<ModuleTreeLinkerRegistry> tree_linker_registry_;
   Member<ScriptModuleResolver> script_module_resolver_;
   Member<DynamicModuleResolver> dynamic_module_resolver_;
+  Member<const ImportMap> import_map_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/script/script_loader.cc b/third_party/blink/renderer/core/script/script_loader.cc
index 2bd15a1..670dc15e 100644
--- a/third_party/blink/renderer/core/script/script_loader.cc
+++ b/third_party/blink/renderer/core/script/script_loader.cc
@@ -43,6 +43,7 @@
 #include "third_party/blink/renderer/core/loader/subresource_integrity_helper.h"
 #include "third_party/blink/renderer/core/script/classic_pending_script.h"
 #include "third_party/blink/renderer/core/script/classic_script.h"
+#include "third_party/blink/renderer/core/script/import_map.h"
 #include "third_party/blink/renderer/core/script/modulator.h"
 #include "third_party/blink/renderer/core/script/module_pending_script.h"
 #include "third_party/blink/renderer/core/script/script.h"
@@ -164,6 +165,34 @@
   return false;
 }
 
+// Returns true on success.
+bool ParseAndRegisterImportMap(ScriptElementBase& element) {
+  Document& element_document = element.GetDocument();
+  Document* context_document = element_document.ContextDocument();
+  DCHECK(context_document);
+  Modulator* modulator =
+      Modulator::From(ToScriptStateForMainWorld(context_document->GetFrame()));
+  DCHECK(modulator);
+
+  // TODO(crbug.com/922212): Implemenet external import maps.
+  if (element.HasSourceAttribute()) {
+    element_document.AddConsoleMessage(
+        ConsoleMessage::Create(kJSMessageSource, kErrorMessageLevel,
+                               "External import maps are not yet supported."));
+    return false;
+  }
+
+  KURL base_url = element_document.BaseURL();
+  ImportMap* import_map =
+      ImportMap::Create(element.TextFromChildren(), base_url, element_document);
+
+  if (!import_map)
+    return false;
+
+  modulator->RegisterImportMap(import_map);
+  return true;
+}
+
 }  // namespace
 
 // <specdef href="https://html.spec.whatwg.org/C/#prepare-a-script">
@@ -171,14 +200,18 @@
     const String& type,
     const String& language,
     LegacyTypeSupport support_legacy_types,
-    mojom::ScriptType& out_script_type) {
+    mojom::ScriptType* out_script_type,
+    bool* out_is_import_map) {
   if (IsValidClassicScriptTypeAndLanguage(type, language,
                                           support_legacy_types)) {
     // <spec step="7">... If the script block's type string is a JavaScript MIME
     // type essence match, the script's type is "classic". ...</spec>
     //
     // TODO(hiroshige): Annotate and/or cleanup this step.
-    out_script_type = mojom::ScriptType::kClassic;
+    if (out_script_type)
+      *out_script_type = mojom::ScriptType::kClassic;
+    if (out_is_import_map)
+      *out_is_import_map = false;
     return true;
   }
 
@@ -186,7 +219,16 @@
     // <spec step="7">... If the script block's type string is an ASCII
     // case-insensitive match for the string "module", the script's type is
     // "module". ...</spec>
-    out_script_type = mojom::ScriptType::kModule;
+    if (out_script_type)
+      *out_script_type = mojom::ScriptType::kModule;
+    if (out_is_import_map)
+      *out_is_import_map = false;
+    return true;
+  }
+
+  if (RuntimeEnabledFeatures::LayeredAPIEnabled() && type == "importmap") {
+    if (out_is_import_map)
+      *out_is_import_map = true;
     return true;
   }
 
@@ -277,13 +319,14 @@
   if (!element_->IsConnected())
     return false;
 
+  bool is_import_map = false;
+
   // <spec step="7">... Determine the script's type as follows: ...</spec>
   //
   // |script_type_| is set here.
-
-  if (!IsValidScriptTypeAndLanguage(element_->TypeAttributeValue(),
-                                    element_->LanguageAttributeValue(),
-                                    support_legacy_types, script_type_)) {
+  if (!IsValidScriptTypeAndLanguage(
+          element_->TypeAttributeValue(), element_->LanguageAttributeValue(),
+          support_legacy_types, &script_type_, &is_import_map)) {
     return false;
   }
 
@@ -333,6 +376,17 @@
   if (!IsScriptForEventSupported())
     return false;
 
+  // Process the import map.
+  if (is_import_map) {
+    if (!ParseAndRegisterImportMap(*element_)) {
+      element_document.GetTaskRunner(TaskType::kDOMManipulation)
+          ->PostTask(FROM_HERE,
+                     WTF::Bind(&ScriptElementBase::DispatchErrorEvent,
+                               WrapPersistent(element_.Get())));
+    }
+    return false;
+  }
+
   // This FeaturePolicy is still in the process of being added to the spec.
   if (ShouldBlockSyncScriptForFeaturePolicy(element_.Get(), GetScriptType(),
                                             parser_inserted_)) {
diff --git a/third_party/blink/renderer/core/script/script_loader.h b/third_party/blink/renderer/core/script/script_loader.h
index 71607bb..612174f 100644
--- a/third_party/blink/renderer/core/script/script_loader.h
+++ b/third_party/blink/renderer/core/script/script_loader.h
@@ -71,11 +71,18 @@
     kDisallowLegacyTypeInTypeAttribute,
     kAllowLegacyTypeInTypeAttribute
   };
+
+  // |out_is_import_map| is set separately from |out_script_type| in order
+  // to avoid adding import maps as a mojom::ScriptType enum, because import
+  // maps are processed quite differently from classic/module scripts.
+  //
+  // TODO(hiroshige, kouhei): Make the method signature simpler.
   static bool IsValidScriptTypeAndLanguage(
       const String& type_attribute_value,
       const String& language_attribute_value,
       LegacyTypeSupport support_legacy_types,
-      mojom::ScriptType& out_script_type);
+      mojom::ScriptType* out_script_type = nullptr,
+      bool* out_is_import_map = nullptr);
 
   static bool BlockForNoModule(mojom::ScriptType, bool nomodule);
 
diff --git a/third_party/blink/renderer/core/testing/dummy_modulator.cc b/third_party/blink/renderer/core/testing/dummy_modulator.cc
index 53b6ce3..ff98353e 100644
--- a/third_party/blink/renderer/core/testing/dummy_modulator.cc
+++ b/third_party/blink/renderer/core/testing/dummy_modulator.cc
@@ -110,6 +110,10 @@
   NOTREACHED();
 }
 
+void DummyModulator::RegisterImportMap(const ImportMap*) {
+  NOTREACHED();
+}
+
 ModuleImportMeta DummyModulator::HostGetImportMetaProperties(
     ScriptModule) const {
   NOTREACHED();
diff --git a/third_party/blink/renderer/core/testing/dummy_modulator.h b/third_party/blink/renderer/core/testing/dummy_modulator.h
index de1a0c9..9e1f4ba 100644
--- a/third_party/blink/renderer/core/testing/dummy_modulator.h
+++ b/third_party/blink/renderer/core/testing/dummy_modulator.h
@@ -56,6 +56,7 @@
                           const KURL&,
                           const ReferrerScriptInfo&,
                           ScriptPromiseResolver*) override;
+  void RegisterImportMap(const ImportMap*) override;
   ModuleImportMeta HostGetImportMetaProperties(ScriptModule) const override;
   ScriptValue InstantiateModule(ScriptModule) override;
   Vector<ModuleRequest> ModuleRequestsFromScriptModule(ScriptModule) override;
diff --git a/third_party/blink/renderer/modules/payments/payment_request.cc b/third_party/blink/renderer/modules/payments/payment_request.cc
index 924033a..49bedb1 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -806,19 +806,19 @@
 PaymentRequest::~PaymentRequest() = default;
 
 ScriptPromise PaymentRequest::show(ScriptState* script_state) {
+  if (!script_state->ContextIsValid() || !LocalDOMWindow::From(script_state) ||
+      !LocalDOMWindow::From(script_state)->GetFrame()) {
+    return ScriptPromise::RejectWithDOMException(
+        script_state, DOMException::Create(DOMExceptionCode::kAbortError,
+                                           "Cannot show the payment request"));
+  }
+
   if (!payment_provider_.is_bound() || accept_resolver_) {
     return ScriptPromise::RejectWithDOMException(
         script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError,
                                            "Already called show() once"));
   }
 
-  if (!script_state->ContextIsValid() || !LocalDOMWindow::From(script_state) ||
-      !LocalDOMWindow::From(script_state)->GetFrame()) {
-    return ScriptPromise::RejectWithDOMException(
-        script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError,
-                                           "Cannot show the payment request"));
-  }
-
   // TODO(crbug.com/825270): Reject with SecurityError DOMException if triggered
   // without user activation.
   bool is_user_gesture = LocalFrame::HasTransientUserActivation(GetFrame());
diff --git a/third_party/blink/renderer/platform/data_resource_helper.cc b/third_party/blink/renderer/platform/data_resource_helper.cc
index 34966144..3e2ada1 100644
--- a/third_party/blink/renderer/platform/data_resource_helper.cc
+++ b/third_party/blink/renderer/platform/data_resource_helper.cc
@@ -42,7 +42,7 @@
 
 String GetResourceAsString(int resource_id) {
   return String::FromUTF8(GetResourceById(resource_id).c_str());
-};
+}
 
 String UncompressResourceAsString(int resource_id) {
   std::string uncompressed;
diff --git a/third_party/blink/renderer/platform/exported/web_http_header_map.cc b/third_party/blink/renderer/platform/exported/web_http_header_map.cc
index c869bb3e..ec52eff3 100644
--- a/third_party/blink/renderer/platform/exported/web_http_header_map.cc
+++ b/third_party/blink/renderer/platform/exported/web_http_header_map.cc
@@ -16,7 +16,7 @@
 
 class WebHTTPHeaderMap::WebHTTPHeaderMapImpl {
  public:
-  explicit WebHTTPHeaderMapImpl(const HTTPHeaderMap& map) : map_(map){};
+  explicit WebHTTPHeaderMapImpl(const HTTPHeaderMap& map) : map_(map) {}
 
   explicit WebHTTPHeaderMapImpl(const net::HttpRequestHeaders* headers) {
     for (net::HttpRequestHeaders::Iterator it(*headers); it.GetNext();) {
@@ -24,7 +24,7 @@
           WTF::AtomicString::FromUTF8(it.name().c_str(), it.name().length()),
           WTF::AtomicString::FromUTF8(it.value().c_str(), it.value().length()));
     }
-  };
+  }
 
   explicit WebHTTPHeaderMapImpl(const net::HttpResponseHeaders* headers) {
     size_t iter = 0;
@@ -42,16 +42,15 @@
       else
         map_.Add(atomic_name, atomic_value);
     }
-  };
+  }
 
-  const HTTPHeaderMap& map() const { return map_; };
+  const HTTPHeaderMap& map() const { return map_; }
 
  private:
   HTTPHeaderMap map_;
 };
 
 WebHTTPHeaderMap::~WebHTTPHeaderMap() = default;
-;
 
 WebHTTPHeaderMap::WebHTTPHeaderMap(const HTTPHeaderMap& map) {
   implementation_ = std::make_unique<WebHTTPHeaderMapImpl>(map);
diff --git a/third_party/blink/renderer/platform/fonts/font.cc b/third_party/blink/renderer/platform/fonts/font.cc
index 804dc25..8a99744 100644
--- a/third_party/blink/renderer/platform/fonts/font.cc
+++ b/third_party/blink/renderer/platform/fonts/font.cc
@@ -400,7 +400,7 @@
     shape_word_by_word_computed_ = true;
   }
   return can_shape_word_by_word_;
-};
+}
 
 bool Font::ComputeCanShapeWordByWord() const {
   if (!GetFontDescription().GetTypesettingFeatures())
@@ -412,7 +412,7 @@
   const FontPlatformData& platform_data = PrimaryFont()->PlatformData();
   TypesettingFeatures features = GetFontDescription().GetTypesettingFeatures();
   return !platform_data.HasSpaceInLigaturesOrKerning(features);
-};
+}
 
 void Font::ReportNotDefGlyph() const {
   FontSelector* fontSelector = font_fallback_list_->GetFontSelector();
diff --git a/third_party/blink/renderer/platform/fonts/font_fallback_iterator.h b/third_party/blink/renderer/platform/fonts/font_fallback_iterator.h
index 7ea449a..19ffa28 100644
--- a/third_party/blink/renderer/platform/fonts/font_fallback_iterator.h
+++ b/third_party/blink/renderer/platform/fonts/font_fallback_iterator.h
@@ -27,7 +27,7 @@
                                              scoped_refptr<FontFallbackList>,
                                              FontFallbackPriority);
 
-  bool HasNext() const { return fallback_stage_ != kOutOfLuck; };
+  bool HasNext() const { return fallback_stage_ != kOutOfLuck; }
   // Returns whether the next call to Next() needs a full hint list, or whether
   // a single character is sufficient. Intended to serve as an optimization in
   // HarfBuzzShaper to avoid spending too much time and resources collecting a
diff --git a/third_party/blink/renderer/platform/fonts/font_fallback_priority.cc b/third_party/blink/renderer/platform/fonts/font_fallback_priority.cc
index 5310cde..b8c6544 100644
--- a/third_party/blink/renderer/platform/fonts/font_fallback_priority.cc
+++ b/third_party/blink/renderer/platform/fonts/font_fallback_priority.cc
@@ -9,6 +9,6 @@
 bool IsNonTextFallbackPriority(FontFallbackPriority fallback_priority) {
   return fallback_priority == FontFallbackPriority::kEmojiText ||
          fallback_priority == FontFallbackPriority::kEmojiEmoji;
-};
+}
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/opentype/font_format_check.cc b/third_party/blink/renderer/platform/fonts/opentype/font_format_check.cc
index e05ebd63..a72946a 100644
--- a/third_party/blink/renderer/platform/fonts/opentype/font_format_check.cc
+++ b/third_party/blink/renderer/platform/fonts/opentype/font_format_check.cc
@@ -16,11 +16,11 @@
 namespace {
 
 struct HarfbuzzBlobDestroyer {
-  inline void operator()(hb_blob_t* blob) { hb_blob_destroy(blob); };
+  inline void operator()(hb_blob_t* blob) { hb_blob_destroy(blob); }
 };
 
 struct HarfbuzzFaceDestroyer {
-  inline void operator()(hb_face_t* face) { hb_face_destroy(face); };
+  inline void operator()(hb_face_t* face) { hb_face_destroy(face); }
 };
 }  // namespace
 
diff --git a/third_party/blink/renderer/platform/fonts/opentype/font_settings_test.cc b/third_party/blink/renderer/platform/fonts/opentype/font_settings_test.cc
index bf748bf..5c2fa7d9 100644
--- a/third_party/blink/renderer/platform/fonts/opentype/font_settings_test.cc
+++ b/third_party/blink/renderer/platform/fonts/opentype/font_settings_test.cc
@@ -44,7 +44,7 @@
   CHECK_NE(one_axis_a->GetHash(), two_axes_different_value->GetHash());
   CHECK_NE(empty_variation_settings->GetHash(), one_axis_a->GetHash());
   CHECK_EQ(empty_variation_settings->GetHash(), 0u);
-};
+}
 
 TEST(FontSettingsTest, ToString) {
   {
diff --git a/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.h b/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.h
index 4f53191..f8786a9d 100644
--- a/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.h
+++ b/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.h
@@ -59,6 +59,6 @@
   mutable FontFormat font_format_;
 };
 
-};  // namespace blink
+}  // namespace blink
 
 #endif
diff --git a/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.cc b/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.cc
index 970e20a..5bcebcb 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.cc
@@ -160,4 +160,4 @@
   return buffer.EmphasisMarkGlyphData(font_.font_description_);
 }
 
-};  // namespace blink
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h
index f364596..c0d7905 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h
@@ -142,7 +142,7 @@
  private:
   explicit HbFontCacheEntry(hb_font_t* font)
       : hb_font_(HbFontUniquePtr(font)),
-        hb_font_data_(std::make_unique<HarfBuzzFontData>()){};
+        hb_font_data_(std::make_unique<HarfBuzzFontData>()) {}
 
   HbFontUniquePtr hb_font_;
   std::unique_ptr<HarfBuzzFontData> hb_font_data_;
diff --git a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
index 6e239ed..fa99bda 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc
@@ -120,7 +120,7 @@
   unsigned start_index_;
   unsigned num_characters_;
   ReshapeQueueItem(ReshapeQueueItemAction action, unsigned start, unsigned num)
-      : action_(action), start_index_(start), num_characters_(num){};
+      : action_(action), start_index_(start), num_characters_(num) {}
 };
 
 template <typename T>
diff --git a/third_party/blink/renderer/platform/fonts/utf16_ragel_iterator.h b/third_party/blink/renderer/platform/fonts/utf16_ragel_iterator.h
index 9784933..c2d3e75 100644
--- a/third_party/blink/renderer/platform/fonts/utf16_ragel_iterator.h
+++ b/third_party/blink/renderer/platform/fonts/utf16_ragel_iterator.h
@@ -21,7 +21,7 @@
 // since Ragel dereferences multiple times without moving the iterator's cursor.
 class PLATFORM_EXPORT UTF16RagelIterator {
  public:
-  UTF16RagelIterator() : buffer_(nullptr), buffer_size_(0), cursor_(0){};
+  UTF16RagelIterator() : buffer_(nullptr), buffer_size_(0), cursor_(0) {}
 
   UTF16RagelIterator(const UChar* buffer,
                      unsigned buffer_size,
@@ -31,7 +31,7 @@
         cursor_(cursor),
         cached_category_(kMaxEmojiScannerCategory) {
     UpdateCachedCategory();
-  };
+  }
 
   UTF16RagelIterator end() {
     UTF16RagelIterator ret = *this;
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder.h b/third_party/blink/renderer/platform/image-decoders/image_decoder.h
index e51dcca..f15e217 100644
--- a/third_party/blink/renderer/platform/image-decoders/image_decoder.h
+++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.h
@@ -191,7 +191,7 @@
   bool IsDecodedSizeAvailable() const { return !failed_ && size_available_; }
 
   virtual IntSize Size() const { return size_; }
-  virtual std::vector<SkISize> GetSupportedDecodeSizes() const { return {}; };
+  virtual std::vector<SkISize> GetSupportedDecodeSizes() const { return {}; }
 
   // Decoders which downsample images should override this method to
   // return the actual decoded size.
@@ -467,7 +467,7 @@
 
   // This methods gets called at the end of InitFrameBuffer. Subclasses can do
   // format specific initialization, for e.g. alpha settings, here.
-  virtual void OnInitFrameBuffer(size_t){};
+  virtual void OnInitFrameBuffer(size_t) {}
 
   // Called by InitFrameBuffer to determine if it can take the bitmap of the
   // previous frame. This condition is different for GIF and WEBP.
diff --git a/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc
index 998193cc..7178c121 100644
--- a/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc
+++ b/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc
@@ -1352,4 +1352,4 @@
   ASSERT_FALSE(decoder->Failed());
 }
 
-};  // namespace blink
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/image-decoders/png/png_image_reader.h b/third_party/blink/renderer/platform/image-decoders/png/png_image_reader.h
index 3826493e..236c428 100644
--- a/third_party/blink/renderer/platform/image-decoders/png/png_image_reader.h
+++ b/third_party/blink/renderer/platform/image-decoders/png/png_image_reader.h
@@ -82,7 +82,7 @@
   // Number of complete frames parsed so far; includes frame 0 even if partial.
   size_t FrameCount() const { return frame_info_.size(); }
 
-  bool ParseCompleted() const { return parse_completed_; };
+  bool ParseCompleted() const { return parse_completed_; }
 
   bool FrameIsReceivedAtIndex(size_t index) const {
     if (!index)
diff --git a/third_party/blink/renderer/platform/image-encoders/image_encoder.cc b/third_party/blink/renderer/platform/image-encoders/image_encoder.cc
index 44e294a..7fb56fd4 100644
--- a/third_party/blink/renderer/platform/image-encoders/image_encoder.cc
+++ b/third_party/blink/renderer/platform/image-encoders/image_encoder.cc
@@ -103,4 +103,4 @@
 
   return options;
 }
-};
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/image-encoders/image_encoder.h b/third_party/blink/renderer/platform/image-encoders/image_encoder.h
index a4a4f195..3c7e3841 100644
--- a/third_party/blink/renderer/platform/image-encoders/image_encoder.h
+++ b/third_party/blink/renderer/platform/image-encoders/image_encoder.h
@@ -88,6 +88,6 @@
   VectorWStream dst_;
   std::unique_ptr<SkEncoder> encoder_;
 };
-};
+}  // namespace blink
 
 #endif
diff --git a/third_party/blink/renderer/platform/mhtml/mhtml_archive.h b/third_party/blink/renderer/platform/mhtml/mhtml_archive.h
index 375982f..01804b6 100644
--- a/third_party/blink/renderer/platform/mhtml/mhtml_archive.h
+++ b/third_party/blink/renderer/platform/mhtml/mhtml_archive.h
@@ -107,7 +107,7 @@
   WTF::Time Date() const { return date_; }
 
   void Trace(blink::Visitor*);
-  blink::mojom::MHTMLLoadResult LoadResult() const { return load_result_; };
+  blink::mojom::MHTMLLoadResult LoadResult() const { return load_result_; }
 
  private:
   static MHTMLArchive* CreateArchive(const KURL&,
diff --git a/third_party/blink/renderer/platform/testing/empty_web_media_player.h b/third_party/blink/renderer/platform/testing/empty_web_media_player.h
index 8e268e9..be44daba 100644
--- a/third_party/blink/renderer/platform/testing/empty_web_media_player.h
+++ b/third_party/blink/renderer/platform/testing/empty_web_media_player.h
@@ -53,7 +53,7 @@
   bool WouldTaintOrigin() const override { return false; }
   double MediaTimeForTimeValue(double time_value) const override {
     return time_value;
-  };
+  }
   unsigned DecodedFrameCount() const override { return 0; }
   unsigned DroppedFrameCount() const override { return 0; }
   uint64_t AudioDecodedByteCount() const override { return 0; }
diff --git a/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc b/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc
index 34f9281..e2ffef20 100644
--- a/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc
+++ b/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc
@@ -4,8 +4,7 @@
 
 #include "third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h"
 
-#include <memory>
-#include <vector>
+#include <utility>
 
 #include "third_party/blink/public/platform/web_media_stream.h"
 #include "third_party/blink/public/platform/web_media_stream_source.h"
@@ -29,7 +28,7 @@
   static uintptr_t last_id_;
 
  public:
-  DummyRtpSenderInternal(WebMediaStreamTrack track)
+  explicit DummyRtpSenderInternal(WebMediaStreamTrack track)
       : id_(++last_id_), track_(std::move(track)) {}
 
   uintptr_t id() const { return id_; }
@@ -45,7 +44,7 @@
 
 class DummyWebRTCRtpSender : public WebRTCRtpSender {
  public:
-  DummyWebRTCRtpSender(WebMediaStreamTrack track)
+  explicit DummyWebRTCRtpSender(WebMediaStreamTrack track)
       : internal_(new DummyRtpSenderInternal(std::move(track))) {}
   DummyWebRTCRtpSender(const DummyWebRTCRtpSender& other)
       : internal_(other.internal_) {}
@@ -83,7 +82,7 @@
   static uintptr_t last_id_;
 
  public:
-  DummyWebRTCRtpReceiver(WebMediaStreamSource::Type type)
+  explicit DummyWebRTCRtpReceiver(WebMediaStreamSource::Type type)
       : id_(++last_id_), track_() {
     if (type == WebMediaStreamSource::Type::kTypeAudio) {
       WebMediaStreamSource web_source;
@@ -369,6 +368,14 @@
   return nullptr;
 }
 
+void MockWebRTCPeerConnectionHandler::
+    RunSynchronousOnceClosureOnSignalingThread(base::OnceClosure closure,
+                                               const char* trace_event_name) {}
+
+void MockWebRTCPeerConnectionHandler::
+    RunSynchronousRepeatingClosureOnSignalingThread(
+        const base::RepeatingClosure& closure,
+        const char* trace_event_name) {}
 std::unique_ptr<WebRTCPeerConnectionHandler>
 TestingPlatformSupportWithWebRTC::CreateRTCPeerConnectionHandler(
     WebRTCPeerConnectionHandlerClient*,
diff --git a/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h b/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h
index db89d47..f039d99f8 100644
--- a/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h
+++ b/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h
@@ -5,6 +5,10 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_TESTING_PLATFORM_SUPPORT_WITH_WEB_RTC_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_TESTING_TESTING_PLATFORM_SUPPORT_WITH_WEB_RTC_H_
 
+#include <memory>
+#include <string>
+#include <vector>
+
 #include "base/single_thread_task_runner.h"
 #include "third_party/blink/public/platform/web_rtc_peer_connection_handler.h"
 #include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
@@ -67,6 +71,12 @@
   void Stop() override;
   WebString Id() const override;
   webrtc::PeerConnectionInterface* NativePeerConnection() override;
+  void RunSynchronousOnceClosureOnSignalingThread(
+      base::OnceClosure closure,
+      const char* trace_event_name) override;
+  void RunSynchronousRepeatingClosureOnSignalingThread(
+      const base::RepeatingClosure& closure,
+      const char* trace_event_name) override;
 
  private:
   class DummyWebRTCRtpTransceiver;
diff --git a/third_party/blink/renderer/platform/text/character_emoji.cc b/third_party/blink/renderer/platform/text/character_emoji.cc
index 054cdcf..0a05362 100644
--- a/third_party/blink/renderer/platform/text/character_emoji.cc
+++ b/third_party/blink/renderer/platform/text/character_emoji.cc
@@ -265,4 +265,4 @@
   return (ch >= 0x1F1E6 && ch <= 0x1F1FF);
 }
 
-};  // namespace blink
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/waitable_event.h b/third_party/blink/renderer/platform/waitable_event.h
index 929b920..b2a4cd2 100644
--- a/third_party/blink/renderer/platform/waitable_event.h
+++ b/third_party/blink/renderer/platform/waitable_event.h
@@ -37,7 +37,7 @@
 
 namespace base {
 class WaitableEvent;
-};  // namespace base
+}  // namespace base
 
 namespace blink {
 
diff --git a/third_party/blink/tools/blinkpy/w3c/import_notifier.py b/third_party/blink/tools/blinkpy/w3c/import_notifier.py
index 11e405a9..87e4f6a0 100644
--- a/third_party/blink/tools/blinkpy/w3c/import_notifier.py
+++ b/third_party/blink/tools/blinkpy/w3c/import_notifier.py
@@ -171,7 +171,7 @@
 
             owners = self.owners_extractor.extract_owners(owners_file)
             # owners may be empty but not None.
-            cc = owners + ['robertma@chromium.org']
+            cc = owners
 
             component = self.owners_extractor.extract_component(owners_file)
             # component could be None.
diff --git a/third_party/blink/tools/blinkpy/w3c/import_notifier_unittest.py b/third_party/blink/tools/blinkpy/w3c/import_notifier_unittest.py
index d4a231b4..6f7c28b 100644
--- a/third_party/blink/tools/blinkpy/w3c/import_notifier_unittest.py
+++ b/third_party/blink/tools/blinkpy/w3c/import_notifier_unittest.py
@@ -187,7 +187,7 @@
         # Only one directory has WPT-NOTIFY enabled.
         self.assertEqual(len(bugs), 1)
         # The formatting of imported commits and new failures are already tested.
-        self.assertEqual(bugs[0].body['cc'], ['foolip@chromium.org', 'robertma@chromium.org'])
+        self.assertEqual(bugs[0].body['cc'], ['foolip@chromium.org'])
         self.assertEqual(bugs[0].body['components'], ['Blink>Infra>Ecosystem'])
         self.assertEqual(bugs[0].body['summary'],
                          '[WPT] New failures introduced in external/wpt/foo by import https://crrev.com/c/12345')
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index df7caf2..f82f595 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -2033,6 +2033,7 @@
 external/wpt/payment-request/payment-response/retry-method-manual.https.html [ WontFix ]
 external/wpt/payment-request/payment-response/shippingAddress-attribute-manual.https.html [ WontFix ]
 external/wpt/payment-request/payment-response/shippingOption-attribute-manual.https.html [ WontFix ]
+external/wpt/payment-request/rejects_if_not_active_manual.https.html [ WontFix ]
 external/wpt/payment-request/shipping-address-changed-manual.https.html [ WontFix ]
 external/wpt/payment-request/show-method-optional-promise-rejects-manual.https.html [ WontFix ]
 external/wpt/payment-request/show-method-optional-promise-resolves-manual.https.html [ WontFix ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 1a7cce9..e0cea85 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1533,7 +1533,6 @@
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/box-sizing-min-max-sizes.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/box-sizing.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/bug604346.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/canvas-dynamic-change.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/columns-auto-size.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/columns-height-set-via-top-bottom.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/content-height-with-scrollbars.html [ Failure ]
@@ -1584,12 +1583,10 @@
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/overflow-keep-scrollpos.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/percentage-height-replaced-element.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/percentage-heights.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/percentage-sizes-quirks.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/position-absolute-child.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/preferred-widths-orthogonal.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/preferred-widths.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/relayout-align-items.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/relayout-image-load.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/relpos-with-percentage-top.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/scrollbars-auto.html [ Skip ]
 crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/scrollbars.html [ Skip ]
@@ -1639,9 +1636,6 @@
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row-reverse-wrap-reverse.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row-wrap-reverse.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-align-items-center.html [ Failure ]
-crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-aspect-ratio-img-column-001.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-aspect-ratio-img-row-002.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-aspect-ratio-img-row-003.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-direction-with-element-insert.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-direction.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-flow-003.html [ Failure ]
@@ -4329,13 +4323,6 @@
 
 crbug.com/825798 external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-non-snap-to-lines.html [ Failure ]
 
-crbug.com/848607 external/wpt/import-maps/module-map-key.tentative.html [ Failure ]
-crbug.com/848607 external/wpt/import-maps/http.sub.tentative.html [ Failure ]
-crbug.com/848607 external/wpt/import-maps/bare.sub.tentative.html [ Failure ]
-crbug.com/848607 external/wpt/import-maps/data.sub.tentative.html [ Failure ]
-crbug.com/848607 external/wpt/import-maps/fallback-disallowed.sub.tentative.html [ Failure ]
-crbug.com/848607 external/wpt/import-maps/fallback.sub.tentative.html [ Failure ]
-crbug.com/848607 external/wpt/import-maps/resolving.tentative.html [ Failure ]
 crbug.com/848607 external/wpt/import-maps/acquire-import-maps-flag/dynamic-import/ [ Skip ]
 crbug.com/848607 external/wpt/import-maps/acquire-import-maps-flag/script-tag/ [ Skip ]
 
@@ -5917,14 +5904,8 @@
 # production code. Because such timing bugs are relatively common in tests and it would thus be very
 # difficult to land the dispatch change without some temporary breakage, these tests are disabled
 # while they can be investigated.
-crbug.com/921719 printing/offscreencanvas-2d-printing.html  [ Skip ]
-crbug.com/921719 printing/offscreencanvas-webgl-printing.html  [ Skip ]
 crbug.com/921719 scrollbars/mock-scrollbars.html [ Skip ]
-crbug.com/921719 virtual/layout_ng_experimental/printing/offscreencanvas-2d-printing.html [ Skip ]
-crbug.com/921719 virtual/layout_ng_experimental/printing/offscreencanvas-webgl-printing.html [ Skip ]
 crbug.com/921719 virtual/prefer_compositing_to_lcd_text/scrollbars/mock-scrollbars.html [ Skip ]
-crbug.com/921719 virtual/threaded/printing/offscreencanvas-2d-printing.html [ Skip ]
-crbug.com/921719 virtual/threaded/printing/offscreencanvas-webgl-printing.html [ Skip ]
 crbug.com/922951 animations/direction-and-fill/fill-mode-iteration-count-non-integer.html [ Skip ]
 crbug.com/922951 animations/direction-and-fill/fill-mode-missing-from-to-keyframes.html [ Skip ]
 crbug.com/922951 animations/direction-and-fill/fill-mode-transform.html [ Skip ]
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 93e23fa8..6bdb028 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
@@ -250579,6 +250579,18 @@
      {}
     ]
    ],
+   "html/webappapis/system-state-and-capabilities/the-navigator-object/navigator_user_agent.tentative.html": [
+    [
+     "/html/webappapis/system-state-and-capabilities/the-navigator-object/navigator_user_agent.tentative.html",
+     {}
+    ]
+   ],
+   "html/webappapis/system-state-and-capabilities/the-navigator-object/navigator_user_agent.tentative.https.html": [
+    [
+     "/html/webappapis/system-state-and-capabilities/the-navigator-object/navigator_user_agent.tentative.https.html",
+     {}
+    ]
+   ],
    "html/webappapis/system-state-and-capabilities/the-navigator-object/navigatorcookies-cookieenabled-true.html": [
     [
      "/html/webappapis/system-state-and-capabilities/the-navigator-object/navigatorcookies-cookieenabled-true.html",
@@ -394155,11 +394167,11 @@
    "support"
   ],
   "domparsing/XMLSerializer-serializeToString-expected.txt": [
-   "965e6c1ab654444cf1dbae221c15d44644e7bfd1",
+   "e727b948d30dd8e7f65cf5a0c11dc0acd4c5e775",
    "support"
   ],
   "domparsing/XMLSerializer-serializeToString.html": [
-   "ab373481204e64070b8e3fd5a0f52f06211153b4",
+   "e2e72e39eb5f849bbaf9302af6f3301a6cb36fa8",
    "testharness"
   ],
   "domparsing/createContextualFragment.html": [
@@ -400047,35 +400059,35 @@
    "support"
   ],
   "fetch/sec-metadata/embed.tentative.https.sub.html": [
-   "1c69c021accb90db3bc4ce599ce1988f5329c8ce",
+   "6f0c439595047049f8c5e71948bbcce6f8c22bd7",
    "testharness"
   ],
   "fetch/sec-metadata/fetch.tentative.https.sub.html": [
-   "f6460b4efca7cadf29ad461b80dd45e79a4e7fb6",
+   "dc4b977ac6ec6544215bcf2a41007a6adde2d36e",
    "testharness"
   ],
   "fetch/sec-metadata/font.tentative.https.sub.html": [
-   "d2bcf6928848f7a353035a29dd6ee38bc365d45b",
+   "9792f2dce9427c3e42f595adb4c67113a6bb29d7",
    "testharness"
   ],
   "fetch/sec-metadata/iframe.tentative.https.sub.html": [
-   "6ee14300296b6f1e9f7f5083637eb06e620f30e8",
+   "73bd90745d1ab9dd52b88cc49871544375bb7703",
    "testharness"
   ],
   "fetch/sec-metadata/iframe.tentative.sub.html": [
-   "ce31a8182510f246c22543b74ea40bec50d7b016",
+   "eab2d3f5886ed178781e092b90bfd52eaa194bc5",
    "testharness"
   ],
   "fetch/sec-metadata/img.tentative.https.sub.html": [
-   "c5c389503ccafd2d2cf21a3634b6995bc22a2e91",
+   "252b220011c553b2b941dbc9fdce427990bb1131",
    "testharness"
   ],
   "fetch/sec-metadata/object.tentative.https.sub.html": [
-   "0b9839470d1d8c49a5c58f4b832f825f77a6460b",
+   "2a0e8de85568c1ae6008af793f4ca9a6fad77a3d",
    "testharness"
   ],
   "fetch/sec-metadata/redirect/cross-site-redirect.tentative.https.sub.html": [
-   "56d88d9156c7ad201b7874fc7e196e5a9b2291f7",
+   "f88cf140d4e32ee21d3d0d6475905be55fe8adad",
    "testharness"
   ],
   "fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub-expected.txt": [
@@ -400083,7 +400095,7 @@
    "support"
   ],
   "fetch/sec-metadata/redirect/multiple-redirect-cross-site.tentative.https.sub.html": [
-   "f6d18f568f1a8c96c6a360a7121241d506a29212",
+   "688c697ac931eefb445e75240bc4cb978c088e47",
    "testharness"
   ],
   "fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub-expected.txt": [
@@ -400091,7 +400103,7 @@
    "support"
   ],
   "fetch/sec-metadata/redirect/multiple-redirect-same-site.tentative.https.sub.html": [
-   "4756a79ab258ffc4402e02d80e745760c9caf9cb",
+   "bc79f7810a1be2cd12b40463ec6cac9a9e80d723",
    "testharness"
   ],
   "fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub-expected.txt": [
@@ -400099,7 +400111,7 @@
    "support"
   ],
   "fetch/sec-metadata/redirect/same-origin-redirect.tentative.https.sub.html": [
-   "8558d6890e6fc8afa9e948906615cfc3ea79818c",
+   "a5323921c26bc9882c0c17e75a2a562fe7d6972f",
    "testharness"
   ],
   "fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub-expected.txt": [
@@ -400107,11 +400119,11 @@
    "support"
   ],
   "fetch/sec-metadata/redirect/same-site-redirect.tentative.https.sub.html": [
-   "8e05b255b88df81ae7db95428e0a5d8dd236000a",
+   "92749ae0b80c44938e6ca88e7c9bbbcd1cef48ca",
    "testharness"
   ],
   "fetch/sec-metadata/report.tentative.https.sub.html": [
-   "1cfa8641ba8785d9168d85b73eaa12b95b10e314",
+   "f1d8e06e50e2decdcd7f5051c50a623e5642ffa4",
    "testharness"
   ],
   "fetch/sec-metadata/report.tentative.https.sub.html.sub.headers": [
@@ -400131,7 +400143,7 @@
    "support"
   ],
   "fetch/sec-metadata/resources/helper.js": [
-   "1a9ec154e02ba4c6a46ee3d4fde7a866ddd330fa",
+   "4bee68996e86e7fc9736f97cbdf3a002b73ad817",
    "support"
   ],
   "fetch/sec-metadata/resources/post-to-owner.py": [
@@ -400151,35 +400163,35 @@
    "support"
   ],
   "fetch/sec-metadata/script.tentative.https.sub.html": [
-   "d76378f1dd8df62fa5404dc1fda1b47fb6a8d409",
+   "a35e753c7898cc89427fa8dc22ce5fd55325ea8e",
    "testharness"
   ],
   "fetch/sec-metadata/script.tentative.sub.html": [
-   "482f4b98f9e8bf4b12e5f960cc39ea4e55ee6c77",
+   "3218a40abdedfbb39b0dcb7a70d1c30d59ae74a2",
    "testharness"
   ],
   "fetch/sec-metadata/serviceworker.tentative.https.sub.html": [
-   "d0b86d2d9a8ccf67119983890a29c52a5c875c62",
+   "5b7ee772b6175d7c2af3b1932a6194d69785ce65",
    "testharness"
   ],
   "fetch/sec-metadata/sharedworker.tentative.https.sub.html": [
-   "66f7d5b9d8dcde9be0b84089701e8d7ca49967e1",
+   "cfeadd8d8e206bc7a108b25b177ec0b3666d8e58",
    "testharness"
   ],
   "fetch/sec-metadata/style.tentative.https.sub.html": [
-   "9697db75c82fa213459aff6c8d4bc6605f6f4be0",
+   "4ae12662a29380b5c241988b7b97d34031d7bec7",
    "testharness"
   ],
   "fetch/sec-metadata/track.tentative.https.sub.html": [
-   "b9dfabf9739775aa77952f5d48fca57d3224b581",
+   "89933f22c393711dd599cbdc4c3a18251005b7f6",
    "testharness"
   ],
   "fetch/sec-metadata/window-open.tentative.https.sub.html": [
-   "236268e177405f4cd428ed6e1121f84343abcf7e",
+   "2957dad40a437aae77914f3b6cc7120894da0b26",
    "testharness"
   ],
   "fetch/sec-metadata/worker.tentative.https.sub.html": [
-   "fcffe91dbf70df0a4d057b59c7c6f7dcafdad235",
+   "89be6f0b5a1b2cdb6ab2489a2cf70a77baf44667",
    "testharness"
   ],
   "fetch/sec-metadata/xslt.tentative.https.sub-expected.txt": [
@@ -400187,7 +400199,7 @@
    "support"
   ],
   "fetch/sec-metadata/xslt.tentative.https.sub.html": [
-   "32349c9598e868ef35873805a5d451a5b987ede9",
+   "eea2329900e000c43cb0b347c011d6d4adb8bd46",
    "testharness"
   ],
   "fetch/security/dangling-markup-mitigation-data-url.tentative.sub.html": [
@@ -418283,7 +418295,7 @@
    "testharness"
   ],
   "html/semantics/text-level-semantics/the-a-element/a.rel-setter-01.html": [
-   "83c69de301422f20241042852ac033023faf5ee0",
+   "c319266887b7ee916e80bce1eadcc033a13411bd",
    "testharness"
   ],
   "html/semantics/text-level-semantics/the-a-element/a.text-getter-01.html": [
@@ -420578,6 +420590,14 @@
    "07bccb788052e7ce2cb722558e416b5c017ed9f0",
    "testharness"
   ],
+  "html/webappapis/system-state-and-capabilities/the-navigator-object/navigator_user_agent.tentative.html": [
+   "dd4c531070c8a21328a14709fd0357c6fba15001",
+   "testharness"
+  ],
+  "html/webappapis/system-state-and-capabilities/the-navigator-object/navigator_user_agent.tentative.https.html": [
+   "5f0dba6bcf72cb94f7e53ee52bfaedf7ac4819bf",
+   "testharness"
+  ],
   "html/webappapis/system-state-and-capabilities/the-navigator-object/navigatorcookies-cookieenabled-false-manual-expected.txt": [
    "a95972302bfe24a2e207a7085bde0d103426de8f",
    "support"
@@ -447955,7 +447975,7 @@
    "testharness"
   ],
   "service-workers/service-worker/fetch-request-xhr.https-expected.txt": [
-   "e676089e01c606b4edd9b0bc1b6b2beb096a73e2",
+   "76e08357b6e2b1edce325a9ebefde287c962681b",
    "support"
   ],
   "service-workers/service-worker/fetch-request-xhr.https.html": [
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/text-level-semantics/the-a-element/a.rel-setter-01.html b/third_party/blink/web_tests/external/wpt/html/semantics/text-level-semantics/the-a-element/a.rel-setter-01.html
index 83c69de3..c319266 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/text-level-semantics/the-a-element/a.rel-setter-01.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/text-level-semantics/the-a-element/a.rel-setter-01.html
@@ -13,8 +13,8 @@
   var a = document.getElementById("test");
 
   test(function() {
-    a.rel = "noreferrer"
-    assert_equals(a.rel, "noreferrer");
+    a.rel = "noreferrer";
+    assert_equals(a.getAttribute("rel"), "noreferrer");
   }, "Test anchor's rel setter");
 });
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/builtin-empty.tentative.html b/third_party/blink/web_tests/external/wpt/import-maps/builtin-empty.tentative.html
new file mode 100644
index 0000000..aba28d18e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/import-maps/builtin-empty.tentative.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helper.js"></script>
+
+<script>
+const importMap = `
+{
+  "imports": {
+    "./resources/log.js?pipe=sub&name=empty": [ "@std/" ],
+    "./resources/log.js?pipe=sub&name=empty-fallback": [
+      "@std/",
+      "./resources/log.js?pipe=sub&name=empty-fallback"
+    ]
+  }
+}
+`;
+
+const tests = {
+  // Arrays of expected results for:
+  // - <script src type="module">,
+  // - <script src> (classic script),
+  // - static import, and
+  // - dynamic import.
+
+  // Discussions about notations are ongoing, e.g.
+  // https://github.com/tc39/proposal-javascript-standard-library/issues/12
+  // Currently the tests expects two notations are accepted.
+  // TODO: Once the discussions converge, update this and related tests.
+  "std:":
+    [Result.FETCH_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR],
+  "@std/":
+    [Result.FETCH_ERROR, Result.PARSE_ERROR, Result.FETCH_ERROR, Result.FETCH_ERROR],
+
+  "./resources/log.js?pipe=sub&name=empty":
+    [Result.URL, Result.URL, Result.PARSE_ERROR, Result.PARSE_ERROR],
+  "./resources/log.js?pipe=sub&name=empty-fallback":
+    [Result.URL, Result.URL, Result.URL, Result.URL],
+};
+
+doTests(importMap, null, tests);
+</script>
+<body>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/resolving.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/import-maps/resolving.tentative-expected.txt
new file mode 100644
index 0000000..4dc845e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/import-maps/resolving.tentative-expected.txt
@@ -0,0 +1,22 @@
+This is a testharness.js-based test.
+PASS Unmapped / should resolve ./ specifiers as URLs
+PASS Unmapped / should resolve ../ specifiers as URLs
+PASS Unmapped / should resolve / specifiers as URLs
+PASS Unmapped / should parse absolute fetch-scheme URLs
+FAIL Unmapped / should fail for absolute non-fetch-scheme URLs assert_throws: function "() => resolveUnderTest('mailto:bad')" did not throw
+FAIL Unmapped / should fail for strings not parseable as absolute URLs and not starting with ./ ../ or / assert_throws: function "() => resolveUnderTest('https://ex ample.org/')" did not throw
+PASS Mapped using the "imports" key only (no scopes) / should fail when the mapping is to an empty array
+PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should work for package main modules
+FAIL Mapped using the "imports" key only (no scopes) / Package-like scenarios / should work for package submodules Failed to resolve module specifier moment/foo: Relative references must start with either "/", "./", or "../".
+PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should work for package names that end in a slash by just passing through
+PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should still fail for package modules that are not declared
+PASS Mapped using the "imports" key only (no scopes) / Tricky specifiers / should work for explicitly-mapped specifiers that happen to have a slash
+PASS Mapped using the "imports" key only (no scopes) / Tricky specifiers / should work when the specifier has punctuation
+PASS Mapped using the "imports" key only (no scopes) / Tricky specifiers / should fail for attempting to get a submodule of something not declared with a trailing slash
+PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should remap to built-in modules
+PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should remap to other URLs
+PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should fail for URLs that remap to empty arrays
+PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should remap URLs that are just composed from / and .
+PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should use the last entry's address when URL-like specifiers parse to the same absolute URL
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/intersection-observer/resources/intersection-observer-test-utils.js b/third_party/blink/web_tests/external/wpt/intersection-observer/resources/intersection-observer-test-utils.js
index 8683c8b..44f794b 100644
--- a/third_party/blink/web_tests/external/wpt/intersection-observer/resources/intersection-observer-test-utils.js
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/resources/intersection-observer-test-utils.js
@@ -72,7 +72,15 @@
 //       notifications.
 function waitForNotification(t, f) {
   requestAnimationFrame(function() {
-    requestAnimationFrame(function() { t.step_timeout(f); });
+    requestAnimationFrame(function() { t.step_timeout(f, 0); });
+  });
+}
+
+// If you need to wait until the IntersectionObserver algorithm has a chance
+// to run, but don't need to wait for delivery of the notifications...
+function waitForFrame(t, f) {
+  requestAnimationFrame(function() {
+    t.step_timeout(f, 0);
   });
 }
 
@@ -85,9 +93,19 @@
 //
 // Following these rules will ensure that the test suite will not abort before
 // all test steps have run.
-function runTestCycle(f, description) {
+//
+// If the 'delay' parameter to the IntersectionObserver constructor is used,
+// tests will need to add the same delay to their runTestCycle invocations, to
+// wait for notifications to be generated and delivered.
+function runTestCycle(f, description, delay) {
   async_test(function(t) {
-    waitForNotification(t, t.step_func_done(f));
+    if (delay) {
+      step_timeout(() => {
+        waitForNotification(t, t.step_func_done(f));
+      }, delay);
+    } else {
+      waitForNotification(t, t.step_func_done(f));
+    }
   }, description);
 }
 
@@ -174,4 +192,4 @@
 function checkIsIntersecting(entries, i, expected) {
   assert_equals(entries[i].isIntersecting, expected,
     'entries[' + i + '].target.isIntersecting equals ' + expected);
-}
\ No newline at end of file
+}
diff --git a/third_party/blink/web_tests/http/tests/intersection-observer/resources/v2-subframe.html b/third_party/blink/web_tests/external/wpt/intersection-observer/resources/v2-subframe.html
similarity index 61%
rename from third_party/blink/web_tests/http/tests/intersection-observer/resources/v2-subframe.html
rename to third_party/blink/web_tests/external/wpt/intersection-observer/resources/v2-subframe.html
index 686ef0f..295bbf04 100644
--- a/third_party/blink/web_tests/http/tests/intersection-observer/resources/v2-subframe.html
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/resources/v2-subframe.html
@@ -1,23 +1,22 @@
 <!DOCTYPE html>
 <div id="target">target</div>
 <script>
+var delay = 100;
 var results = [];
 
-if (window.internals) {
-  internals.DisableIntersectionObserverThrottleDelay();
-}
-
 function waitForNotification(f) {
-  requestAnimationFrame(function () {
-    setTimeout(function () {
-      setTimeout(f)
+  setTimeout(() => {
+    requestAnimationFrame(function () {
+      requestAnimationFrame(function () {
+        setTimeout(f)
+      })
     })
-  })
+  }, delay)
 }
 
 window.addEventListener("message", event => {
   waitForNotification(() => {
-    window.parent.postMessage(results.map(e => { return e.isVisible }), "*");
+    window.parent.postMessage(results.map(e => e.isVisible), "*");
     results = [];
   });
 });
@@ -26,7 +25,7 @@
   var target = document.getElementById("target");
   var observer = new IntersectionObserver(entries => {
     results = entries;
-  }, {trackVisibility: true, delay: 100});
+  }, {trackVisibility: true, delay: delay});
   observer.observe(document.getElementById("target"));
   window.parent.postMessage("", "*");
 };
diff --git a/third_party/blink/web_tests/intersection-observer/v2/animated-occlusion.html b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/animated-occlusion.html
similarity index 71%
rename from third_party/blink/web_tests/intersection-observer/v2/animated-occlusion.html
rename to third_party/blink/web_tests/external/wpt/intersection-observer/v2/animated-occlusion.html
index 2e076cf..c1eafb7 100644
--- a/third_party/blink/web_tests/intersection-observer/v2/animated-occlusion.html
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/animated-occlusion.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <script src="../resources/intersection-observer-test-utils.js"></script>
 
 <style>
@@ -37,40 +37,36 @@
 <div id="occluder"></div>
 
 <script>
+var vw = document.documentElement.clientWidth;
+var vh = document.documentElement.clientHeight;
+var delay = 100;
 var entries = [];
 var target;
 var occluder;
 
-if (window.internals) {
-  internals.DisableIntersectionObserverThrottleDelay();
-}
-
 runTestCycle(function() {
-  assert_equals(window.innerWidth, 800, "Window must be 800 pixels wide.");
-  assert_equals(window.innerHeight, 600, "Window must be 600 pixels high.");
-
   target = document.getElementById("target");
   occluder = document.getElementById("occluder");
   assert_true(!!target, "target exists");
   assert_true(!!occluder, "occluder exists");
   var observer = new IntersectionObserver(function(changes) {
     entries = entries.concat(changes)
-  }, {trackVisibility: true, delay: 100});
+  }, {trackVisibility: true, delay: delay});
   observer.observe(target);
   entries = entries.concat(observer.takeRecords());
   assert_equals(entries.length, 0, "No initial notifications.");
-  runTestCycle(step0, "First rAF.");
-}, "IntersectionObserverV2 in a single document using the implicit root, with an animated occluding element.");
+  runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 in a single document using the implicit root, with an animated occluding element.", delay);
 
 function step0() {
   occluder.style.animation = "rotate .1s linear";
-  setTimeout(() => {
-    runTestCycle(step1, "occluder.style.animation = 'rotate .1s linear'");
+  step_timeout(() => {
+    runTestCycle(step1, "occluder.style.animation = 'rotate .1s linear'", delay);
   }, 50);
-  checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
+  checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, vw, 0, vh, true, true]);
 }
 
 function step1() {
-  checkLastEntry(entries, 1, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, false]);
+  checkLastEntry(entries, 1, [0, 100, 0, 100, 0, 100, 0, 100, 0, vw, 0, vh, true, false]);
 }
 </script>
diff --git a/third_party/blink/web_tests/intersection-observer/v2/blur-filter.html b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/blur-filter.html
similarity index 79%
rename from third_party/blink/web_tests/intersection-observer/v2/blur-filter.html
rename to third_party/blink/web_tests/external/wpt/intersection-observer/v2/blur-filter.html
index c4782eb..2f55066 100644
--- a/third_party/blink/web_tests/intersection-observer/v2/blur-filter.html
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/blur-filter.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <script src="../resources/intersection-observer-test-utils.js"></script>
 
 <style>
@@ -30,14 +30,11 @@
 <div id="occluder"></div>
 
 <script>
+var delay = 100;
 var entries = [];
 var target;
 var occluder;
 
-if (window.internals) {
-  internals.DisableIntersectionObserverThrottleDelay();
-}
-
 runTestCycle(function() {
   target = document.getElementById("target");
   occluder = document.getElementById("occluder");
@@ -45,17 +42,17 @@
   assert_true(!!occluder, "occluder exists");
   var observer = new IntersectionObserver(function(changes) {
     entries = entries.concat(changes)
-  }, {trackVisibility: true, delay: 100});
+  }, {trackVisibility: true, delay: delay});
   observer.observe(target);
   entries = entries.concat(observer.takeRecords());
   assert_equals(entries.length, 0, "No initial notifications.");
-  runTestCycle(step0, "First rAF.");
-}, "IntersectionObserverV2 in a single document using the implicit root, with an occluding element.");
+  runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 in a single document using the implicit root, with an occluding element.", delay);
 
 function step0() {
   // Occluding elements with opacity=0 should not affect target visibility.
   occluder.style.opacity = "0";
-  runTestCycle(step2, "occluder.style.opacity = 0");
+  runTestCycle(step2, "occluder.style.opacity = 0", delay);
 
   // First notification should report occlusion due to blur filter.
   checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, false]);
diff --git a/third_party/blink/web_tests/intersection-observer/v2/box-shadow.html b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/box-shadow.html
similarity index 78%
rename from third_party/blink/web_tests/intersection-observer/v2/box-shadow.html
rename to third_party/blink/web_tests/external/wpt/intersection-observer/v2/box-shadow.html
index 6a3c1e0..bcc6980 100644
--- a/third_party/blink/web_tests/intersection-observer/v2/box-shadow.html
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/box-shadow.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <script src="../resources/intersection-observer-test-utils.js"></script>
 
 <style>
@@ -26,14 +26,11 @@
 <iframe id=target srcdoc="<!DOCTYPE html><div>Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum.</div>"></iframe><div id=box-shadow></div>
 
 <script>
+var delay = 100;
 var entries = [];
 var target;
 var occluder;
 
-if (window.internals) {
-  internals.DisableIntersectionObserverThrottleDelay();
-}
-
 runTestCycle(function() {
   target = document.getElementById("target");
   occluder = document.getElementById("box-shadow");
@@ -41,23 +38,23 @@
   assert_true(!!occluder, "occluder exists");
   let observer = new IntersectionObserver(function(changes) {
     entries = entries.concat(changes)
-  }, {trackVisibility: true, delay: 100});
+  }, {trackVisibility: true, delay: delay});
   observer.observe(target);
   entries = entries.concat(observer.takeRecords());
   assert_equals(entries.length, 0, "No initial notifications.");
-  runTestCycle(step0, "First rAF.");
-}, "IntersectionObserverV2 observing an iframe element.");
+  runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 observing an iframe element.", delay);
 
 function step0() {
   occluder.style.boxShadow = "none";
-  runTestCycle(step1, 'occluder.style.boxShadow = "none"');
+  runTestCycle(step1, 'occluder.style.boxShadow = "none"', delay);
   assert_equals(entries.length, 1, "Initial notification.");
   assert_equals(entries[0].isVisible, false, "Initially occluded.");
 }
 
 function step1() {
   occluder.style.boxShadow = "";
-  runTestCycle(step2, 'occluder.style.boxShadow = ""');
+  runTestCycle(step2, 'occluder.style.boxShadow = ""', delay);
   assert_equals(entries.length, 2, "Notification after removing box shadow.");
   assert_equals(entries[1].isVisible, true, "Visible when box shadow removed.");
 }
diff --git a/third_party/blink/web_tests/http/tests/intersection-observer/v2/cross-origin-effects.html b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/cross-origin-effects.sub.html
similarity index 79%
rename from third_party/blink/web_tests/http/tests/intersection-observer/v2/cross-origin-effects.html
rename to third_party/blink/web_tests/external/wpt/intersection-observer/v2/cross-origin-effects.sub.html
index 546ec74..edb8f02 100644
--- a/third_party/blink/web_tests/http/tests/intersection-observer/v2/cross-origin-effects.html
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/cross-origin-effects.sub.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/intersection-observer-test-utils.js"></script>
 
 <style>
 pre, #log {
@@ -11,16 +12,10 @@
 </style>
 
 <div id="container">
-  <iframe src="http://localhost:8080/intersection-observer/resources/v2-subframe.html"></iframe>
+  <iframe src="http://{{domains[www1]}}:{{ports[http][0]}}/intersection-observer/resources/v2-subframe.html"></iframe>
 </div>
 
 <script>
-function waitForFrame(f) {
-  requestAnimationFrame(() => {
-    setTimeout(f)
-  })
-}
-
 async_test(function(t) {
   let container = document.getElementById("container");
   let iframe = document.querySelector("iframe");
@@ -57,7 +52,7 @@
   window.addEventListener("message", event => {
     if (steps.length) {
       t.step_func(steps.shift(), event);
-      waitForFrame(() => {
+      waitForFrame(t, () => {
         iframe.contentWindow.postMessage("", "*")
       });
     } else {
diff --git a/third_party/blink/web_tests/http/tests/intersection-observer/v2/cross-origin-occlusion.html b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/cross-origin-occlusion.sub.html
similarity index 79%
rename from third_party/blink/web_tests/http/tests/intersection-observer/v2/cross-origin-occlusion.html
rename to third_party/blink/web_tests/external/wpt/intersection-observer/v2/cross-origin-occlusion.sub.html
index 1556ade4..6f9fa57 100644
--- a/third_party/blink/web_tests/http/tests/intersection-observer/v2/cross-origin-occlusion.html
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/cross-origin-occlusion.sub.html
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/intersection-observer-test-utils.js"></script>
 
 <style>
 pre, #log {
@@ -21,16 +22,10 @@
 }
 </style>
 
-<iframe src="http://localhost:8080/intersection-observer/resources/v2-subframe.html"></iframe>
+<iframe src="http://{{domains[www1]}}:{{ports[http][0]}}/intersection-observer/resources/v2-subframe.html"></iframe>
 <div id="occluder"></div>
 
 <script>
-function waitForFrame(f) {
-  requestAnimationFrame(() => {
-    setTimeout(f)
-  })
-}
-
 async_test(function(t) {
   let iframe = document.querySelector("iframe");
   let occluder = document.getElementById("occluder");
@@ -61,7 +56,7 @@
   window.addEventListener("message", event => {
     if (steps.length) {
       t.step_func(steps.shift(), event);
-      waitForFrame(() => {
+      waitForFrame(t, () => {
         iframe.contentWindow.postMessage("", "*");
       });
     } else {
diff --git a/third_party/blink/web_tests/intersection-observer/v2/delay-test.html b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/delay-test.html
similarity index 92%
rename from third_party/blink/web_tests/intersection-observer/v2/delay-test.html
rename to third_party/blink/web_tests/external/wpt/intersection-observer/v2/delay-test.html
index 52ab5b84..086301c4 100644
--- a/third_party/blink/web_tests/intersection-observer/v2/delay-test.html
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/delay-test.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <script src="../resources/intersection-observer-test-utils.js"></script>
 
 <style>
@@ -43,16 +43,7 @@
   entries = entries.concat(observer.takeRecords());
   assert_equals(entries.length, 0, "No initial notifications.");
   // The first notification should be sent without delay.
-  waitForNotification(t.step_func(step0));
-
-  function step0() {
-    assert_equals(entries.length, 1);
-    assert_true(entries[0].isVisible);
-    // This should trigger a notification on the next run.
-    occluder.style.marginTop = "-10px";
-    // Enter a rAF loop until the delay timer expires.
-    waitForDelay(false);
-  }
+  waitForNotification(t, t.step_func(step0));
 
   function waitForDelay(timerExpiredBeforeLastFrame) {
     requestAnimationFrame(t.step_func(() => {
@@ -71,5 +62,14 @@
     }));
   }
 
+  function step0() {
+    assert_equals(entries.length, 1);
+    assert_true(entries[0].isVisible);
+    // This should trigger a notification on the next run.
+    occluder.style.marginTop = "-10px";
+    // Enter a rAF loop until the delay timer expires.
+    waitForDelay(false);
+  }
+
 }, "'delay' parameter throttles frequency of notifications.");
 </script>
diff --git a/third_party/blink/web_tests/intersection-observer/v2/iframe-target.html b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/iframe-target.html
similarity index 73%
rename from third_party/blink/web_tests/intersection-observer/v2/iframe-target.html
rename to third_party/blink/web_tests/external/wpt/intersection-observer/v2/iframe-target.html
index d7cbf27..3e53ee5 100644
--- a/third_party/blink/web_tests/intersection-observer/v2/iframe-target.html
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/iframe-target.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <script src="../resources/intersection-observer-test-utils.js"></script>
 
 <style>
@@ -22,24 +22,21 @@
 <iframe srcdoc="<!DOCTYPE html><div>Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum.</div>"></iframe>
 
 <script>
+var delay = 100;
 var entries = [];
 var target;
 
-if (window.internals) {
-  internals.DisableIntersectionObserverThrottleDelay();
-}
-
 runTestCycle(function() {
   target = document.querySelector("iframe");
   assert_true(!!target, "target exists");
   var observer = new IntersectionObserver(function(changes) {
     entries = entries.concat(changes)
-  }, {trackVisibility: true, delay: 100});
+  }, {trackVisibility: true, delay: delay});
   observer.observe(target);
   entries = entries.concat(observer.takeRecords());
   assert_equals(entries.length, 0, "No initial notifications.");
-  runTestCycle(step0, "First rAF.");
-}, "IntersectionObserverV2 observing an iframe element.");
+  runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 observing an iframe element.", delay);
 
 function step0() {
   checkLastEntry(entries, 0, [0, 150, 0, 100, 0, 150, 0, 100, 0, 800, 0, 600, true, true]);
diff --git a/third_party/blink/web_tests/intersection-observer/v2/simple-effects.html b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/simple-effects.html
similarity index 75%
rename from third_party/blink/web_tests/intersection-observer/v2/simple-effects.html
rename to third_party/blink/web_tests/external/wpt/intersection-observer/v2/simple-effects.html
index 913da21..2b7a83a9 100644
--- a/third_party/blink/web_tests/intersection-observer/v2/simple-effects.html
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/simple-effects.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <script src="../resources/intersection-observer-test-utils.js"></script>
 
 <style>
@@ -28,14 +28,11 @@
 </div>
 
 <script>
+var delay = 100;
 var entries = [];
 var target;
 var effects;
 
-if (window.internals) {
-  internals.DisableIntersectionObserverThrottleDelay();
-}
-
 runTestCycle(function() {
   target = document.getElementById("target");
   effects = document.getElementById("effects");
@@ -43,28 +40,28 @@
   assert_true(!!effects, "effects exists");
   var observer = new IntersectionObserver(function(changes) {
     entries = entries.concat(changes)
-  }, {trackVisibility: true, delay: 100});
+  }, {trackVisibility: true, delay: delay});
   observer.observe(target);
   entries = entries.concat(observer.takeRecords());
   assert_equals(entries.length, 0, "No initial notifications.");
-  runTestCycle(step0, "First rAF.");
-}, "IntersectionObserverV2 in a single document using the implicit root, with a non-zero opacity ancestor.");
+  runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 in a single document using the implicit root, with a non-zero opacity ancestor.", delay);
 
 function step0() {
   effects.style.opacity = "0.99";
-  runTestCycle(step1, "effects.style.opacity = 0.99");
+  runTestCycle(step1, "effects.style.opacity = 0.99", delay);
   checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
 }
 
 function step1() {
   effects.style.opacity = "1";
-  runTestCycle(step2, "effects.style.opacity = 1");
+  runTestCycle(step2, "effects.style.opacity = 1", delay);
   checkLastEntry(entries, 1, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, false]);
 }
 
 function step2() {
   effects.style.filter = "grayscale(50%)";
-  runTestCycle(step3, "effects.style.filter = grayscale(50%)");
+  runTestCycle(step3, "effects.style.filter = grayscale(50%)", delay);
   checkLastEntry(entries, 2, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
 }
 
diff --git a/third_party/blink/web_tests/intersection-observer/v2/simple-occlusion-svg-foreign-object.html b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/simple-occlusion-svg-foreign-object.html
similarity index 78%
rename from third_party/blink/web_tests/intersection-observer/v2/simple-occlusion-svg-foreign-object.html
rename to third_party/blink/web_tests/external/wpt/intersection-observer/v2/simple-occlusion-svg-foreign-object.html
index a13938a..fcdff67 100644
--- a/third_party/blink/web_tests/intersection-observer/v2/simple-occlusion-svg-foreign-object.html
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/simple-occlusion-svg-foreign-object.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <script src="../resources/intersection-observer-test-utils.js"></script>
 
 <style>
@@ -32,14 +32,11 @@
 </svg>
 
 <script>
+var delay = 100;
 var entries = [];
 var target;
 var occluder;
 
-if (window.internals) {
-  internals.DisableIntersectionObserverThrottleDelay();
-}
-
 runTestCycle(function() {
   target = document.getElementById("target");
   occluder = document.getElementById("occluder");
@@ -47,23 +44,23 @@
   assert_true(!!occluder, "occluder exists");
   var observer = new IntersectionObserver(function(changes) {
     entries = entries.concat(changes)
-  }, {trackVisibility: true, delay: 100});
+  }, {trackVisibility: true, delay: delay});
   observer.observe(target);
   entries = entries.concat(observer.takeRecords());
   assert_equals(entries.length, 0, "No initial notifications.");
-  runTestCycle(step0, "First rAF.");
-}, "IntersectionObserverV2 in a single document using the implicit root, with an occluding element.");
+  runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 in a single document using the implicit root, with an occluding element.", delay);
 
 function step0() {
   svg.style.marginTop = "-10px";
-  runTestCycle(step1, "svg.style.marginTop = '-10px'");
+  runTestCycle(step1, "svg.style.marginTop = '-10px'", delay);
   checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
 }
 
 function step1() {
   // Occluding elements with opacity=0 should not affect target visibility.
   svg.style.opacity = "0";
-  runTestCycle(step2, "occluder.style.opacity = 0");
+  runTestCycle(step2, "occluder.style.opacity = 0", delay);
   checkLastEntry(entries, 1, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, false]);
 }
 
diff --git a/third_party/blink/web_tests/intersection-observer/v2/simple-occlusion.html b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/simple-occlusion.html
similarity index 77%
rename from third_party/blink/web_tests/intersection-observer/v2/simple-occlusion.html
rename to third_party/blink/web_tests/external/wpt/intersection-observer/v2/simple-occlusion.html
index 16f2f22..ea1ee31 100644
--- a/third_party/blink/web_tests/intersection-observer/v2/simple-occlusion.html
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/simple-occlusion.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <script src="../resources/intersection-observer-test-utils.js"></script>
 
 <style>
@@ -28,14 +28,11 @@
 <div id="occluder"></div>
 
 <script>
+var delay = 100;
 var entries = [];
 var target;
 var occluder;
 
-if (window.internals) {
-  internals.DisableIntersectionObserverThrottleDelay();
-}
-
 runTestCycle(function() {
   target = document.getElementById("target");
   occluder = document.getElementById("occluder");
@@ -43,23 +40,23 @@
   assert_true(!!occluder, "occluder exists");
   var observer = new IntersectionObserver(function(changes) {
     entries = entries.concat(changes)
-  }, {trackVisibility: true, delay: 100});
+  }, {trackVisibility: true, delay: delay});
   observer.observe(target);
   entries = entries.concat(observer.takeRecords());
   assert_equals(entries.length, 0, "No initial notifications.");
-  runTestCycle(step0, "First rAF.");
-}, "IntersectionObserverV2 in a single document using the implicit root, with an occluding element.");
+  runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 in a single document using the implicit root, with an occluding element.", delay);
 
 function step0() {
   occluder.style.marginTop = "-10px";
-  runTestCycle(step1, "occluder.style.marginTop = '-10px'");
+  runTestCycle(step1, "occluder.style.marginTop = '-10px'", delay);
   checkLastEntry(entries, 0, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, true]);
 }
 
 function step1() {
   // Occluding elements with opacity=0 should not affect target visibility.
   occluder.style.opacity = "0";
-  runTestCycle(step2, "occluder.style.opacity = 0");
+  runTestCycle(step2, "occluder.style.opacity = 0", delay);
   checkLastEntry(entries, 1, [0, 100, 0, 100, 0, 100, 0, 100, 0, 800, 0, 600, true, false]);
 }
 
diff --git a/third_party/blink/web_tests/intersection-observer/v2/text-shadow.html b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/text-shadow.html
similarity index 79%
rename from third_party/blink/web_tests/intersection-observer/v2/text-shadow.html
rename to third_party/blink/web_tests/external/wpt/intersection-observer/v2/text-shadow.html
index 6a49ae3..c6445c5 100644
--- a/third_party/blink/web_tests/intersection-observer/v2/text-shadow.html
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/v2/text-shadow.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <script src="../resources/intersection-observer-test-utils.js"></script>
 
 <style>
@@ -29,14 +29,11 @@
 <iframe id=target srcdoc="<!DOCTYPE html><div>Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum. Lorem ipsum.</div>"></iframe><div id=text-shadow>O</div>
 
 <script>
+var delay = 100;
 var entries = [];
 var target;
 var occluder;
 
-if (window.internals) {
-  internals.DisableIntersectionObserverThrottleDelay();
-}
-
 runTestCycle(function() {
   target = document.getElementById("target");
   occluder = document.getElementById("text-shadow");
@@ -44,23 +41,23 @@
   assert_true(!!occluder, "occluder exists");
   let observer = new IntersectionObserver(function(changes) {
     entries = entries.concat(changes)
-  }, {trackVisibility: true, delay: 100});
+  }, {trackVisibility: true, delay: delay});
   observer.observe(target);
   entries = entries.concat(observer.takeRecords());
   assert_equals(entries.length, 0, "No initial notifications.");
-  runTestCycle(step0, "First rAF.");
-}, "IntersectionObserverV2 observing an iframe element.");
+  runTestCycle(step0, "First rAF.", delay);
+}, "IntersectionObserverV2 observing an iframe element.", delay);
 
 function step0() {
   occluder.style.textShadow = "none";
-  runTestCycle(step1, 'occluder.style.textShadow = "none"');
+  runTestCycle(step1, 'occluder.style.textShadow = "none"', delay);
   assert_equals(entries.length, 1, "Initial notification.");
   assert_equals(entries[0].isVisible, false, "Initially occluded.");
 }
 
 function step1() {
   occluder.style.textShadow = "";
-  runTestCycle(step2, 'occluder.style.textShadow = ""');
+  runTestCycle(step2, 'occluder.style.textShadow = ""', delay);
   assert_equals(entries.length, 2, "Notification after removing text shadow.");
   assert_equals(entries[1].isVisible, true, "Visible when text shadow removed.");
 }
diff --git a/third_party/blink/web_tests/http/tests/performance-timing/layout-jank/buffer-layout-jank.html b/third_party/blink/web_tests/external/wpt/layout-stability/buffer-layout-jank.html
similarity index 94%
rename from third_party/blink/web_tests/http/tests/performance-timing/layout-jank/buffer-layout-jank.html
rename to third_party/blink/web_tests/external/wpt/layout-stability/buffer-layout-jank.html
index c9cfd05..f5818cfb 100644
--- a/third_party/blink/web_tests/http/tests/performance-timing/layout-jank/buffer-layout-jank.html
+++ b/third_party/blink/web_tests/external/wpt/layout-stability/buffer-layout-jank.html
@@ -9,7 +9,7 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <!-- Delay onload by inserting a slow image.-->
-<img src="/resources/slow-image.php?name=notthere.png&mimeType=image&sleep=3000">
+<img src="resources/slow-image.py">
 <script>
   async_test(function (t) {
     // Modify the position of the div.
diff --git a/third_party/blink/web_tests/http/tests/performance-timing/layout-jank/observe-layoutjank.html b/third_party/blink/web_tests/external/wpt/layout-stability/observe-layoutjank.html
similarity index 100%
rename from third_party/blink/web_tests/http/tests/performance-timing/layout-jank/observe-layoutjank.html
rename to third_party/blink/web_tests/external/wpt/layout-stability/observe-layoutjank.html
diff --git a/third_party/blink/web_tests/external/wpt/layout-stability/resources/slow-image.py b/third_party/blink/web_tests/external/wpt/layout-stability/resources/slow-image.py
new file mode 100644
index 0000000..ee7988c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/layout-stability/resources/slow-image.py
@@ -0,0 +1,6 @@
+import time
+
+def main(request, response):
+    # Sleep for 3s to delay onload.
+    time.sleep(3)
+    return [], ""
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/performance-timing/layout-jank/supported-layout-type.html b/third_party/blink/web_tests/external/wpt/layout-stability/supported-layout-type.html
similarity index 100%
rename from third_party/blink/web_tests/http/tests/performance-timing/layout-jank/supported-layout-type.html
rename to third_party/blink/web_tests/external/wpt/layout-stability/supported-layout-type.html
diff --git a/third_party/blink/web_tests/external/wpt/lint.whitelist b/third_party/blink/web_tests/external/wpt/lint.whitelist
index 64ff029..0d066ac 100644
--- a/third_party/blink/web_tests/external/wpt/lint.whitelist
+++ b/third_party/blink/web_tests/external/wpt/lint.whitelist
@@ -174,6 +174,7 @@
 SET TIMEOUT: html/webappapis/scripting/processing-model-2/*
 SET TIMEOUT: IndexedDB/*
 SET TIMEOUT: infrastructure/*
+SET TIMEOUT: intersection-observer/resources/v2-subframe.html
 SET TIMEOUT: intersection-observer/target-in-different-window.html
 SET TIMEOUT: media-source/mediasource-util.js
 SET TIMEOUT: media-source/URL-createObjectURL-revoke.html
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active.https-expected.txt b/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active.https-expected.txt
index 5eccd51..0d8fb1a5 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active.https-expected.txt
@@ -1,6 +1,4 @@
 This is a testharness.js-based test.
-FAIL PaymentRequest.show() aborts if the document is not active assert_throws: Inactive document, so must throw AbortError function "function() { throw e }" threw object "InvalidStateError: Already called show() once" that is not a DOMException AbortError: property "code" is equal to 11, expected 20
-FAIL PaymentRequest.show() aborts if the document is active, but not fully active promise_test: Unhandled rejection with value: object "InvalidStateError: Already called show() once"
 FAIL If a payment request is showing, but its document is navigated away (so no longer fully active), the payment request aborts. promise_test: Unhandled rejection with value: object "InvalidStateError: Already called show() once"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active.https.html b/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active.https.html
index 06c1f738..3c7e85b 100644
--- a/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active.https.html
+++ b/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active.https.html
@@ -1,12 +1,11 @@
 <!DOCTYPE html>
 <meta charset=utf-8>
-<link rel="help" href="https://w3c.github.io/payment-request/#show()-method">
 <title>PaymentRequest show() rejects if doc is not fully active</title>
+<link rel="help" href="https://w3c.github.io/payment-request/#show-method">
 <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>
-<link rel="help" href="https://w3c.github.io/payment-request/#dom-paymentrequest-show()">
 <body>
 <script>
 const applePay = Object.freeze({
@@ -54,94 +53,6 @@
   const iframe = document.createElement("iframe");
   iframe.allowPaymentRequest = true;
   document.body.appendChild(iframe);
-  // We first got to page1.html, grab a PaymentRequest instance.
-  const request1 = await getLoadedPaymentRequest(
-    iframe,
-    "/payment-request/resources/page1.html"
-  );
-  // We navigate the iframe again, putting request1's document into an inactive state.
-  const request2 = await getLoadedPaymentRequest(
-    iframe,
-    "/payment-request/resources/page2.html"
-  );
-  await test_driver.bless("show payment request", async () => {
-    // Now, request1's relevant global object's document is no longer active.
-    // So, call .show(), and make sure it rejects appropriately.
-    await promise_rejects(
-      t,
-      "AbortError",
-      request1.show(),
-      "Inactive document, so must throw AbortError"
-    );
-  });
-  await test_driver.bless("show payment request", async () => {
-    // request2 has an active document tho, so confirm it's working as expected:
-    request2.show();
-    await request2.abort();
-    await promise_rejects(
-      t,
-      "InvalidStateError",
-      request2.show(),
-      "Abort already called, so InvalidStateError"
-    );
-    // We are done, so clean up.
-    iframe.remove();
-  });
-}, "PaymentRequest.show() aborts if the document is not active");
-
-promise_test(async t => {
-  // We nest two iframes and wait for them to load.
-  const outerIframe = document.createElement("iframe");
-  outerIframe.allowPaymentRequest = true;
-  document.body.appendChild(outerIframe);
-  // Load the outer iframe (we don't care about the awaited request)
-  await getLoadedPaymentRequest(
-    outerIframe,
-    "/payment-request/resources/page1.html"
-  );
-
-  // Now we create the inner iframe
-  const innerIframe = outerIframe.contentDocument.createElement("iframe");
-  innerIframe.allowPaymentRequest = true;
-
-  // nest them
-  outerIframe.contentDocument.body.appendChild(innerIframe);
-
-  // load innerIframe, and get the PaymentRequest instance
-  const request = await getLoadedPaymentRequest(
-    innerIframe,
-    "/payment-request/resources/page2.html"
-  );
-
-  // Navigate the outer iframe to a new location.
-  // Wait for the load event to fire.
-  await new Promise(resolve => {
-    outerIframe.addEventListener("load", resolve);
-    outerIframe.src = "/payment-request/resources/page2.html";
-  });
-
-  const showPromise = await test_driver.bless("show payment request", () => {
-    return request.show();
-  });
-  // Now, request's relevant global object's document is still active
-  // (it is the active document of the inner iframe), but is not fully active
-  // (since the parent of the inner iframe is itself no longer active).
-  // So, call request.show() and make sure it rejects appropriately.
-  await promise_rejects(
-    t,
-    "AbortError",
-    showPromise,
-    "Active, but not fully active, so must throw AbortError"
-  );
-  // We are done, so clean up.
-
-  iframe.remove();
-}, "PaymentRequest.show() aborts if the document is active, but not fully active");
-
-promise_test(async t => {
-  const iframe = document.createElement("iframe");
-  iframe.allowPaymentRequest = true;
-  document.body.appendChild(iframe);
   // Make a request in the iframe.
   const request = await getLoadedPaymentRequest(
     iframe,
diff --git a/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active_manual.https.html b/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active_manual.https.html
new file mode 100644
index 0000000..f1d2fb83
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/payment-request/rejects_if_not_active_manual.https.html
@@ -0,0 +1,164 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>PaymentRequest show() rejects if doc is not fully active</title>
+<link rel="help" href="https://w3c.github.io/payment-request/#show-method">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+setup({
+  explicit_done: true,
+  explicit_timeout: true,
+});
+
+const applePay = Object.freeze({
+  supportedMethods: "https://apple.com/apple-pay",
+  data: {
+    version: 3,
+    merchantIdentifier: "merchant.com.example",
+    countryCode: "US",
+    merchantCapabilities: ["supports3DS"],
+    supportedNetworks: ["visa"],
+  }
+});
+const validMethod = Object.freeze({
+  supportedMethods: "basic-card",
+});
+const validMethods = Object.freeze([validMethod, applePay]);
+
+const validDetails = Object.freeze({
+  total: {
+    label: "Total due",
+      amount: {
+      currency: "USD",
+      value: "5.00",
+    },
+  },
+});
+
+function getLoadedPaymentRequest(iframe, url) {
+  return new Promise(resolve => {
+    iframe.addEventListener(
+      "load",
+      () => {
+        const { PaymentRequest } = iframe.contentWindow;
+        const request = new PaymentRequest(validMethods, validDetails);
+        resolve(request);
+      },
+      { once: true }
+    );
+    iframe.src = url;
+  });
+}
+
+function testAbortShowIfDocumentIsNotActive() {
+  promise_test(async t => {
+    const iframe = document.createElement("iframe");
+    iframe.allowPaymentRequest = true;
+    document.body.appendChild(iframe);
+    // We first got to page1.html, grab a PaymentRequest instance.
+    const request1 = await getLoadedPaymentRequest(
+      iframe,
+      "/payment-request/resources/page1.html"
+    );
+    // We navigate the iframe again, putting request1's document into an inactive state.
+    const request2 = await getLoadedPaymentRequest(
+      iframe,
+      "/payment-request/resources/page2.html"
+    );
+    // Now, request1's relevant global object's document is no longer active.
+    // So, call .show(), and make sure it rejects appropriately.
+    await promise_rejects(
+      t,
+      "AbortError",
+      request1.show(),
+      "Inactive document, so must throw AbortError"
+    );
+    // request2 has an active document tho, so confirm it's working as expected:
+    request2.show();
+    await request2.abort();
+    await promise_rejects(
+      t,
+      "InvalidStateError",
+      request2.show(),
+      "Abort already called, so InvalidStateError"
+    );
+    // We are done, so clean up.
+    iframe.remove();
+  }, "PaymentRequest.show() aborts if the document is not active.");
+}
+
+function testAbortShowIfDocumentIsNotFullyActive() {
+  promise_test(async t => {
+    // We nest two iframes and wait for them to load.
+    const outerIframe = document.createElement("iframe");
+    outerIframe.allowPaymentRequest = true;
+    document.body.appendChild(outerIframe);
+    // Load the outer iframe (we don't care about the awaited request)
+    await getLoadedPaymentRequest(
+      outerIframe,
+      "/payment-request/resources/page1.html"
+    );
+
+    // Now we create the inner iframe
+    const innerIframe = outerIframe.contentDocument.createElement("iframe");
+    innerIframe.allowPaymentRequest = true;
+
+    // nest them
+    outerIframe.contentDocument.body.appendChild(innerIframe);
+
+    // load innerIframe, and get the PaymentRequest instance
+    const request = await getLoadedPaymentRequest(
+      innerIframe,
+      "/payment-request/resources/page2.html"
+    );
+
+    // Navigate the outer iframe to a new location.
+    // Wait for the load event to fire.
+    await new Promise(resolve => {
+      outerIframe.addEventListener("load", resolve);
+      outerIframe.src = "/payment-request/resources/page2.html";
+    });
+
+    const showPromise = request.show();
+    // Now, request's relevant global object's document is still active
+    // (it is the active document of the inner iframe), but is not fully active
+    // (since the parent of the inner iframe is itself no longer active).
+    // So, call request.show() and make sure it rejects appropriately.
+    await promise_rejects(
+      t,
+      "AbortError",
+      showPromise,
+      "Active, but not fully active, so must throw AbortError"
+    );
+    // We are done, so clean up.
+
+    outerIframe.remove();
+  }, "PaymentRequest.show() aborts if the document is active, but not fully active.");
+}
+</script>
+
+<h2>PaymentRequest show() rejects if doc is not fully active</h2>
+<p>
+  Click on each button in sequence from top to bottom without refreshing the
+  page. Each button will bring up the Payment Request UI window and then will
+  close it automatically. (If a payment sheet stays open, the test has failed.)
+</p>
+<ol>
+  <li>
+    <button onclick="testAbortShowIfDocumentIsNotActive()">
+      PaymentRequest.show() aborts if the document is not active.
+    </button>
+  </li>
+  <li>
+    <button onclick="testAbortShowIfDocumentIsNotFullyActive()">
+      PaymentRequest.show() aborts if the document is active, but not fully
+      active.
+    </button>
+  </li>
+  <li><button onclick="done()">Done!</button></li>
+</ol>
+<small>
+  If you find a buggy test, please <a href="https://github.com/web-platform-tests/wpt/issues">file a bug</a>
+  and tag one of the <a href="https://github.com/web-platform-tests/wpt/blob/master/payment-request/META.yml">suggested reviewers</a>.
+</small>
diff --git a/third_party/blink/web_tests/fast/events/drag-nested-eventSender-use-expected.txt b/third_party/blink/web_tests/fast/events/drag-nested-eventSender-use-expected.txt
index b282d0b..381406b8 100644
--- a/third_party/blink/web_tests/fast/events/drag-nested-eventSender-use-expected.txt
+++ b/third_party/blink/web_tests/fast/events/drag-nested-eventSender-use-expected.txt
@@ -2,7 +2,7 @@
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
-PASS runTest() threw exception Error: Nested beginDragWithFiles() not supported..
+PASS runTest() threw exception Error: Nested beginDragWithFiles/beginDragWithStringData() not supported..
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/blink/web_tests/fast/workers/resources/worker-thread-multi-port.js b/third_party/blink/web_tests/fast/workers/resources/worker-thread-multi-port.js
index 27424cc..2ce7cae5 100644
--- a/third_party/blink/web_tests/fast/workers/resources/worker-thread-multi-port.js
+++ b/third_party/blink/web_tests/fast/workers/resources/worker-thread-multi-port.js
@@ -1,48 +1,43 @@
 onmessage = function(event) {
-    if (event.data == "noport") {
-        if (event.ports && !event.ports.length)
-            testPassed("event.ports is non-null and zero length when no port sent");
-        else
-            testFailed("event.ports is null or non-zero length when no port sent");
-    } else if (event.data == "zero ports") {
-        if (event.ports && !event.ports.length)
-            testPassed("event.ports is non-null and zero length when empty array sent");
-        else
-            testFailed("event.ports is null or non-zero length when empty array sent");
-    } else if (event.data == "two ports") {
-        if (!event.ports) {
-            testFailed("event.ports should be non-null when ports sent");
-            return;
-        }
-        if (event.ports.length == 2)
-            testPassed("event.ports contains two ports when two ports sent");
-        else
-            testFailed("event.ports contained " + event.ports.length + " when two ports sent");
-    } else if (event.data == "failed ports") {
-        if (event.ports.length == 2)
-            testPassed("event.ports contains two ports when two ports re-sent after error");
-        else
-            testFailed("event.ports contained " + event.ports.length + " when two ports re-sent after error");
-    } else if (event.data == "done") {
-        postMessage("done");
-        event.ports[0].postMessage("done");
-    } else if (event.data == "noargs") {
-        try {
-            postMessage();
-            testFailed("postMessage() did not throw");
-        } catch (e) {
-            testPassed("postMessage() threw exception: " + e);
-        }
-    } else
-        testFailed("Received unexpected message: " + event.data);
+  if (event.data == "noport") {
+    if (event.ports && !event.ports.length)
+      testPassed("event.ports is non-null and zero length when no port sent");
+    else
+      testFailed("event.ports is null or non-zero length when no port sent");
+  } else if (event.data == "zero ports") {
+    if (event.ports && !event.ports.length)
+      testPassed("event.ports is non-null and zero length when empty array sent");
+    else
+      testFailed("event.ports is null or non-zero length when empty array sent");
+  } else if (event.data == "two ports") {
+    if (!event.ports) {
+      testFailed("event.ports should be non-null when ports sent");
+      return;
+    }
+    if (event.ports.length == 2)
+      testPassed("event.ports contains two ports when two ports sent");
+    else
+      testFailed("event.ports contained " + event.ports.length + " when two ports sent");
+  } else if (event.data == "failed ports") {
+    if (event.ports.length == 2)
+      testPassed("event.ports contains two ports when two ports re-sent after error");
+    else
+      testFailed("event.ports contained " + event.ports.length + " when two ports re-sent after error");
+  } else if (event.data == "noargs") {
+    try {
+      postMessage();
+      testFailed("postMessage() did not throw");
+    } catch (e) {
+      testPassed("postMessage() threw exception: " + e);
+    }
+  } else
+    testFailed("Received unexpected message: " + event.data);
 };
 
-function testPassed(msg)
-{
-    postMessage("PASS"+msg);
+function testPassed(msg) {
+  postMessage("PASS"+msg);
 }
 
-function testFailed(msg)
-{
-    postMessage("FAIL"+msg);
+function testFailed(msg) {
+  postMessage("FAIL"+msg);
 }
diff --git a/third_party/blink/web_tests/fast/workers/resources/worker-timeout-cancel-order.js b/third_party/blink/web_tests/fast/workers/resources/worker-timeout-cancel-order.js
index e530f7ff..afc66cf 100644
--- a/third_party/blink/web_tests/fast/workers/resources/worker-timeout-cancel-order.js
+++ b/third_party/blink/web_tests/fast/workers/resources/worker-timeout-cancel-order.js
@@ -1,8 +1,7 @@
-self.postMessage("Test started.");
-// The test will create 3 timeouts with their intervals decreasing.
-// If the timeouts execute in order then the test is PASS.
+// The test will create 2 timeouts and cancel the first one. If only the second
+// timeout executes then the test passes.
 self.addEventListener('message', function(e) {
     var t1 = setTimeout(function () { postMessage(1); }, 5);
-    setTimeout(function () { postMessage(2); postMessage("DONE"); }, 10);
+    setTimeout(function () { postMessage(2); }, 10);
     clearTimeout(t1);
-}, false);
\ No newline at end of file
+}, false);
diff --git a/third_party/blink/web_tests/fast/workers/resources/worker-timeout-decreasing-order.js b/third_party/blink/web_tests/fast/workers/resources/worker-timeout-decreasing-order.js
index e16507a..b93dd5d 100644
--- a/third_party/blink/web_tests/fast/workers/resources/worker-timeout-decreasing-order.js
+++ b/third_party/blink/web_tests/fast/workers/resources/worker-timeout-decreasing-order.js
@@ -1,8 +1,7 @@
-self.postMessage("Test started.");
 // The test will create 3 timeouts with their intervals decreasing.
 // If the timeouts execute in order then the test is PASS.
 self.addEventListener('message', function(e) {
-    setTimeout(function () { postMessage(3); postMessage("DONE"); }, 15);
+    setTimeout(function () { postMessage(3); }, 15);
     setTimeout(function () { postMessage(2); }, 10);
     setTimeout(function () { postMessage(1); }, 5);
-}, false);
\ No newline at end of file
+}, false);
diff --git a/third_party/blink/web_tests/fast/workers/resources/worker-timeout-increasing-order.js b/third_party/blink/web_tests/fast/workers/resources/worker-timeout-increasing-order.js
index 522b051..42f81daa 100644
--- a/third_party/blink/web_tests/fast/workers/resources/worker-timeout-increasing-order.js
+++ b/third_party/blink/web_tests/fast/workers/resources/worker-timeout-increasing-order.js
@@ -1,8 +1,7 @@
-self.postMessage("Test started.");
 // The test will create 3 timeouts with their intervals increasing.
 // If the timeouts execute in order then the test is PASS.
 self.addEventListener('message', function(e) {
     setTimeout(function () { postMessage(1); }, 5);
     setTimeout(function () { postMessage(2); }, 10);
-    setTimeout(function () { postMessage(3); postMessage("DONE"); }, 15);
-}, false);
\ No newline at end of file
+    setTimeout(function () { postMessage(3); }, 15);
+}, false);
diff --git a/third_party/blink/web_tests/fast/workers/worker-close-expected.txt b/third_party/blink/web_tests/fast/workers/worker-close-expected.txt
deleted file mode 100644
index e129059..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-close-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Test WorkerContext.close functionality. Should print a series of PASS messages, followed with DONE.
-
-PASS: typeof close: function
-PASS: received message before close
-PASS: Received message posted right after close() was invoked: Should be delivered
-PASS: no messages arrive to worker after JS fragment with close() exits
-PASS: Error arrived after close: Uncaught ReferenceError: nonExistentFunction is not defined
-PASS: close() did not dispatch pending events
-PASS: Received message after worker closed: Should be delivered
-DONE
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-close.html b/third_party/blink/web_tests/fast/workers/worker-close.html
index 55dc7cb..f54af13 100644
--- a/third_party/blink/web_tests/fast/workers/worker-close.html
+++ b/third_party/blink/web_tests/fast/workers/worker-close.html
@@ -1,108 +1,66 @@
-<body>
-<p>Test WorkerContext.close functionality. Should print a series of PASS messages, followed with DONE.</p>
-<div id=result></div>
+<!DOCTYPE html>
+<title>Test WorkerGlobalScope.close functionality.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-function log(message)
-{
-    document.getElementById("result").innerHTML += message + "<br>";
-}
+setup({ allow_uncaught_exception: true });
 
-if (window.testRunner)
-{
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
+async_test(function(t) {
+  var worker = new Worker('resources/worker-close.js');
+  worker.postMessage("typeofClose");
+    worker.onmessage = t.step_func_done(function(evt) {
+    assert_equals(evt.data, "typeof close: function");
+    });
+}, 'Test type of close function.');
 
-var worker = new Worker('resources/worker-close.js');
-var timeout = 0;
-
-worker.postMessage("typeofClose");
-worker.onmessage = testTypeofClose;
-
-function testTypeofClose(evt)
-{
-    if (evt.data == "typeof close: function")
-        log("PASS: " + evt.data);
-    else
-        log("FAIL: " + evt.data);
-    worker.onmessage = testMessageAfterClose;
-    worker.postMessage("ping");
-}
-
-function testMessageAfterClose(evt) {
-    if (evt.data == "pong")
-        log("PASS: received message before close");
-    else
-        log("FAIL: received unknown response: " + evt.data);
-
-    // Tell the worker to close, then send a followup message. This message should not be delivered,
-    // since that would require JS to invoke the onmessage handler, which does not happen after the JS
-    // fragment with 'close()' in it exits. So, the 'ping' should not come back as 'pong'.
+async_test(function(t) {
+  var worker = new Worker('resources/worker-close.js');  
+  worker.postMessage("ping");
+    worker.onmessage = t.step_func(function(evt) {
+    assert_equals(evt.data, "pong");
+    // Tell the worker to close, then send a followup message. This message
+    // should not be delivered, since that would require JS to invoke the
+    //  onmessage handler, which does not happen after the JS fragment with
+    // 'close()' in it exits. So, the 'ping' should not come back as 'pong'.
     worker.postMessage("close");
     worker.postMessage("ping");
-    worker.onmessage = function(evt) {
-        if (evt.data != "pong") {
-            log("PASS: Received message posted right after close() was invoked: " + evt.data);
-            timeout = setTimeout(testErrorAfterClose, 1000);
-        } else {
-            log("FAIL: Received a message originated from a handler in the worker after the JS fragment with close() exited" + evt.data);
-            done();
-        }
-    };
-}
+      worker.onmessage = t.step_func(function(evt) {
+      assert_not_equals(evt.data, "pong");
+      t.step_timeout(function() { t.done(); }, 500);
+    });
+  });
+}, 'Test sending a message after closing.');
 
-function testErrorAfterClose()
-{
-    log("PASS: no messages arrive to worker after JS fragment with close() exits");
-    // Test that errors are delivered after close.
-    worker = new Worker('resources/worker-close.js');
-    worker.postMessage("closeWithError");
-    worker.onerror = function(event) {
-        log("PASS: Error arrived after close: " + event.message);
-        testPendingEvents();
-        return false;
-    }
-}
+async_test(function(t) {
+  var worker = new Worker('resources/worker-close.js');
+  worker.postMessage("closeWithError");
+  worker.onerror = function(event) {
+    t.done()
+  };
+}, 'Test errors are delivered after close.');
 
-function testPendingEvents()
-{
-    // Now test that workers do not deliver pending events
-    worker = new Worker('resources/worker-close.js');
-    worker.postMessage("closeWithPendingEvents");
-    worker.onmessage = function(evt) {
-        log("FAIL: pending events should not fire:" + evt.data);
-        done();
-    }
-    worker.onerror = function(evt) {
-        log("FAIL: pending events should not fire:" + evt.message);
-        done();
-    }
-    timeout = setTimeout(testTerminateAfterClose, 500);
-}
+async_test(function(t) {
+  var worker = new Worker('resources/worker-close.js');
+  worker.postMessage("closeWithPendingEvents");
+  worker.onmessage = t.step_func(function(evt) {
+    assert_unreached("Pending events should not fire: " + evt.data);
+  });
+  worker.onerror = t.step_func(function(evt) {
+    assert_unreached("Pending events should not fire:" + evt.message);
+  });
+  t.step_timeout(function() { t.done(); }, 500);
+}, 'Test workers do not deliver pending events.');
 
-function testTerminateAfterClose()
-{
-    log("PASS: close() did not dispatch pending events");
-    worker = new Worker('resources/worker-close.js');
-    worker.postMessage("close");
-    worker.onmessage = function(evt) {
-        log("PASS: Received message after worker closed: " + evt.data);
-        // Give worker a chance to close first, then terminate it.
-        timeout = setTimeout(function() {
-            worker.terminate();
-            done();
-        }, 500);
-    };
-}
-
-function done() {
-    if (timeout)
-        clearTimeout(timeout);
-    log("DONE");
-    if (window.testRunner)
-        testRunner.notifyDone();
-}
+async_test(function(t) {
+  var worker = new Worker('resources/worker-close.js');
+  worker.postMessage("close");
+  worker.onmessage = function(evt) {
+    assert_equals(evt.data, "Should be delivered");
+    // Give worker a chance to close first, then terminate it.
+    t.step_timeout(function() {
+      worker.terminate();
+      t.done();
+    }, 500);
+  };
+}, 'Test terminating a worker after close.');
 </script>
-</body>
-</html>
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-constructor-expected.txt b/third_party/blink/web_tests/fast/workers/worker-constructor-expected.txt
deleted file mode 100644
index 708955f..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-constructor-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Test Worker constructor functionality. Should print a series of PASS messages, followed with DONE.
-
-PASS: toString exception propagated correctly.
-PASS: trying to create workers recursively resulted in an exception (RangeError: Maximum call stack size exceeded)
-PASS: invoking Worker constructor without arguments resulted in an exception (TypeError: Failed to construct 'Worker': 1 argument required, but only 0 present.)
-PASS: onerror invoked for an empty script URL, resolving to this HTML document's URL.
-PASS: invoking Worker constructor with invalid script URL resulted in an exception (SyntaxError: Failed to construct 'Worker': 'http://invalid:123$' is not a valid URL.)
-PASS: onerror invoked for a script that could not be loaded.
-PASS: Successfully created worker.
-DONE
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-constructor.html b/third_party/blink/web_tests/fast/workers/worker-constructor.html
index 38f5423..7b554848 100644
--- a/third_party/blink/web_tests/fast/workers/worker-constructor.html
+++ b/third_party/blink/web_tests/fast/workers/worker-constructor.html
@@ -1,138 +1,59 @@
-<body>
-<p>Test Worker constructor functionality. Should print a series of PASS messages, followed with DONE.</p>
-<div id=result></div>
+<!DOCTYPE html>
+<title>Test Worker constructor functionality.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-function log(message)
-{
-    document.getElementById("result").innerHTML += message + "<br>";
-}
 
-var testCases = [
-    "testArgumentException",
-    "testRecursiveWorkerCreation",
-    "testNoArgument",
-    "testEmptyScriptUrl",
-    "testInvalidScriptUrl",
-    "testNotExistentScriptUrl",
-    "testSuccessWorkerCreation",
-];
-var testIndex = 0;
+test(() => {
+  assert_throws(new Error(),
+                function() {
+                    new Worker({toString:function(){throw new Error()}})},
+                'toString exception should be propagated');
+}, 'Test toString propagation exception.');
 
-function runNextTest()
-{
-    if (testIndex < testCases.length) {
-        testIndex++;
-        window[testCases[testIndex - 1]]();
-    } else {
-        log("DONE");
-        if (window.testRunner)
-            testRunner.notifyDone();
-    }
-}
+test(() => {
+  try {
+    var foo = {toString:function(){new Worker(foo)}};
+    new Worker(foo);
+  } catch(ex) {
+    assert_true(true, 'trying to create workers recursively should result in an: ' +
+                ex + 'exception.')
+  }
+}, 'Test recursive Worker creation.');
 
-function testArgumentException()
-{
-    try {
-        new Worker({toString:function(){throw "exception"}})
-        log("FAIL: toString exception not propagated.");
-    } catch (ex) {
-        if (ex == "exception")
-            log("PASS: toString exception propagated correctly.");
-        else
-            log("FAIL: unexpected exception (" + ex + ") received instead of one propagated from toString.");
-    }
-    runNextTest();
-}
+test(() => {
+  assert_throws(new TypeError(),
+                function() { new Worker(); },
+                'invoking Worker constructor without arguments should result' +
+                'in an exception.')
+}, 'Test worker creation with no arguments');
 
-function testRecursiveWorkerCreation()
-{
-    try {
-        var foo = {toString:function(){new Worker(foo)}}
-        new Worker(foo);
-        log("FAIL: no exception when trying to create workers recursively");
-    } catch (ex) {
-        log("PASS: trying to create workers recursively resulted in an exception (" + ex + ")");
-    }
-    runNextTest();
-}
+async_test(t => {
+  var worker = new Worker('');
+  worker.onerror = function(e) {
+      t.done();
+  }
+}, 'Test Worker creation with empty script URL.');
 
-function testNoArgument()
-{
-    try {
-        new Worker();
-        log("FAIL: invoking Worker constructor without arguments did not result in an exception");
-    } catch (ex) {
-        log("PASS: invoking Worker constructor without arguments resulted in an exception (" + ex + ")");
-    }
-    runNextTest();
-}
+test(() => {
+  assert_throws(new SyntaxError(),
+                function() { var worker = new Worker('http://invalid:123$'); },
+                'Invoking Worker constructor with invalid script URL should' +
+                'result in an exception.');
+}, 'Test invalid script URL.');
 
-function testEmptyScriptUrl()
-{
-    try {
-        var worker = new Worker("");
-        worker.onerror = function(e) {
-            log("PASS: onerror invoked for an empty script URL, resolving to this HTML document's URL.");
-            e.preventDefault();
-            runNextTest();
-        }
-    } catch (ex) {
-        log("FAIL: invoking Worker constructor with empty script URL resulted in a exception (" + ex + ")");
-        runNextTest();
-    }
-}
+async_test(t => {
+  var worker = new Worker('does-not-exist.js');
+  worker.onerror = function(e) {
+    t.done();
+  }
+}, 'Test not existent script URL.');
 
-function testInvalidScriptUrl()
-{
-    try {
-        var worker = new Worker("http://invalid:123$");
-        worker.onerror = function() {
-            log("FAIL: onerror invoked for an invalid script URL.");
-            runNextTest();
-        }
-    } catch (ex) {
-        log("PASS: invoking Worker constructor with invalid script URL resulted in an exception (" + ex + ")");
-        runNextTest();
-    }
-}
-
-function testNotExistentScriptUrl()
-{
-    try {
-        var worker = new Worker("does-not-exist.js");
-        worker.onerror = function() {
-            log("PASS: onerror invoked for a script that could not be loaded.");
-            runNextTest();
-        }
-    } catch (ex) {
-        log("FAIL: unexpected exception " + ex);
-        runNextTest();
-    }
-}
-
-function testSuccessWorkerCreation()
-{
-    try {
-        var worker = new Worker("resources/worker-common.js");
-        // Make sure attributes from both Worker and AbstractWorker are visible.
-        if (!worker.postMessage)
-            log("FAIL: worker.postMessage did not exist.");
-        else if (!worker.addEventListener)
-            log("FAIL: worker.addEventListener did not exist.");
-        else
-            log("PASS: Successfully created worker.");
-    } catch (ex) {
-        log("FAIL: unexpected exception (" + ex + ") thrown when creating worker");
-    }
-    runNextTest();
-}
-
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
-
-runNextTest();
-
+test(() => {
+  var worker = new Worker('resources/worker-common.js');
+  assert_true('postMessage' in worker,
+              'worker.postMessage did not exist.');
+  assert_true('addEventListener' in worker,
+              'worker.addEventListener did not exist.');
+}, 'Test the Worker object defines postMessage() and addEventListener().');
 </script>
-</body>
diff --git a/third_party/blink/web_tests/fast/workers/worker-messageport-expected.txt b/third_party/blink/web_tests/fast/workers/worker-messageport-expected.txt
deleted file mode 100644
index 906b6b80a..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-messageport-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Test that pages and workers can send MessagePorts to one another. Should print "DONE" when done.
-
-PASS: evt.ports = [] as expected
-PASS: Received message port
-PASS: Received response from Worker via MessagePort
-PASS: Got port from worker
-PASS: Received final response from worker
-PASS: Got 1000 messages
-DONE
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-messageport.html b/third_party/blink/web_tests/fast/workers/worker-messageport.html
index aa81d7c..1c59195e 100644
--- a/third_party/blink/web_tests/fast/workers/worker-messageport.html
+++ b/third_party/blink/web_tests/fast/workers/worker-messageport.html
@@ -1,100 +1,69 @@
-<body>
-<p>Test that pages and workers can send MessagePorts to one another.
-Should print "DONE" when done.</p>
-<div id=result></div>
+<!DOCTYPE html>
+<title>Test that pages and workers can send MessagePorts to one another.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-function log(message)
-{
-    document.getElementById("result").innerHTML += message + "<br>";
-}
+async_test(function(t) {
+  var worker = new Worker("resources/worker-messageport.js");
 
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
+  // Send messages with and without ports to the worker to make sure it gets them.
+  worker.postMessage("noport");
+  worker.onmessage = t.step_func_done(evt => {
+    assert_equals(evt.data, "PASS: evt.ports = [] as expected");
+  });
+}, 'Test sending messages to workers with no port.');
 
-var worker = new Worker("resources/worker-messageport.js");
-var channel = new MessageChannel();
+async_test(function(t) {
+  var worker = new Worker("resources/worker-messageport.js");
+  var channel = new MessageChannel();
 
-// Send messages with and without ports to the worker to make sure it gets them.
-worker.postMessage("noport");
-worker.onmessage = function(evt) {
-    log(evt.data);
-    worker.postMessage("port", [channel.port1]);
-    worker.onmessage = function(evt) {
-        log(evt.data);
-    }
-};
+  worker.postMessage("port", [channel.port1]);
+  worker.onmessage = t.step_func(evt => {
+    assert_equals(evt.data, "PASS: Received message port");
+  });
 
-// Send a message on the new port to make sure it gets to the worker.
-channel.port2.postMessage("ping");
+  // Send a message on the new port to make sure it gets to the worker.
+  channel.port2.postMessage("ping");
 
-// Wait for the response.
-channel.port2.onmessage = function(evt) {
-    if (evt.data == "pong") {
-        log("PASS: Received response from Worker via MessagePort");
-        worker.onmessage = awaitPortFromWorker;
-        worker.postMessage("getport");
-    } else {
-        log("FAIL: Received unknown event: " + evt.data);
-    }
-}
-channel.port2.start();
+  // Wait for the response.
+  channel.port2.onmessage = t.step_func_done(evt => {
+    assert_equals(evt.data, "pong");
+  });
+  channel.port2.start();
+}, 'Test sending message to a worker on a port.');
 
-// Invoked once the first batch of tests are done, to test sending from the worker.
-function awaitPortFromWorker(evt)
-{
-    if (evt.data == "port") {
-        if (!evt.ports) {
-            log("FAIL: Did not get port from worker");
-        } else if (evt.ports.length != 1) {
-            log("FAIL: Got the wrong number of ports from worker: " + evt.ports.length);
-        } else {
-            log("PASS: Got port from worker");
-            evt.ports[0].postMessage("ping");
-            evt.ports[0].onmessage = function(evt) {
-                if (evt.data == "pong") {
-                    log("PASS: Received final response from worker");
-                } else {
-                    log("FAIL: Got unexpected response: " + evt.data);
-                }
-                startSpamTest();
-            }
-            evt.ports[0].start();
-        }
-    } else {
-        log(evt.data);
-    }
-}
+async_test(function(t) {
+  var worker = new Worker("resources/worker-messageport.js");
+  var channel = new MessageChannel();
 
-function startSpamTest()
-{
-    var channel = new MessageChannel();
-    worker.onmessage = function () { gotSpam(channel.port1); }
-    worker.postMessage("spam", [channel.port2]);
-}
+  worker.onmessage = t.step_func(evt => {
+    assert_equals(evt.data, "port");
+    assert_equals(String(evt.ports), "[object MessagePort]");
+    assert_equals(evt.ports.length, 1);
+    evt.ports[0].postMessage("ping");
+    evt.ports[0].onmessage = t.step_func_done(evt => {
+      assert_equals(evt.data, "pong");
+    });
+    evt.ports[0].start();
+  });
+  worker.postMessage("getport");
+}, 'Test getting messages from a worker on a port.');
 
-function gotSpam(port)
-{
+async_test(function(t) {
+  var worker = new Worker("resources/worker-messageport.js");
+  var channel = new MessageChannel();
+  worker.onmessage = t.step_func(evt => { gotSpam(channel.port1); });
+  worker.postMessage("spam", [channel.port2]);
+
+  function gotSpam(port) {
     var spamCount = 0;
-    port.onmessage = function(evt) {
-        if (evt.data != spamCount)
-            log("FAIL: Got out of order message: " + spamCount);
-        spamCount++;
-        if (spamCount == 1000) {
-            log("PASS: Got 1000 messages");
-            done();
-        }
-    }
-}
-
-function done()
-{
-    log("DONE");
-    if (window.testRunner)
-        testRunner.notifyDone();
-}
-
+    port.onmessage = t.step_func(evt => {
+      assert_equals(evt.data, spamCount);
+      spamCount++;
+      if (spamCount == 1000) {
+        t.done();
+      }
+    });
+  }
+}, 'Test sending many messages to workers using ports.');
 </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/fast/workers/worker-multi-port-expected.txt b/third_party/blink/web_tests/fast/workers/worker-multi-port-expected.txt
deleted file mode 100644
index edd4cbf..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-multi-port-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-This test checks the various use cases around sending multiple ports through Worker.postMessage
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS worker.postMessage() threw exception TypeError: Failed to execute 'postMessage' on 'Worker': 1 argument required, but only 0 present..
-PASS worker.postMessage("null port", [channel3.port1, null, channel3.port2]) threw exception TypeError: Failed to execute 'postMessage' on 'Worker': Value at index 1 is an untransferable 'null' value..
-PASS worker.postMessage("notAPort", [channel3.port1, {}, channel3.port2]) threw exception TypeError: Failed to execute 'postMessage' on 'Worker': Value at index 1 does not have a transferable type..
-PASS worker.postMessage("notASequence", [{length: 3}]) threw exception TypeError: Failed to execute 'postMessage' on 'Worker': Value at index 0 does not have a transferable type..
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
-PASS postMessage() threw exception: TypeError: Failed to execute 'postMessage' on 'DedicatedWorkerGlobalScope': 1 argument required, but only 0 present.
-PASS event.ports is non-null and zero length when no port sent
-PASS event.ports is non-null and zero length when empty array sent
-PASS event.ports contains two ports when two ports sent
-PASS event.ports contains two ports when two ports re-sent after error
-
-TEST COMPLETE
diff --git a/third_party/blink/web_tests/fast/workers/worker-multi-port.html b/third_party/blink/web_tests/fast/workers/worker-multi-port.html
index 9efcd645..1a721f2 100644
--- a/third_party/blink/web_tests/fast/workers/worker-multi-port.html
+++ b/third_party/blink/web_tests/fast/workers/worker-multi-port.html
@@ -1,7 +1,86 @@
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<script src="resources/worker-util.js"></script>
-<script src="resources/worker-multi-port.js"></script>
-</body>
+<!DOCTYPE html>
+<title>Test sending multiple ports through Worker.postMessage.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+async_test(function(t) {
+  var worker = new Worker("resources/worker-thread-multi-port.js");
+  worker.onmessage = t.step_func_done(function(evt) {
+    assert_true(evt.data.startsWith('PASS'));
+  });
+  worker.postMessage("noport");
+}, 'Test postMessage with no port.');
+
+async_test(function(t) {
+  var worker = new Worker("resources/worker-thread-multi-port.js");
+  worker.onmessage = t.step_func_done(function(evt) {
+    assert_true(evt.data.startsWith('PASS'));
+  });
+  worker.postMessage("noargs");
+}, 'Test postMessage with no arguments.');
+
+async_test(function(t) {
+  var worker = new Worker("resources/worker-thread-multi-port.js");
+  worker.onmessage = t.step_func_done(function(evt) {
+    assert_true(evt.data.startsWith('PASS'));
+  });
+  worker.postMessage("zero ports", []);
+}, 'Test postMessage with no ports and empty array.');
+
+async_test(function(t) {
+  var worker = new Worker("resources/worker-thread-multi-port.js");
+  var channel = new MessageChannel();
+  worker.onmessage = t.step_func_done(function(evt) {
+    assert_true(evt.data.startsWith('PASS'));
+  });
+  worker.postMessage("two ports", [channel.port1, channel.port2]);
+}, 'Test postMessage with two ports.');
+
+test(() => {
+  var worker = new Worker("resources/worker-thread-multi-port.js");
+  assert_throws(new TypeError(),
+                function() { worker.postMessage(); },
+                'Empty postMessage should throw exception.');
+}, 'Test empty postMessage throws exception.');
+
+test(() => {
+  var worker = new Worker("resources/worker-thread-multi-port.js");
+  var channel = new MessageChannel();
+  assert_throws(new TypeError(),
+                function() { worker.postMessage("null port",
+                                                [channel.port1, null,
+                                                 channel.port2]); },
+                'postMessage with null ports should throw exception.');
+}, 'Test postMessage with null ports throws exception.');
+
+test(() => {
+  var worker = new Worker("resources/worker-thread-multi-port.js")
+  var channel = new MessageChannel();
+  assert_throws(new TypeError(),
+                function() { worker.postMessage("notAPort",
+                                                [channel.port1, {},
+                                                 channel.port2]); },
+                'postMessage with incorrect ports should throw exception.');
+}, 'Test postMessage with incorrect ports throws exception');
+
+test(() => {
+  var worker = new Worker("resources/worker-thread-multi-port.js");
+  assert_throws(new TypeError(),
+                function() { worker.postMessage("notASequence", [{length: 3}]) },
+                'postMessage without sequence should throw exception.');
+}, 'Test postMessage without sequence throws exception');
+
+async_test(function(t) {
+  var worker = new Worker("resources/worker-thread-multi-port.js");
+  var channel = new MessageChannel();
+  assert_throws(new TypeError(),
+                function() { worker.postMessage("notAPort",
+                                                [channel.port1, {},
+                                                 channel.port2]); },
+                'postMessage with incorrect ports should throw exception.');
+  worker.onmessage = t.step_func_done(function(evt) {
+    assert_true(evt.data.startsWith('PASS'));
+  });
+  worker.postMessage("failed ports", [channel.port1, channel.port2]);
+}, 'Test postMessage on channel with previous failed postMessage calls.');
+</script>
diff --git a/third_party/blink/web_tests/fast/workers/worker-nested-importScripts-error-expected.txt b/third_party/blink/web_tests/fast/workers/worker-nested-importScripts-error-expected.txt
deleted file mode 100644
index bcf9af0c1a..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-nested-importScripts-error-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-This tests that errors from nested importScripts have the expected provenance.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-Starting worker: resources/importScripts-1.js
-PASS event.type is "error"
-PASS event.filename.indexOf('invalidScript.js') >= 0 is true
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-nested-importScripts-error.html b/third_party/blink/web_tests/fast/workers/worker-nested-importScripts-error.html
index 49cdacc..61cdf4c7 100644
--- a/third_party/blink/web_tests/fast/workers/worker-nested-importScripts-error.html
+++ b/third_party/blink/web_tests/fast/workers/worker-nested-importScripts-error.html
@@ -1,22 +1,17 @@
 <!DOCTYPE html>
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
+<title>This tests that errors from nested importScripts have the expected provenance.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-description("This tests that errors from nested importScripts have the expected provenance.");
+promise_test(t => {
+  let worker;
 
-self.jsTestIsAsync = true;
-
-var worker = startWorker("resources/importScripts-1.js");
-var event;
-worker.onerror = function (e) {
-    event = e;
-    shouldBeEqualToString("event.type", "error");
-    shouldBeTrue("event.filename.indexOf('invalidScript.js') >= 0");
-    finishJSTest();
-};
+  return new Promise((resolve) => {
+    worker = new Worker("resources/importScripts-1.js");
+    worker.onerror = resolve;
+  }).then(e => {
+    assert_equals(e.type, "error");
+    assert_true(e.filename.indexOf('invalidScript.js') >= 0);
+  });
+}, 'Tests that errors from the import scripts come from the expected file.')
 </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/fast/workers/worker-structure-message-expected.txt b/third_party/blink/web_tests/fast/workers/worker-structure-message-expected.txt
deleted file mode 100644
index de7381f9..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-structure-message-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-Test that pages and workers can send Structure Message to one another.
-
-On success, you will see a series of "PASS" messages, followed by "DONE".
-
-PASS: Worker receives correct structure message.
-PASS: Receive correct structure message from Worker.
-DONE
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-structure-message.html b/third_party/blink/web_tests/fast/workers/worker-structure-message.html
index 10749af..200f863 100644
--- a/third_party/blink/web_tests/fast/workers/worker-structure-message.html
+++ b/third_party/blink/web_tests/fast/workers/worker-structure-message.html
@@ -1,53 +1,27 @@
 <!DOCTYPE html>
-<html>
-<body>
-<p>Test that pages and workers can send Structure Message to one another.</p>
-<p>On success, you will see a series of "PASS" messages, followed by "DONE".</p>
-<div id=result></div>
+<title>Test that pages and workers can send Structure Message to one another.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-function log(message)
-{
-    document.getElementById("result").innerHTML += message + "<br>";
-}
+promise_test(t => {
+  let worker;
 
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
-
-var worker = new Worker("resources/worker-structure-message.js");
-worker.onmessage = function(evt) {
-    log(evt.data);
-    if (evt.data.indexOf("FAIL") == 0) {
-        done();
-    }
-    worker.onmessage = function(evt) {
-        if (evt.data.operation == 'find-edges' &&
-            ArrayBuffer.prototype.isPrototypeOf(evt.data.input) &&
-            evt.data.input.byteLength == 20 &&
-            evt.data.threshold == 0.6) {
-                log("PASS: Receive correct structure message from Worker.");
-        }
-        else
-            log("FAIL: Receive error structure message from Worker.");
-        done();
-    }
-}
-
-var buf = new ArrayBuffer(20);
-worker.postMessage({
-    operation: 'find-edges',
-    input: buf,
-    threshold: 0.6
-});
-
-function done()
-{
-    log("DONE");
-    if (window.testRunner)
-        testRunner.notifyDone();
-}
-
+  return new Promise(resolve => {
+    worker = new Worker("resources/worker-structure-message.js");
+    worker.onmessage = resolve;
+    worker.postMessage({
+      operation: 'find-edges',
+      input: new ArrayBuffer(20),
+      threshold: 0.6
+    });
+  }).then(evt => {
+    assert_false(evt.data.startsWith('FAIL'));
+    return new Promise(resolve => worker.onmessage = resolve);
+  }).then(evt => {
+    assert_equals(evt.data.operation, 'find-edges');
+    assert_true(ArrayBuffer.prototype.isPrototypeOf(evt.data.input));
+    assert_equals(evt.data.input.byteLength, 20);
+    assert_equals(evt.data.threshold, 0.6);
+  });
+}, 'Tests sending structure message to/from worker.');
 </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/fast/workers/worker-terminate-forever-expected.txt b/third_party/blink/web_tests/fast/workers/worker-terminate-forever-expected.txt
deleted file mode 100644
index be53ddf3..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-terminate-forever-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-Test Worker.terminate() for a worker that tries to run forever.
diff --git a/third_party/blink/web_tests/fast/workers/worker-terminate-forever.html b/third_party/blink/web_tests/fast/workers/worker-terminate-forever.html
index e3ca759..cd6db3e 100644
--- a/third_party/blink/web_tests/fast/workers/worker-terminate-forever.html
+++ b/third_party/blink/web_tests/fast/workers/worker-terminate-forever.html
@@ -1,11 +1,11 @@
-<body>
-<p>Test Worker.terminate() for a worker that tries to run forever.</p>
+<!DOCTYPE html>
+<title>Test Worker.terminate() for a worker that tries to run forever.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-if (window.testRunner)
-    testRunner.dumpAsText();
-
-var worker = new Worker('resources/worker-run-forever.js');
-worker.terminate();
+test((t) => {
+  var worker = new Worker('resources/worker-run-forever.js');
+  worker.terminate();
+  t.step_timeout(function() { t.done(); }, 500);
+}, 'Tests terminating a worker that is trying to run forever.');
 </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/fast/workers/worker-timeout-cancel-order-expected.txt b/third_party/blink/web_tests/fast/workers/worker-timeout-cancel-order-expected.txt
deleted file mode 100644
index 06d670f..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-timeout-cancel-order-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Test setTimeOut,cancelTimeout in Web Workers.
-
-Test started.
-PASS: Timeout canceled.
-DONE.
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-timeout-cancel-order.html b/third_party/blink/web_tests/fast/workers/worker-timeout-cancel-order.html
index aa70fdf5..f15d51c 100644
--- a/third_party/blink/web_tests/fast/workers/worker-timeout-cancel-order.html
+++ b/third_party/blink/web_tests/fast/workers/worker-timeout-cancel-order.html
@@ -1,41 +1,17 @@
 <!DOCTYPE html>
-<html>
-<body>
-<p>Test setTimeOut,cancelTimeout in Web Workers.</p>
-<div id="result"></div>
-<script type="text/javascript">
-function log(message)
-{
-    document.getElementById("result").innerHTML += message + "</br>";
-}
+<title>Test setTimeOut,cancelTimeout in Web Workers.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+promise_test(t => {
+  let worker
 
-if (window.testRunner) {
-   testRunner.dumpAsText();
-   testRunner.waitUntilDone();
-}
-
-var worker = new Worker('resources/worker-timeout-cancel-order.js');
-var testAlreadyFailed = false;
-
-worker.postMessage("TS");
-
-worker.onmessage = function(evt) {
-    if (evt.data == "DONE") {
-        log("DONE.");
-        if (window.testRunner)
-            testRunner.notifyDone();
-    }
-    if(2 == evt.data && !testAlreadyFailed) {
-        log("PASS: Timeout canceled.");
-    }
-    else if(1 == evt.data) {
-        testAlreadyFailed = true;
-        log("FAIL: Timeout did not cancel.");
-    }
-    if(evt.data == "Test started.") {
-        log(evt.data);
-    }
-}
+  return new Promise(resolve => {
+    worker = new Worker('resources/worker-timeout-cancel-order.js');
+    worker.postMessage('start');
+    worker.onmessage = resolve;
+  }).then(evt => {
+    assert_equals(evt.data, 2, 'Timeout not canceled');
+  });
+}, 'Tests setting and canceling timeout in workers.');
 </script>
-</body>
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/workers/worker-timeout-decreasing-order-expected.txt b/third_party/blink/web_tests/fast/workers/worker-timeout-decreasing-order-expected.txt
deleted file mode 100644
index 3e57e03..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-timeout-decreasing-order-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Test setTimeOut,fired in decreasing order in Web Workers.
-
-Test started.
-PASS: Timeouts executed in order.
-DONE.
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-timeout-decreasing-order.html b/third_party/blink/web_tests/fast/workers/worker-timeout-decreasing-order.html
index 14257bc..da4056c 100644
--- a/third_party/blink/web_tests/fast/workers/worker-timeout-decreasing-order.html
+++ b/third_party/blink/web_tests/fast/workers/worker-timeout-decreasing-order.html
@@ -1,56 +1,23 @@
 <!DOCTYPE html>
-<html>
-<body>
-<p>Test setTimeOut,fired in decreasing order in Web Workers.</p>
-<div id="result"></div>
-<script type="text/javascript">
-function log(message)
-{
-    document.getElementById("result").innerHTML += message + "</br>";
-}
-
-if (window.testRunner) {
-   testRunner.dumpAsText();
-   testRunner.waitUntilDone();
-}
-
-var worker = new Worker('resources/worker-timeout-decreasing-order.js');
-// Start the first test of settimeout's
-var lastTestResult = 0;
-var testCounterLimit = 3;
-var timerLimit = 3;
-var testStarted = false;
-var testAlreadyFailed = false;
-
-worker.postMessage("TS");
-
-worker.onmessage = function(evt) {
-    if(testStarted) {
-        var currentNum = evt.data;
-        if(lastTestResult == currentNum - 1 && !testAlreadyFailed) {
-            lastTestResult = currentNum;
-            --timerLimit;
-            // we got all the results in order
-            if(lastTestResult == testCounterLimit && timerLimit == 0)
-                log("PASS: Timeouts executed in order.");
-        }
-        else {
-            testAlreadyFailed = true;
-            --timerLimit;
-            if(timerLimit == 0)
-                log("FAIL: Timeouts executed out of order.");
-        }
-    }
-    if(evt.data == "Test started.") {
-        log(evt.data);
-        testStarted = true;
-    }
-    if (evt.data == "DONE") {
-        log("DONE.");
-        if (window.testRunner)
-            testRunner.notifyDone();
-    } 
-}
+<title>Test setTimeOut,fired in decreasing order in Web Workers.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+promise_test (t => {
+  let worker;
+    
+  return new Promise(resolve => {
+    worker = new Worker('resources/worker-timeout-decreasing-order.js');
+    worker.postMessage('start');
+    worker.onmessage = resolve;
+  }).then(evt => {
+    assert_equals(evt.data, 1);
+    return (new Promise(resolve => worker.onmessage = resolve));
+  }).then(evt => {
+    assert_equals(evt.data, 2);
+    return (new Promise(resolve => worker.onmessage = resolve));
+  }).then(evt => {
+    assert_equals(evt.data, 3);
+  });
+}, 'Tests timeouts on the worker are fired in decreasing order.');
 </script>
-</body>
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/workers/worker-timeout-increasing-order-expected.txt b/third_party/blink/web_tests/fast/workers/worker-timeout-increasing-order-expected.txt
deleted file mode 100644
index 96299ea..0000000
--- a/third_party/blink/web_tests/fast/workers/worker-timeout-increasing-order-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Test setTimeOut,fired in increasing order in Web Workers.
-
-Test started.
-PASS: Timeouts executed in order.
-DONE.
-
diff --git a/third_party/blink/web_tests/fast/workers/worker-timeout-increasing-order.html b/third_party/blink/web_tests/fast/workers/worker-timeout-increasing-order.html
index 3c40a306..3e44116 100644
--- a/third_party/blink/web_tests/fast/workers/worker-timeout-increasing-order.html
+++ b/third_party/blink/web_tests/fast/workers/worker-timeout-increasing-order.html
@@ -1,55 +1,23 @@
 <!DOCTYPE html>
-<html>
-<body>
-<p>Test setTimeOut,fired in increasing order in Web Workers.</p>
-<div id="result"></div>
-<script type="text/javascript">
-function log(message)
-{
-    document.getElementById("result").innerHTML += message + "</br>";
-}
+<title>Test setTimeOut,fired in increasing order in Web Workers.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+promise_test (t => {
+  let worker;
 
-if (window.testRunner) {
-   testRunner.dumpAsText();
-   testRunner.waitUntilDone();
-}
-
-var worker = new Worker('resources/worker-timeout-increasing-order.js');
-var lastTestResult = 0;
-var testCounterLimit = 3;
-var timerLimit = 3;
-var testStarted = false;
-var testAlreadyFailed = false;
-
-worker.postMessage("TS");
-
-worker.onmessage = function(evt) {
-    if(testStarted) {
-        var currentNum = evt.data;
-        if(lastTestResult == currentNum - 1 && !testAlreadyFailed) {
-            lastTestResult = currentNum;
-            --timerLimit;
-            // we got all the results in order
-            if(lastTestResult == testCounterLimit && timerLimit == 0)
-                log("PASS: Timeouts executed in order.");
-        }
-        else {
-            testAlreadyFailed = true;
-            --timerLimit;
-            if(timerLimit == 0)
-                log("FAIL: PASS: Timeouts executed out of order.");
-        }
-    }
-    if(evt.data == "Test started.") {
-        log(evt.data);
-        testStarted = true;
-    }
-    if (evt.data == "DONE") {
-        log("DONE.");
-        if (window.testRunner)
-            testRunner.notifyDone();
-    }
-}
+  return new Promise(resolve => {
+    worker = new Worker('resources/worker-timeout-increasing-order.js');
+    worker.postMessage('start');
+    worker.onmessage = resolve;
+  }).then(evt => {
+    assert_equals(evt.data, 1);
+    return (new Promise(resolve => worker.onmessage = resolve));
+  }).then(evt => {
+    assert_equals(evt.data, 2);
+    return (new Promise(resolve => worker.onmessage = resolve));
+  }).then(evt => {
+    assert_equals(evt.data, 3);
+  });
+}, 'Tests timeouts on the worker are fired in increasing order.');
 </script>
-</body>
-</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/misc/drag-bookmark-expected.txt b/third_party/blink/web_tests/http/tests/misc/drag-bookmark-expected.txt
new file mode 100644
index 0000000..8047eca
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/misc/drag-bookmark-expected.txt
@@ -0,0 +1 @@
+This is drag-bookmark-destination.html.
diff --git a/third_party/blink/web_tests/http/tests/misc/drag-bookmark.html b/third_party/blink/web_tests/http/tests/misc/drag-bookmark.html
new file mode 100644
index 0000000..d0bd0e8
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/misc/drag-bookmark.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<script>
+
+// Simulate dragging a bookmark to a cross-site URL.
+const crossSiteURL = "http://localhost:8000/misc/resources/" +
+                     "drag-bookmark-destination.html";
+eventSender.beginDragWithStringData(crossSiteURL, "text/uri-list");
+eventSender.mouseMoveTo(10, 10);
+eventSender.mouseUp();
+
+// notifyDone will be called once we navigate to the "bookmarked" URL that is
+// being dragged above.
+testRunner.waitUntilDone();
+
+</script>
diff --git a/third_party/blink/web_tests/http/tests/misc/resources/drag-bookmark-destination.html b/third_party/blink/web_tests/http/tests/misc/resources/drag-bookmark-destination.html
new file mode 100644
index 0000000..27553b1
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/misc/resources/drag-bookmark-destination.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<script>
+testRunner.dumpAsText();
+</script>
+<body onload="testRunner.notifyDone()">
+  This is drag-bookmark-destination.html.
+</body>
diff --git a/third_party/blink/web_tests/media/alpha-video-playback-expected.png b/third_party/blink/web_tests/media/alpha-video-playback-expected.png
new file mode 100644
index 0000000..59cf826
--- /dev/null
+++ b/third_party/blink/web_tests/media/alpha-video-playback-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/media/alpha-video-playback.html b/third_party/blink/web_tests/media/alpha-video-playback.html
new file mode 100644
index 0000000..7b2ec45
--- /dev/null
+++ b/third_party/blink/web_tests/media/alpha-video-playback.html
@@ -0,0 +1,35 @@
+<style>
+body { background: white; }
+video, canvas { background: pink; }
+</style>
+<script>
+if (window.testRunner)
+  testRunner.waitUntilDone();
+
+function startTest() {
+  var video = document.querySelector('video');
+
+  video.onplaying = function() {
+    if (video.currentTime == 0) {
+      setTimeout(video.onplaying, 150);
+      return;
+    }
+
+    var canvas = document.querySelector('canvas');
+    var ctx = canvas.getContext('2d');
+
+    // This will squish the video a bit, but it doesn't matter for this test.
+    ctx.clearRect(0, 0, canvas.width, canvas.height);
+    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
+
+    if (window.testRunner)
+      testRunner.notifyDone();
+  }
+
+  video.play();
+}
+</script>
+<body onload="startTest();">
+<video src="resources/white-square-vp9a.webm" width="320" height="240"></video>
+<canvas width="320" height="240"></canvas>
+</body>
diff --git a/third_party/blink/web_tests/media/resources/white-square-vp9a.webm b/third_party/blink/web_tests/media/resources/white-square-vp9a.webm
new file mode 100644
index 0000000..e3d85fb
--- /dev/null
+++ b/third_party/blink/web_tests/media/resources/white-square-vp9a.webm
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/media/alpha-video-playback-expected.png b/third_party/blink/web_tests/platform/win7/media/alpha-video-playback-expected.png
new file mode 100644
index 0000000..7096b54
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/media/alpha-video-playback-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/printing/offscreencanvas-2d-printing.html b/third_party/blink/web_tests/printing/offscreencanvas-2d-printing.html
index 5622ba0..ac9d9e3 100644
--- a/third_party/blink/web_tests/printing/offscreencanvas-2d-printing.html
+++ b/third_party/blink/web_tests/printing/offscreencanvas-2d-printing.html
@@ -1,37 +1,41 @@
 <!DOCTYPE html>
 <canvas id='canvas'></canvas>
 <script>
-  var canvas = document.getElementById('canvas');
-  canvas.width = canvas.height = 100;
-  var offscreenContext = canvas.transferControlToOffscreen().getContext("2d");
-  offscreenContext.fillStyle = "green";
-  offscreenContext.fillRect(0, 0, 100, 100);
+var documentCanvas = document.getElementById('canvas');
+documentCanvas.width = documentCanvas.height = 100;
+var offscreenContext = documentCanvas.transferControlToOffscreen().getContext(
+  "2d");
+offscreenContext.fillStyle = "green";
+offscreenContext.fillRect(0, 0, 100, 100);
 
-  // Make sure that the canvas has been drawn to before capturing
-  function waitForCanvasToDraw() {
-    return new Promise(resolve => {
-      var testPixel = function() {
-        var pixel = offscreenContext.getImageData(0, 0, 1, 1).data;
-        var greenChannel = pixel[1];
-        if (greenChannel != 128) {
-          requestAnimationFrame(testPixel);
-          return;
-        } else {
-          resolve();
-        }
+// For testing that the offscreen canvas has drawn
+var testCanvas = document.createElement("canvas");
+var testContext = testCanvas.getContext("2d");
+
+// Make sure that the canvas has been drawn to before capturing
+function waitForCanvasToDraw() {
+  return new Promise(resolve => {
+    var testPixel = function() {
+      testContext.drawImage(documentCanvas, 0, 0);
+      // Get the pixel in the upper left corner
+      var pixel = testContext.getImageData(0, 0, 1, 1).data;
+      if (pixel[0] === 0 && pixel[1] === 0 && pixel[2] === 0) {
+        // pixel is still empty, wait
+        requestAnimationFrame(testPixel);
+        return;
+      } else {
+        resolve();
       }
-      testPixel();
-    });
-  }
+    }
+    testPixel();
+  });
+}
 
-  if (window.testRunner) {
-    testRunner.setPrinting();
-    testRunner.waitUntilDone();
-    waitForCanvasToDraw().then(() => {
-      // Wait for all testRunner javascript to complete
-      window.setTimeout(() => {
-        testRunner.notifyDone()
-      }, 0);
-    });
-  }
+if (window.testRunner) {
+  testRunner.setPrinting();
+  testRunner.waitUntilDone();
+  waitForCanvasToDraw().then(() => {
+    testRunner.notifyDone()
+  });
+}
 </script>
diff --git a/third_party/blink/web_tests/printing/offscreencanvas-webgl-printing.html b/third_party/blink/web_tests/printing/offscreencanvas-webgl-printing.html
index 0376385..6581587 100644
--- a/third_party/blink/web_tests/printing/offscreencanvas-webgl-printing.html
+++ b/third_party/blink/web_tests/printing/offscreencanvas-webgl-printing.html
@@ -1,41 +1,42 @@
 <!DOCTYPE html>
 <canvas id='canvas'></canvas>
 <script>
-  var canvas = document.getElementById('canvas');
-  canvas.width = canvas.height = 100;
-  var offscreenContext = canvas.transferControlToOffscreen().getContext(
-    "webgl", {preserveDrawingBuffer: true});
-  offscreenContext.clearColor(0, 1, 0, 1);
-  offscreenContext.clear(offscreenContext.COLOR_BUFFER_BIT);
-  var pixel = new Uint8Array(4);
+var documentCanvas = document.getElementById('canvas');
+documentCanvas.width = documentCanvas.height = 100;
+var offscreenContext = documentCanvas.transferControlToOffscreen().getContext(
+  "webgl", {preserveDrawingBuffer: true});
+offscreenContext.clearColor(0, 1, 0, 1);
+offscreenContext.clear(offscreenContext.COLOR_BUFFER_BIT);
+var pixel = new Uint8Array(4);
 
-  // Make sure that the canvas has been drawn to before capturing
-  function waitForCanvasToDraw() {
-    return new Promise(resolve => {
-      var testPixel = function() {
-        offscreenContext.readPixels(0, 0, 1, 1,
-          offscreenContext.RGBA, offscreenContext.UNSIGNED_BYTE, pixel);
-        var greenChannel = pixel[1];
-        if (greenChannel != 255) { // The green channel
-          requestAnimationFrame(testPixel);
-          return;
-        } else {
-          resolve();
-        }
+// For testing that the offscreen canvas has drawn
+var testCanvas = document.createElement("canvas");
+var testContext = testCanvas.getContext("2d");
+
+// Make sure that the canvas has been drawn to before capturing
+function waitForCanvasToDraw() {
+  return new Promise(resolve => {
+    var testPixel = function() {
+      testContext.drawImage(documentCanvas, 0, 0);
+      // Get the pixel in the upper left corner
+      var pixel = testContext.getImageData(0, 0, 1, 1).data;
+      if (pixel[0] === 0 && pixel[1] === 0 && pixel[2] === 0) {
+        // pixel is still empty, wait
+        requestAnimationFrame(testPixel);
+        return;
+      } else {
+        resolve();
       }
-      testPixel();
-    });
-  }
+    }
+    testPixel();
+  });
+}
 
-  if (window.testRunner)
-  {
-    testRunner.setPrinting();
-    testRunner.waitUntilDone();
-    waitForCanvasToDraw().then(() => {
-      // Wait for all testRunner javascript to complete
-      window.setTimeout(() => {
-        testRunner.notifyDone()
-      }, 0);
-    });
-  }
+if (window.testRunner) {
+  testRunner.setPrinting();
+  testRunner.waitUntilDone();
+  waitForCanvasToDraw().then(() => {
+    testRunner.notifyDone()
+  });
+}
 </script>
\ No newline at end of file
diff --git a/third_party/inspector_protocol/README.chromium b/third_party/inspector_protocol/README.chromium
index d042fb5..66cacb7 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: d2f819f6307d3105853dffe89edd391bd8cfb400
+Revision: a0abcb6bfbd8d13071bb0d2ac4ee1066703eb60a
 License: BSD
 License File: LICENSE
 Security Critical: no
diff --git a/third_party/inspector_protocol/lib/DispatcherBase_cpp.template b/third_party/inspector_protocol/lib/DispatcherBase_cpp.template
index fc1c9a3..11843f4 100644
--- a/third_party/inspector_protocol/lib/DispatcherBase_cpp.template
+++ b/third_party/inspector_protocol/lib/DispatcherBase_cpp.template
@@ -142,18 +142,14 @@
         return std::unique_ptr<ProtocolError>(new ProtocolError(code, errorMessage));
     }
 
-    ProtocolMessage serialize() override
+    String serializeToJSON() override
     {
-        std::unique_ptr<protocol::DictionaryValue> error = DictionaryValue::create();
-        error->setInteger("code", m_code);
-        error->setString("message", m_errorMessage);
-        if (m_data.length())
-            error->setString("data", m_data);
-        std::unique_ptr<protocol::DictionaryValue> message = DictionaryValue::create();
-        message->setObject("error", std::move(error));
-        if (m_hasCallId)
-            message->setInteger("id", m_callId);
-        return message->serialize();
+        return serialize()->serializeToJSON();
+    }
+
+    std::vector<uint8_t> serializeToBinary() override
+    {
+        return serialize()->serializeToBinary();
     }
 
     ~ProtocolError() override {}
@@ -165,6 +161,19 @@
     {
     }
 
+    std::unique_ptr<DictionaryValue> serialize() {
+        std::unique_ptr<protocol::DictionaryValue> error = DictionaryValue::create();
+        error->setInteger("code", m_code);
+        error->setString("message", m_errorMessage);
+        if (m_data.length())
+            error->setString("data", m_data);
+        std::unique_ptr<protocol::DictionaryValue> message = DictionaryValue::create();
+        message->setObject("error", std::move(error));
+        if (m_hasCallId)
+            message->setInteger("id", m_callId);
+        return message;
+    }
+
     DispatchResponse::ErrorCode m_code;
     String m_errorMessage;
     String m_data;
@@ -275,12 +284,6 @@
     return !!findDispatcher(method);
 }
 
-void UberDispatcher::dispatch(int callId, const String& in_method, const ProtocolMessage& rawMessage)
-{
-    std::unique_ptr<Value> parsedMessage = StringUtil::parseProtocolMessage(rawMessage);
-    return dispatch(callId, in_method, std::move(parsedMessage), rawMessage);
-}
-
 void UberDispatcher::dispatch(int callId, const String& in_method, std::unique_ptr<Value> parsedMessage, const ProtocolMessage& rawMessage)
 {
     String method = in_method;
@@ -310,18 +313,32 @@
     return std::unique_ptr<InternalResponse>(new InternalResponse(0, notification, std::move(params)));
 }
 
-ProtocolMessage InternalResponse::serialize()
+String InternalResponse::serializeToJSON()
 {
     std::unique_ptr<DictionaryValue> result = DictionaryValue::create();
     std::unique_ptr<Serializable> params(m_params ? std::move(m_params) : DictionaryValue::create());
     if (m_notification.length()) {
         result->setString("method", m_notification);
-        result->setValue("params", SerializedValue::create(params->serialize()));
+        result->setValue("params", SerializedValue::fromJSON(params->serializeToJSON()));
     } else {
         result->setInteger("id", m_callId);
-        result->setValue("result", SerializedValue::create(params->serialize()));
+        result->setValue("result", SerializedValue::fromJSON(params->serializeToJSON()));
     }
-    return result->serialize();
+    return result->serializeToJSON();
+}
+
+std::vector<uint8_t> InternalResponse::serializeToBinary()
+{
+    std::unique_ptr<DictionaryValue> result = DictionaryValue::create();
+    std::unique_ptr<Serializable> params(m_params ? std::move(m_params) : DictionaryValue::create());
+    if (m_notification.length()) {
+        result->setString("method", m_notification);
+        result->setValue("params", SerializedValue::fromBinary(params->serializeToBinary()));
+    } else {
+        result->setInteger("id", m_callId);
+        result->setValue("result", SerializedValue::fromBinary(params->serializeToBinary()));
+    }
+    return result->serializeToBinary();
 }
 
 InternalResponse::InternalResponse(int callId, const String& notification, std::unique_ptr<Serializable> params)
diff --git a/third_party/inspector_protocol/lib/DispatcherBase_h.template b/third_party/inspector_protocol/lib/DispatcherBase_h.template
index 92a6466..7d859c4 100644
--- a/third_party/inspector_protocol/lib/DispatcherBase_h.template
+++ b/third_party/inspector_protocol/lib/DispatcherBase_h.template
@@ -111,7 +111,6 @@
     void setupRedirects(const std::unordered_map<String, String>&);
     bool parseCommand(Value* message, int* callId, String* method);
     bool canDispatch(const String& method);
-    void dispatch(int callId, const String& method, const ProtocolMessage& rawMessage);
     void dispatch(int callId, const String& method, std::unique_ptr<Value> message, const ProtocolMessage& rawMessage);
     FrontendChannel* channel() { return m_frontendChannel; }
     virtual ~UberDispatcher();
@@ -129,7 +128,8 @@
     static std::unique_ptr<InternalResponse> createResponse(int callId, std::unique_ptr<Serializable> params);
     static std::unique_ptr<InternalResponse> createNotification(const String& notification, std::unique_ptr<Serializable> params = nullptr);
 
-    ProtocolMessage serialize() override;
+    String serializeToJSON() override;
+    std::vector<uint8_t> serializeToBinary() override;
 
     ~InternalResponse() override {}
 
@@ -143,24 +143,36 @@
 
 class InternalRawNotification : public Serializable {
 public:
-    static std::unique_ptr<InternalRawNotification> create(const ProtocolMessage& notification)
+    static std::unique_ptr<InternalRawNotification> fromJSON(String notification)
     {
-        return std::unique_ptr<InternalRawNotification>(new InternalRawNotification(notification));
+        return std::unique_ptr<InternalRawNotification>(new InternalRawNotification(std::move(notification)));
     }
+
+    static std::unique_ptr<InternalRawNotification> fromBinary(std::vector<uint8_t> notification)
+    {
+        return std::unique_ptr<InternalRawNotification>(new InternalRawNotification(std::move(notification)));
+    }
+
     ~InternalRawNotification() override {}
 
-    ProtocolMessage serialize() override
+    String serializeToJSON() override
     {
-        return m_notification;
+        return std::move(m_jsonNotification);
+    }
+
+    std::vector<uint8_t> serializeToBinary() override
+    {
+        return std::move(m_binaryNotification);
     }
 
 private:
-  explicit InternalRawNotification(const ProtocolMessage& notification)
-    : m_notification(notification)
-  {
-  }
+  explicit InternalRawNotification(String notification)
+    : m_jsonNotification(std::move(notification)) { }
+  explicit InternalRawNotification(std::vector<uint8_t> notification)
+    : m_binaryNotification(std::move(notification)) { }
 
-  ProtocolMessage m_notification;
+  String m_jsonNotification;
+  std::vector<uint8_t> m_binaryNotification;
 };
 
 {% for namespace in config.protocol.namespace %}
diff --git a/third_party/inspector_protocol/lib/FrontendChannel_h.template b/third_party/inspector_protocol/lib/FrontendChannel_h.template
index 874a903..df104de 100644
--- a/third_party/inspector_protocol/lib/FrontendChannel_h.template
+++ b/third_party/inspector_protocol/lib/FrontendChannel_h.template
@@ -13,7 +13,14 @@
 
 class {{config.lib.export_macro}} Serializable {
 public:
-    virtual ProtocolMessage serialize() = 0;
+    ProtocolMessage serialize(bool binary) {
+      if (binary)
+        return StringUtil::binaryToMessage(serializeToBinary());
+      else
+        return StringUtil::jsonToMessage(serializeToJSON());
+    }
+    virtual String serializeToJSON() = 0;
+    virtual std::vector<uint8_t> serializeToBinary() = 0;
     virtual ~Serializable() = default;
 };
 
diff --git a/third_party/inspector_protocol/lib/Values_cpp.template b/third_party/inspector_protocol/lib/Values_cpp.template
index 7ada850c..55455076 100644
--- a/third_party/inspector_protocol/lib/Values_cpp.template
+++ b/third_party/inspector_protocol/lib/Values_cpp.template
@@ -62,6 +62,11 @@
 
 } // anonymous namespace
 
+// static
+std::unique_ptr<Value> Value::parseBinary(const uint8_t* data, size_t size) {
+  return nullptr;
+}
+
 bool Value::asBoolean(bool*) const
 {
     return false;
@@ -101,9 +106,12 @@
     return StringUtil::builderToString(result);
 }
 
-ProtocolMessage Value::serialize()
-{
-    return StringUtil::toProtocolMessage(*this);
+String Value::serializeToJSON() {
+    return toJSONString();
+}
+
+std::vector<uint8_t> Value::serializeToBinary() {
+    return std::vector<uint8_t>();
 }
 
 bool FundamentalValue::asBoolean(bool* output) const
@@ -186,12 +194,12 @@
 void SerializedValue::writeJSON(StringBuilder* output) const
 {
     DCHECK(type() == TypeSerialized);
-    StringUtil::builderAppend(*output, StringUtil::jsonComponent(m_serializedValue));
+    StringUtil::builderAppend(*output, m_serializedJSON);
 }
 
 std::unique_ptr<Value> SerializedValue::clone() const
 {
-    return SerializedValue::create(m_serializedValue);
+    return std::unique_ptr<SerializedValue>(new SerializedValue(m_serializedJSON, m_serializedBinary));
 }
 
 DictionaryValue::~DictionaryValue()
diff --git a/third_party/inspector_protocol/lib/Values_h.template b/third_party/inspector_protocol/lib/Values_h.template
index e7e5324..320ea40 100644
--- a/third_party/inspector_protocol/lib/Values_h.template
+++ b/third_party/inspector_protocol/lib/Values_h.template
@@ -28,6 +28,8 @@
         return std::unique_ptr<Value>(new Value());
     }
 
+    static std::unique_ptr<Value> parseBinary(const uint8_t* data, size_t size);
+
     enum ValueType {
         TypeNull = 0,
         TypeBoolean,
@@ -51,7 +53,9 @@
     virtual void writeJSON(StringBuilder* output) const;
     virtual std::unique_ptr<Value> clone() const;
     String toJSONString() const;
-    ProtocolMessage serialize() override;
+    String serializeToJSON() override;
+    std::vector<uint8_t> serializeToBinary() override;
+
 
 protected:
     Value() : m_type(TypeNull) { }
@@ -124,17 +128,26 @@
 
 class {{config.lib.export_macro}} SerializedValue : public Value {
 public:
-    static std::unique_ptr<SerializedValue> create(const ProtocolMessage& value)
+    static std::unique_ptr<SerializedValue> fromJSON(const String& value)
     {
         return std::unique_ptr<SerializedValue>(new SerializedValue(value));
     }
 
+    static std::unique_ptr<SerializedValue> fromBinary(std::vector<uint8_t> value)
+    {
+        return std::unique_ptr<SerializedValue>(new SerializedValue(std::move(value)));
+    }
+
     void writeJSON(StringBuilder* output) const override;
     std::unique_ptr<Value> clone() const override;
 
 private:
-    explicit SerializedValue(const ProtocolMessage& value) : Value(TypeSerialized), m_serializedValue(value) { }
-    ProtocolMessage m_serializedValue;
+    explicit SerializedValue(const String& json) : Value(TypeSerialized), m_serializedJSON(json) { }
+    explicit SerializedValue(std::vector<uint8_t> binary) : Value(TypeSerialized), m_serializedBinary(std::move(binary)) { }
+    SerializedValue(const String& json, const std::vector<uint8_t>& binary)
+        : Value(TypeSerialized), m_serializedJSON(json), m_serializedBinary(binary) { }
+    String m_serializedJSON;
+    std::vector<uint8_t> m_serializedBinary;
 };
 
 class {{config.lib.export_macro}} DictionaryValue : public Value {
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 d0730e5c..1576cd7 100644
--- a/third_party/inspector_protocol/lib/base_string_adapter_cc.template
+++ b/third_party/inspector_protocol/lib/base_string_adapter_cc.template
@@ -128,30 +128,26 @@
 }
 
 // static
-std::unique_ptr<Value> StringUtil::parseJSON(
-    const std::string& json) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
+std::unique_ptr<Value> StringUtil::parseMessage(
+    const std::string& message, bool binary) {
+  if (binary) {
+    return Value::parseBinary(
+        reinterpret_cast<const uint8_t*>(message.data()),
+        message.length());
+  }
+  std::unique_ptr<base::Value> value = base::JSONReader::Read(message);
   return toProtocolValue(value.get(), 1000);
 }
 
 // static
-std::unique_ptr<protocol::Value> StringUtil::parseProtocolMessage(const ProtocolMessage& message) {
-  return StringUtil::parseJSON(message);
-}
-
-// static
-ProtocolMessage StringUtil::toProtocolMessage(const Value& value) {
-  return value.toJSONString();
-}
-
-// static
-String StringUtil::jsonComponent(const ProtocolMessage& message) {
+ProtocolMessage StringUtil::jsonToMessage(String message) {
   return message;
 }
 
 // static
-ProtocolMessage StringUtil::fromJsonComponent(const String& message) {
-  return message;
+ProtocolMessage StringUtil::binaryToMessage(std::vector<uint8_t> message) {
+  // TODO(pfeldman): figure out what to do with this copy.
+  return std::string(reinterpret_cast<const char*>(message.data()), message.size());
 }
 
 StringBuilder::StringBuilder() {}
diff --git a/third_party/inspector_protocol/lib/base_string_adapter_h.template b/third_party/inspector_protocol/lib/base_string_adapter_h.template
index 73a5173c..44a0c9b 100644
--- a/third_party/inspector_protocol/lib/base_string_adapter_h.template
+++ b/third_party/inspector_protocol/lib/base_string_adapter_h.template
@@ -87,15 +87,18 @@
   static String builderToString(StringBuilder& builder) {
     return builder.toString();
   }
-  static std::vector<uint8_t> utf8data(const String& str) {
-    return std::vector<uint8_t>(str.begin(), str.end());
-  }
 
-  static std::unique_ptr<Value> parseJSON(const String&);
-  static std::unique_ptr<Value> parseProtocolMessage(const ProtocolMessage&);
-  static ProtocolMessage toProtocolMessage(const Value& value);
-  static String jsonComponent(const ProtocolMessage& message);
-  static ProtocolMessage fromJsonComponent(const String& message);
+  static std::unique_ptr<Value> parseMessage(const std::string& message, bool binary);
+  static ProtocolMessage jsonToMessage(String message);
+  static ProtocolMessage binaryToMessage(std::vector<uint8_t> message);
+
+  static String fromUTF8(const uint8_t* data, size_t length) {
+    return std::string(reinterpret_cast<const char*>(data), length);
+  }
+  static void writeUTF8(const String& string, std::vector<uint8_t>* out) {
+    const uint8_t* data = reinterpret_cast<const uint8_t*>(string.data());
+    out->insert(out->end(), data, data + string.length());
+  }
 };
 
 // A read-only sequence of uninterpreted bytes with reference-counted storage.
diff --git a/third_party/inspector_protocol/templates/Exported_h.template b/third_party/inspector_protocol/templates/Exported_h.template
index a8c3d73..4ea9167 100644
--- a/third_party/inspector_protocol/templates/Exported_h.template
+++ b/third_party/inspector_protocol/templates/Exported_h.template
@@ -51,8 +51,10 @@
 class {{config.exported.export_macro}} {{type.id}} {
 public:
     virtual {{config.exported.string_out}} toJSONString() const = 0;
+    virtual std::vector<uint8_t> toBinary() const = 0;
     virtual ~{{type.id}}() { }
     static std::unique_ptr<protocol::{{domain.domain}}::API::{{type.id}}> fromJSONString(const {{config.exported.string_in}}& json);
+    static std::unique_ptr<protocol::{{domain.domain}}::API::{{type.id}}> fromBinary(const uint8_t* data, size_t length);
 };
   {% endfor %}
 
diff --git a/third_party/inspector_protocol/templates/Imported_h.template b/third_party/inspector_protocol/templates/Imported_h.template
index d583bf6..469587e39 100644
--- a/third_party/inspector_protocol/templates/Imported_h.template
+++ b/third_party/inspector_protocol/templates/Imported_h.template
@@ -28,9 +28,13 @@
             errors->addError("value expected");
             return nullptr;
         }
-        ProtocolMessage message = value->serialize();
-        String json = StringUtil::jsonComponent(message);
-        auto result = {{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}::fromJSONString({{config.imported.to_imported_string % "json"}});
+
+        // TODO(pfeldman): switch from JSON to binary commented below.
+        std::unique_ptr<{{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}> result;
+        String json = value->serializeToJSON();
+        result = {{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}::fromJSONString({{config.imported.to_imported_string % "json"}});
+        // std::vector<uint8_t> binary = value->serializeToBinary();
+        // result = {{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}::fromBinary(binary.data(), binary.size());
         if (!result)
             errors->addError("cannot parse");
         return result;
@@ -38,9 +42,11 @@
 
     static std::unique_ptr<protocol::Value> toValue(const {{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}* value)
     {
+        // TODO(pfeldman): switch from JSON to binary commented below.
         auto json = value->toJSONString();
-        ProtocolMessage message = StringUtil::fromJsonComponent({{config.imported.from_imported_string % "std::move(json)"}});
-        return SerializedValue::create(message);
+        String local_json = ({{config.imported.from_imported_string % "std::move(json)"}});
+        return SerializedValue::fromJSON(local_json);
+        // return SerializedValue::fromBinary(value->toBinary());
     }
 
     static std::unique_ptr<protocol::Value> toValue(const std::unique_ptr<{{"::".join(config.imported.namespace)}}::{{domain.domain}}::API::{{type.id}}>& value)
diff --git a/third_party/inspector_protocol/templates/TypeBuilder_cpp.template b/third_party/inspector_protocol/templates/TypeBuilder_cpp.template
index fb71d2c..07e45a3 100644
--- a/third_party/inspector_protocol/templates/TypeBuilder_cpp.template
+++ b/third_party/inspector_protocol/templates/TypeBuilder_cpp.template
@@ -101,10 +101,15 @@
 
 {{config.exported.string_out}} {{type.id}}::toJSONString() const
 {
-    String json = toValue()->serialize();
+    String json = toValue()->serializeToJSON();
     return {{config.exported.to_string_out % "json"}};
 }
 
+std::vector<uint8_t> {{type.id}}::toBinary() const
+{
+    return toValue()->serializeToBinary();
+}
+
 // static
 std::unique_ptr<API::{{type.id}}> API::{{type.id}}::fromJSONString(const {{config.exported.string_in}}& json)
 {
@@ -115,6 +120,16 @@
     return protocol::{{domain.domain}}::{{type.id}}::fromValue(value.get(), &errors);
 }
 
+// static
+std::unique_ptr<API::{{type.id}}> API::{{type.id}}::fromBinary(const uint8_t* data, size_t length)
+{
+    ErrorSupport errors;
+    std::unique_ptr<Value> value = Value::parseBinary(data, length);
+    if (!value)
+        return nullptr;
+    return protocol::{{domain.domain}}::{{type.id}}::fromValue(value.get(), &errors);
+}
+
     {% endif %}
   {% endfor %}
 
@@ -188,9 +203,14 @@
     m_frontendChannel->flushProtocolNotifications();
 }
 
-void Frontend::sendRawNotification(const ProtocolMessage& notification)
+void Frontend::sendRawNotification(String notification)
 {
-    m_frontendChannel->sendProtocolNotification(InternalRawNotification::create(notification));
+    m_frontendChannel->sendProtocolNotification(InternalRawNotification::fromJSON(std::move(notification)));
+}
+
+void Frontend::sendRawNotification(std::vector<uint8_t> notification)
+{
+    m_frontendChannel->sendProtocolNotification(InternalRawNotification::fromBinary(std::move(notification)));
 }
 
 // --------------------- Dispatcher.
diff --git a/third_party/inspector_protocol/templates/TypeBuilder_h.template b/third_party/inspector_protocol/templates/TypeBuilder_h.template
index 2cdf83a..c5e95d7 100644
--- a/third_party/inspector_protocol/templates/TypeBuilder_h.template
+++ b/third_party/inspector_protocol/templates/TypeBuilder_h.template
@@ -100,11 +100,13 @@
     {% endfor %}
 
     std::unique_ptr<protocol::DictionaryValue> toValue() const;
-    ProtocolMessage serialize() override { return toValue()->serialize(); }
+    String serializeToJSON() override { return toValue()->serializeToJSON(); }
+    std::vector<uint8_t> serializeToBinary() override { return toValue()->serializeToBinary(); }
     String toJSON() const { return toValue()->toJSONString(); }
     std::unique_ptr<{{type.id}}> clone() const;
     {% if protocol.is_exported(domain.domain, type.id) %}
     {{config.exported.string_out}} toJSONString() const override;
+    std::vector<uint8_t> toBinary() const override;
     {% endif %}
 
     template<int STATE>
@@ -267,7 +269,8 @@
   {% endfor %}
 
     void flush();
-    void sendRawNotification(const ProtocolMessage&);
+    void sendRawNotification(String);
+    void sendRawNotification(std::vector<uint8_t>);
 private:
     FrontendChannel* m_frontendChannel;
 };
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium
index 1fc90b1..6bb4842 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: Wednesday February 06 2019
+Date: Tuesday February 12 2019
 Branch: master
-Commit: ce4336c2ab60d185b431345987b2188511760e54
+Commit: e2381829e984c58e54a7ad0580c168cb7432ef92
 
 Description:
 Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/source/config/ios/arm-neon/vpx_config.asm b/third_party/libvpx/source/config/ios/arm-neon/vpx_config.asm
index 8a79f63d..7a7f7fb 100644
--- a/third_party/libvpx/source/config/ios/arm-neon/vpx_config.asm
+++ b/third_party/libvpx/source/config/ios/arm-neon/vpx_config.asm
@@ -88,6 +88,5 @@
 .set CONFIG_FP_MB_STATS ,  0
 .set CONFIG_EMULATE_HARDWARE ,  0
 .set CONFIG_NON_GREEDY_MV ,  0
-.set CONFIG_ML_VAR_PARTITION ,  0
 .set DECODE_WIDTH_LIMIT ,  16384
 .set DECODE_HEIGHT_LIMIT ,  16384
diff --git a/third_party/libvpx/source/config/ios/arm-neon/vpx_config.h b/third_party/libvpx/source/config/ios/arm-neon/vpx_config.h
index 7c92a22..c19d1d9 100644
--- a/third_party/libvpx/source/config/ios/arm-neon/vpx_config.h
+++ b/third_party/libvpx/source/config/ios/arm-neon/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/ios/arm64/vpx_config.asm b/third_party/libvpx/source/config/ios/arm64/vpx_config.asm
index ab563f8a..c4860ad 100644
--- a/third_party/libvpx/source/config/ios/arm64/vpx_config.asm
+++ b/third_party/libvpx/source/config/ios/arm64/vpx_config.asm
@@ -88,6 +88,5 @@
 .set CONFIG_FP_MB_STATS ,  0
 .set CONFIG_EMULATE_HARDWARE ,  0
 .set CONFIG_NON_GREEDY_MV ,  0
-.set CONFIG_ML_VAR_PARTITION ,  0
 .set DECODE_WIDTH_LIMIT ,  16384
 .set DECODE_HEIGHT_LIMIT ,  16384
diff --git a/third_party/libvpx/source/config/ios/arm64/vpx_config.h b/third_party/libvpx/source/config/ios/arm64/vpx_config.h
index 3437c03..e4de0be 100644
--- a/third_party/libvpx/source/config/ios/arm64/vpx_config.h
+++ b/third_party/libvpx/source/config/ios/arm64/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.asm b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.asm
index 241f370..0d29fb5 100644
--- a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.asm
+++ b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.asm
@@ -85,7 +85,6 @@
 .equ CONFIG_FP_MB_STATS ,  0
 .equ CONFIG_EMULATE_HARDWARE ,  0
 .equ CONFIG_NON_GREEDY_MV ,  0
-.equ CONFIG_ML_VAR_PARTITION ,  0
 .equ DECODE_WIDTH_LIMIT ,  16384
 .equ DECODE_HEIGHT_LIMIT ,  16384
 	.section	.note.GNU-stack,"",%progbits
diff --git a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.h b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.h
index 1af5ae89..58b42323 100644
--- a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/linux/arm-neon-highbd/vpx_config.asm b/third_party/libvpx/source/config/linux/arm-neon-highbd/vpx_config.asm
index 225e0896..f7a28f8 100644
--- a/third_party/libvpx/source/config/linux/arm-neon-highbd/vpx_config.asm
+++ b/third_party/libvpx/source/config/linux/arm-neon-highbd/vpx_config.asm
@@ -85,7 +85,6 @@
 .equ CONFIG_FP_MB_STATS ,  0
 .equ CONFIG_EMULATE_HARDWARE ,  0
 .equ CONFIG_NON_GREEDY_MV ,  0
-.equ CONFIG_ML_VAR_PARTITION ,  0
 .equ DECODE_WIDTH_LIMIT ,  16384
 .equ DECODE_HEIGHT_LIMIT ,  16384
 	.section	.note.GNU-stack,"",%progbits
diff --git a/third_party/libvpx/source/config/linux/arm-neon-highbd/vpx_config.h b/third_party/libvpx/source/config/linux/arm-neon-highbd/vpx_config.h
index 3e56331e..5df6afd 100644
--- a/third_party/libvpx/source/config/linux/arm-neon-highbd/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/arm-neon-highbd/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/linux/arm-neon/vpx_config.asm b/third_party/libvpx/source/config/linux/arm-neon/vpx_config.asm
index 34101dab..64cec85 100644
--- a/third_party/libvpx/source/config/linux/arm-neon/vpx_config.asm
+++ b/third_party/libvpx/source/config/linux/arm-neon/vpx_config.asm
@@ -85,7 +85,6 @@
 .equ CONFIG_FP_MB_STATS ,  0
 .equ CONFIG_EMULATE_HARDWARE ,  0
 .equ CONFIG_NON_GREEDY_MV ,  0
-.equ CONFIG_ML_VAR_PARTITION ,  0
 .equ DECODE_WIDTH_LIMIT ,  16384
 .equ DECODE_HEIGHT_LIMIT ,  16384
 	.section	.note.GNU-stack,"",%progbits
diff --git a/third_party/libvpx/source/config/linux/arm-neon/vpx_config.h b/third_party/libvpx/source/config/linux/arm-neon/vpx_config.h
index 7c92a22..c19d1d9 100644
--- a/third_party/libvpx/source/config/linux/arm-neon/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/arm-neon/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/linux/arm/vpx_config.asm b/third_party/libvpx/source/config/linux/arm/vpx_config.asm
index b9450db..a13825c 100644
--- a/third_party/libvpx/source/config/linux/arm/vpx_config.asm
+++ b/third_party/libvpx/source/config/linux/arm/vpx_config.asm
@@ -85,7 +85,6 @@
 .equ CONFIG_FP_MB_STATS ,  0
 .equ CONFIG_EMULATE_HARDWARE ,  0
 .equ CONFIG_NON_GREEDY_MV ,  0
-.equ CONFIG_ML_VAR_PARTITION ,  0
 .equ DECODE_WIDTH_LIMIT ,  16384
 .equ DECODE_HEIGHT_LIMIT ,  16384
 	.section	.note.GNU-stack,"",%progbits
diff --git a/third_party/libvpx/source/config/linux/arm/vpx_config.h b/third_party/libvpx/source/config/linux/arm/vpx_config.h
index e699eab..acc4935 100644
--- a/third_party/libvpx/source/config/linux/arm/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/arm/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/linux/arm64-highbd/vpx_config.asm b/third_party/libvpx/source/config/linux/arm64-highbd/vpx_config.asm
index f728cb2..f94c4910 100644
--- a/third_party/libvpx/source/config/linux/arm64-highbd/vpx_config.asm
+++ b/third_party/libvpx/source/config/linux/arm64-highbd/vpx_config.asm
@@ -85,7 +85,6 @@
 .equ CONFIG_FP_MB_STATS ,  0
 .equ CONFIG_EMULATE_HARDWARE ,  0
 .equ CONFIG_NON_GREEDY_MV ,  0
-.equ CONFIG_ML_VAR_PARTITION ,  0
 .equ DECODE_WIDTH_LIMIT ,  16384
 .equ DECODE_HEIGHT_LIMIT ,  16384
 	.section	.note.GNU-stack,"",%progbits
diff --git a/third_party/libvpx/source/config/linux/arm64-highbd/vpx_config.h b/third_party/libvpx/source/config/linux/arm64-highbd/vpx_config.h
index e57b1c4..1a03c79 100644
--- a/third_party/libvpx/source/config/linux/arm64-highbd/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/arm64-highbd/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/linux/arm64/vpx_config.asm b/third_party/libvpx/source/config/linux/arm64/vpx_config.asm
index 648ea113..559e41d 100644
--- a/third_party/libvpx/source/config/linux/arm64/vpx_config.asm
+++ b/third_party/libvpx/source/config/linux/arm64/vpx_config.asm
@@ -85,7 +85,6 @@
 .equ CONFIG_FP_MB_STATS ,  0
 .equ CONFIG_EMULATE_HARDWARE ,  0
 .equ CONFIG_NON_GREEDY_MV ,  0
-.equ CONFIG_ML_VAR_PARTITION ,  0
 .equ DECODE_WIDTH_LIMIT ,  16384
 .equ DECODE_HEIGHT_LIMIT ,  16384
 	.section	.note.GNU-stack,"",%progbits
diff --git a/third_party/libvpx/source/config/linux/arm64/vpx_config.h b/third_party/libvpx/source/config/linux/arm64/vpx_config.h
index 3437c03..e4de0be 100644
--- a/third_party/libvpx/source/config/linux/arm64/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/arm64/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/linux/generic/vpx_config.asm b/third_party/libvpx/source/config/linux/generic/vpx_config.asm
index 20c7b9b..fdb927f2 100644
--- a/third_party/libvpx/source/config/linux/generic/vpx_config.asm
+++ b/third_party/libvpx/source/config/linux/generic/vpx_config.asm
@@ -85,7 +85,6 @@
 .equ CONFIG_FP_MB_STATS ,  0
 .equ CONFIG_EMULATE_HARDWARE ,  0
 .equ CONFIG_NON_GREEDY_MV ,  0
-.equ CONFIG_ML_VAR_PARTITION ,  0
 .equ DECODE_WIDTH_LIMIT ,  16384
 .equ DECODE_HEIGHT_LIMIT ,  16384
 	.section	.note.GNU-stack,"",%progbits
diff --git a/third_party/libvpx/source/config/linux/generic/vpx_config.h b/third_party/libvpx/source/config/linux/generic/vpx_config.h
index 9578b56..abc94bfc 100644
--- a/third_party/libvpx/source/config/linux/generic/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/generic/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/linux/ia32/vpx_config.asm b/third_party/libvpx/source/config/linux/ia32/vpx_config.asm
index 57637ae08..5569f05 100644
--- a/third_party/libvpx/source/config/linux/ia32/vpx_config.asm
+++ b/third_party/libvpx/source/config/linux/ia32/vpx_config.asm
@@ -82,6 +82,5 @@
 %define CONFIG_FP_MB_STATS 0
 %define CONFIG_EMULATE_HARDWARE 0
 %define CONFIG_NON_GREEDY_MV 0
-%define CONFIG_ML_VAR_PARTITION 0
 %define DECODE_WIDTH_LIMIT 16384
 %define DECODE_HEIGHT_LIMIT 16384
diff --git a/third_party/libvpx/source/config/linux/ia32/vpx_config.h b/third_party/libvpx/source/config/linux/ia32/vpx_config.h
index a65ea2d..fff9290 100644
--- a/third_party/libvpx/source/config/linux/ia32/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/ia32/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/linux/mips64el/vpx_config.h b/third_party/libvpx/source/config/linux/mips64el/vpx_config.h
index d79a46a9..7941761 100644
--- a/third_party/libvpx/source/config/linux/mips64el/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/mips64el/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/linux/mipsel/vpx_config.h b/third_party/libvpx/source/config/linux/mipsel/vpx_config.h
index 9910a7ff..38c667e 100644
--- a/third_party/libvpx/source/config/linux/mipsel/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/mipsel/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/linux/x64/vpx_config.asm b/third_party/libvpx/source/config/linux/x64/vpx_config.asm
index 0f7956f..613735d8 100644
--- a/third_party/libvpx/source/config/linux/x64/vpx_config.asm
+++ b/third_party/libvpx/source/config/linux/x64/vpx_config.asm
@@ -82,6 +82,5 @@
 %define CONFIG_FP_MB_STATS 0
 %define CONFIG_EMULATE_HARDWARE 0
 %define CONFIG_NON_GREEDY_MV 0
-%define CONFIG_ML_VAR_PARTITION 0
 %define DECODE_WIDTH_LIMIT 16384
 %define DECODE_HEIGHT_LIMIT 16384
diff --git a/third_party/libvpx/source/config/linux/x64/vpx_config.h b/third_party/libvpx/source/config/linux/x64/vpx_config.h
index 260602b..677a9fc 100644
--- a/third_party/libvpx/source/config/linux/x64/vpx_config.h
+++ b/third_party/libvpx/source/config/linux/x64/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/mac/ia32/vpx_config.asm b/third_party/libvpx/source/config/mac/ia32/vpx_config.asm
index 57637ae08..5569f05 100644
--- a/third_party/libvpx/source/config/mac/ia32/vpx_config.asm
+++ b/third_party/libvpx/source/config/mac/ia32/vpx_config.asm
@@ -82,6 +82,5 @@
 %define CONFIG_FP_MB_STATS 0
 %define CONFIG_EMULATE_HARDWARE 0
 %define CONFIG_NON_GREEDY_MV 0
-%define CONFIG_ML_VAR_PARTITION 0
 %define DECODE_WIDTH_LIMIT 16384
 %define DECODE_HEIGHT_LIMIT 16384
diff --git a/third_party/libvpx/source/config/mac/ia32/vpx_config.h b/third_party/libvpx/source/config/mac/ia32/vpx_config.h
index a65ea2d..fff9290 100644
--- a/third_party/libvpx/source/config/mac/ia32/vpx_config.h
+++ b/third_party/libvpx/source/config/mac/ia32/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/mac/x64/vpx_config.asm b/third_party/libvpx/source/config/mac/x64/vpx_config.asm
index 0f7956f..613735d8 100644
--- a/third_party/libvpx/source/config/mac/x64/vpx_config.asm
+++ b/third_party/libvpx/source/config/mac/x64/vpx_config.asm
@@ -82,6 +82,5 @@
 %define CONFIG_FP_MB_STATS 0
 %define CONFIG_EMULATE_HARDWARE 0
 %define CONFIG_NON_GREEDY_MV 0
-%define CONFIG_ML_VAR_PARTITION 0
 %define DECODE_WIDTH_LIMIT 16384
 %define DECODE_HEIGHT_LIMIT 16384
diff --git a/third_party/libvpx/source/config/mac/x64/vpx_config.h b/third_party/libvpx/source/config/mac/x64/vpx_config.h
index 260602b..677a9fc 100644
--- a/third_party/libvpx/source/config/mac/x64/vpx_config.h
+++ b/third_party/libvpx/source/config/mac/x64/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/nacl/vpx_config.h b/third_party/libvpx/source/config/nacl/vpx_config.h
index 9578b56..abc94bfc 100644
--- a/third_party/libvpx/source/config/nacl/vpx_config.h
+++ b/third_party/libvpx/source/config/nacl/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h
index 1433f84..dff0bbf 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  "142-gce4336c2ab"
+#define VERSION_EXTRA  "161-ge2381829e9"
 #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.8.0-142-gce4336c2ab"
-#define VERSION_STRING      " v1.8.0-142-gce4336c2ab"
+#define VERSION_STRING_NOSP "v1.8.0-161-ge2381829e9"
+#define VERSION_STRING      " v1.8.0-161-ge2381829e9"
diff --git a/third_party/libvpx/source/config/win/arm64/vpx_config.asm b/third_party/libvpx/source/config/win/arm64/vpx_config.asm
index 5eeb841..02c1c51 100644
--- a/third_party/libvpx/source/config/win/arm64/vpx_config.asm
+++ b/third_party/libvpx/source/config/win/arm64/vpx_config.asm
@@ -88,6 +88,5 @@
 .set CONFIG_FP_MB_STATS ,  0
 .set CONFIG_EMULATE_HARDWARE ,  0
 .set CONFIG_NON_GREEDY_MV ,  0
-.set CONFIG_ML_VAR_PARTITION ,  0
 .set DECODE_WIDTH_LIMIT ,  16384
 .set DECODE_HEIGHT_LIMIT ,  16384
diff --git a/third_party/libvpx/source/config/win/arm64/vpx_config.h b/third_party/libvpx/source/config/win/arm64/vpx_config.h
index 0f793cb6..e05718c 100644
--- a/third_party/libvpx/source/config/win/arm64/vpx_config.h
+++ b/third_party/libvpx/source/config/win/arm64/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/win/ia32/vpx_config.asm b/third_party/libvpx/source/config/win/ia32/vpx_config.asm
index 054b531a3..6c3ef6c 100644
--- a/third_party/libvpx/source/config/win/ia32/vpx_config.asm
+++ b/third_party/libvpx/source/config/win/ia32/vpx_config.asm
@@ -82,6 +82,5 @@
 %define CONFIG_FP_MB_STATS 0
 %define CONFIG_EMULATE_HARDWARE 0
 %define CONFIG_NON_GREEDY_MV 0
-%define CONFIG_ML_VAR_PARTITION 0
 %define DECODE_WIDTH_LIMIT 16384
 %define DECODE_HEIGHT_LIMIT 16384
diff --git a/third_party/libvpx/source/config/win/ia32/vpx_config.h b/third_party/libvpx/source/config/win/ia32/vpx_config.h
index 2444863..2d967a0 100644
--- a/third_party/libvpx/source/config/win/ia32/vpx_config.h
+++ b/third_party/libvpx/source/config/win/ia32/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/third_party/libvpx/source/config/win/x64/vpx_config.asm b/third_party/libvpx/source/config/win/x64/vpx_config.asm
index f992b51..d104fd3f 100644
--- a/third_party/libvpx/source/config/win/x64/vpx_config.asm
+++ b/third_party/libvpx/source/config/win/x64/vpx_config.asm
@@ -82,6 +82,5 @@
 %define CONFIG_FP_MB_STATS 0
 %define CONFIG_EMULATE_HARDWARE 0
 %define CONFIG_NON_GREEDY_MV 0
-%define CONFIG_ML_VAR_PARTITION 0
 %define DECODE_WIDTH_LIMIT 16384
 %define DECODE_HEIGHT_LIMIT 16384
diff --git a/third_party/libvpx/source/config/win/x64/vpx_config.h b/third_party/libvpx/source/config/win/x64/vpx_config.h
index 093f254..8a07c942 100644
--- a/third_party/libvpx/source/config/win/x64/vpx_config.h
+++ b/third_party/libvpx/source/config/win/x64/vpx_config.h
@@ -94,7 +94,6 @@
 #define CONFIG_FP_MB_STATS 0
 #define CONFIG_EMULATE_HARDWARE 0
 #define CONFIG_NON_GREEDY_MV 0
-#define CONFIG_ML_VAR_PARTITION 0
 #define DECODE_WIDTH_LIMIT 16384
 #define DECODE_HEIGHT_LIMIT 16384
 #endif /* VPX_CONFIG_H */
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index f57d8ef..b466c69a 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -15433,6 +15433,7 @@
   <int value="519" label="BrowserSwitcherKeepLastChromeTab"/>
   <int value="520" label="DeviceRebootAfterArcSession"/>
   <int value="521" label="ForceNetworkInProcess"/>
+  <int value="522" label="SchedulerConfiguration"/>
 </enum>
 
 <enum name="EnterprisePolicyInvalidations">
diff --git a/tools/metrics/histograms/generate_expired_histograms_array.py b/tools/metrics/histograms/generate_expired_histograms_array.py
index a122247..cf10df7 100755
--- a/tools/metrics/histograms/generate_expired_histograms_array.py
+++ b/tools/metrics/histograms/generate_expired_histograms_array.py
@@ -43,6 +43,13 @@
 
 _DATE_FORMAT_ERROR = "Unable to parse expiry {date} in histogram {name}."
 
+# Some extra "grace" time is given to expired histograms during which they
+# will contintue to be collected and reported.  The dashboard should ignore
+# data from this period making the expiry noticeable and giving time for
+# owners to re-enable them without any discontinuity of data.
+_EXPIRE_GRACE_MSTONES = 2
+_EXPIRE_GRACE_WEEKS = _EXPIRE_GRACE_MSTONES * 6
+
 
 class Error(Exception):
   pass
@@ -180,6 +187,38 @@
       hashes_size=len(histograms_map))
 
 
+def _GenerateFileContent(descriptions, branch_file_content,
+                         mstone_file_content, header_filename, namespace):
+  """Generates header file containing array with hashes of expired histograms.
+
+  Args:
+    descriptions: Combined histogram descriptions.
+    branch_file_content: Content of file with base date.
+    mstone_file_content: Content of file with milestone information.
+    header_filename: A filename of the generated header file.
+    namespace: A namespace to contain generated array.
+
+  Raises:
+    Error if there is an error in input xml files.
+  """
+  histograms, had_errors = (
+      extract_histograms.ExtractHistogramsFromDom(descriptions))
+  if had_errors:
+    raise Error("Error parsing inputs.")
+  base_date = _GetBaseDate(branch_file_content, _DATE_FILE_RE)
+  base_date -= datetime.timedelta(weeks=_EXPIRE_GRACE_WEEKS)
+  current_milestone = _GetCurrentMilestone(
+      mstone_file_content, _CURRENT_MILESTONE_RE)
+  current_milestone -= _EXPIRE_GRACE_MSTONES
+
+  expired_histograms_names = _GetExpiredHistograms(
+      histograms, base_date, current_milestone)
+  expired_histograms_map = _GetHashToNameMap(expired_histograms_names)
+  header_file_content = _GenerateHeaderFileContent(
+      header_filename, namespace, expired_histograms_map)
+  return header_file_content
+
+
 def _GenerateFile(arguments):
   """Generates header file containing array with hashes of expired histograms.
 
@@ -191,28 +230,17 @@
       arguments.output_dir: A directory to put the generated file.
       arguments.major_branch_date_filepath: File path for base date.
       arguments.milestone_filepath: File path for milestone information.
-
-  Raises:
-    Error if there is an error in input xml files.
   """
   descriptions = merge_xml.MergeFiles(arguments.inputs)
-  histograms, had_errors = (
-      extract_histograms.ExtractHistogramsFromDom(descriptions))
-  if had_errors:
-    raise Error("Error parsing inputs.")
   with open(arguments.major_branch_date_filepath, "r") as date_file:
-    file_content = date_file.read()
-  base_date = _GetBaseDate(file_content, _DATE_FILE_RE)
+    branch_file_content = date_file.read()
   with open(arguments.milestone_filepath, "r") as milestone_file:
-    file_content = milestone_file.read()
-  current_milestone = _GetCurrentMilestone(file_content, _CURRENT_MILESTONE_RE)
+    mstone_file_content = milestone_file.read()
 
-  expired_histograms_names = _GetExpiredHistograms(
-      histograms, base_date, current_milestone)
-  expired_histograms_map = _GetHashToNameMap(expired_histograms_names)
-  header_file_content = _GenerateHeaderFileContent(
-      arguments.header_filename, arguments.namespace,
-      expired_histograms_map)
+  header_file_content = _GenerateFileContent(
+      descriptions, branch_file_content, mstone_file_content,
+      arguments.header_filename, arguments.namespace)
+
   with open(os.path.join(arguments.output_dir, arguments.header_filename),
             "w") as generated_file:
     generated_file.write(header_file_content)
diff --git a/tools/metrics/histograms/generate_expired_histograms_array_unittest.py b/tools/metrics/histograms/generate_expired_histograms_array_unittest.py
index 12aef04..a4f2d721 100755
--- a/tools/metrics/histograms/generate_expired_histograms_array_unittest.py
+++ b/tools/metrics/histograms/generate_expired_histograms_array_unittest.py
@@ -5,6 +5,7 @@
 
 import datetime
 import unittest
+import xml.dom.minidom
 
 import generate_expired_histograms_array
 
@@ -148,6 +149,30 @@
     self.assertEqual(_EXPECTED_HEADER_FILE_CONTENT.format(
         array_definition=_EXPECTED_NON_EMPTY_ARRAY_DEFINITION), content)
 
+  def testGenerateFileHistogramExpiryWithGrace(self):
+    histograms = xml.dom.minidom.parseString("""
+<histogram-configuration>
+<histograms><!-- Must be alphabetical. -->
+  <histogram name="FirstHistogram" expires_after="2010-11-01"/>
+  <histogram name="FourthHistogram" expires_after="M61"/>
+  <histogram name="SecondHistogram" expires_after="2010-10-01"/>
+  <histogram name="ThirdHistogram" expires_after="M60"/>
+</histograms>
+</histogram-configuration>
+""")
+
+    branch_data = "MAJOR_BRANCH_DATE=2011-01-01\n"
+    mstone_data = "MAJOR=63\n"
+
+    content = generate_expired_histograms_array._GenerateFileContent(
+        histograms, branch_data, mstone_data, "header.h", "uma")
+    # These have expired but are within the 12-week/2-milestone grace period.
+    self.assertNotIn("FirstHistogram", content);
+    self.assertNotIn("FourthHistogram", content);
+    # These have expired and are outside of the grace period.
+    self.assertIn("SecondHistogram", content);
+    self.assertIn("ThirdHistogram", content);
+
   def testGenerateHeaderFileContentEmptyArray(self):
     header_filename = "test/test.h"
     namespace = "some_namespace"
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 87710aca..37fc835 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -26609,9 +26609,7 @@
 
 <histogram name="EasyUnlock.AuthEvent.DidUserManuallyUnlockPhone"
     enum="EasyUnlockDidUserManuallyUnlockPhone">
-  <owner>isherman@google.com</owner>
   <owner>hansberry@chromium.org</owner>
-  <owner>xiyuan@google.com</owner>
   <summary>
     Upon a successful Smart Lock unlock or signin, records whether the user's
     phone was locked during any point while the lock screen was up. This can be
@@ -26621,9 +26619,7 @@
 </histogram>
 
 <histogram name="EasyUnlock.AuthEvent.SignIn" enum="EasyUnlockAuthEvent">
-  <owner>isherman@google.com</owner>
   <owner>hansberry@chromium.org</owner>
-  <owner>xiyuan@google.com</owner>
   <summary>
     Measures the use of Smart Lock on the sign-in screen: records whether a
     Smart Lock login succeeded or failed; or if a password fallback was used,
@@ -26633,8 +26629,6 @@
 </histogram>
 
 <histogram name="EasyUnlock.AuthEvent.SignIn.Duration" units="ms">
-  <owner>isherman@google.com</owner>
-  <owner>tengs@google.com</owner>
   <owner>hansberry@chromium.org</owner>
   <summary>
     Measures the time elapsed between the user focusing their user pod and
@@ -26643,9 +26637,7 @@
 </histogram>
 
 <histogram name="EasyUnlock.AuthEvent.Unlock" enum="EasyUnlockAuthEvent">
-  <owner>isherman@google.com</owner>
   <owner>hansberry@chromium.org</owner>
-  <owner>xiyuan@google.com</owner>
   <summary>
     Measures the use of Smart Lock on the lock screen: records whether a Smart
     Lock unlock attempt succeeded or failed; or if a password fallback was used,
@@ -26655,8 +26647,6 @@
 </histogram>
 
 <histogram name="EasyUnlock.AuthEvent.Unlock.Duration" units="ms">
-  <owner>isherman@google.com</owner>
-  <owner>tengs@google.com</owner>
   <owner>hansberry@chromium.org</owner>
   <summary>
     Measures the time elapsed between the lock screen being shown and the user
@@ -26668,7 +26658,6 @@
 
 <histogram name="EasyUnlock.AuthProximity.RemoteDeviceModelHash"
     enum="EasyUnlockDeviceModelHash">
-  <owner>tengs@chromium.org</owner>
   <owner>hansberry@chromium.org</owner>
   <summary>
     The hash of the phone model used to successfully sign in or unlock using
@@ -26681,7 +26670,6 @@
 </histogram>
 
 <histogram name="EasyUnlock.AuthProximity.RollingRssi" units="dBm">
-  <owner>tengs@chromium.org</owner>
   <owner>hansberry@chromium.org</owner>
   <summary>
     Measures the exponentially weighted rolling average of the received signal
@@ -26765,8 +26753,7 @@
 </histogram>
 
 <histogram name="EasyUnlock.ClickedButton" enum="EasyUnlockButton">
-  <owner>joshwoodward@google.com</owner>
-  <owner>tbarzic@chromium.org</owner>
+  <owner>hansberry@chromium.org</owner>
   <summary>Button clicked in EasyUnlock app during setup process.</summary>
 </histogram>
 
@@ -26785,9 +26772,7 @@
 
 <histogram name="EasyUnlock.RemoteLockScreenState"
     enum="EasyUnlockRemoteLockScreenState">
-  <owner>joshwoodward@google.com</owner>
-  <owner>tengs@chromium.org</owner>
-  <owner>isherman@chromium.org</owner>
+  <owner>hansberry@chromium.org</owner>
   <summary>
     Whether a lock screen and a trust agent are enabled on the remote device
     (Android phone) for Easy Unlock. Recorded once per status update message
@@ -26799,7 +26784,6 @@
 </histogram>
 
 <histogram name="EasyUnlock.Setup.Devices.Count.Eligible">
-  <owner>isherman@chromium.org</owner>
   <owner>hansberry@chromium.org</owner>
   <summary>
     The number of eligible devices that the CryptAuth server returns during the
@@ -26813,7 +26797,6 @@
 </histogram>
 
 <histogram name="EasyUnlock.Setup.Devices.Count.Ineligible">
-  <owner>isherman@chromium.org</owner>
   <owner>hansberry@chromium.org</owner>
   <summary>
     The number of ineligible devices that the CryptAuth server returns during
@@ -26828,7 +26811,6 @@
 
 <histogram name="EasyUnlock.Setup.Devices.HasSecureScreenLock"
     enum="EasyUnlockHasSecureScreenLock">
-  <owner>isherman@chromium.org</owner>
   <owner>hansberry@chromium.org</owner>
   <summary>
     Whether the user's phone has a secure screen lock installed. Recorded during
@@ -26838,7 +26820,6 @@
 
 <histogram name="EasyUnlock.Setup.Devices.HasTrustAgentEnabled"
     enum="EasyUnlockHasTrustAgentEnabled">
-  <owner>isherman@chromium.org</owner>
   <owner>hansberry@chromium.org</owner>
   <summary>
     Whether the user's phone has a trust agent -- e.g. Smart Lock for Android --
@@ -26856,7 +26837,6 @@
 
 <histogram name="EasyUnlock.Setup.Devices.IneligibilityReason"
     enum="EasyUnlockDeviceIneligibilityReason">
-  <owner>isherman@chromium.org</owner>
   <owner>hansberry@chromium.org</owner>
   <summary>
     Records the most actionable reason why none of a user's devices were
@@ -26876,6 +26856,7 @@
 
 <histogram name="EasyUnlock.Setup.Progress.SansPromo"
     enum="EasyUnlockSetupProgress">
+  <owner>hansberry@chromium.org</owner>
   <owner>jhawkins@chromium.org</owner>
   <summary>
     Records events at each step of the Setup process, when the Setup flow is
@@ -26885,6 +26866,7 @@
 
 <histogram name="EasyUnlock.Setup.Progress.ViaPromo"
     enum="EasyUnlockSetupProgress">
+  <owner>hansberry@chromium.org</owner>
   <owner>jhawkins@chromium.org</owner>
   <summary>
     Records events at each step of the Setup process, when the Setup flow is
@@ -26894,7 +26876,6 @@
 
 <histogram name="EasyUnlock.Setup.PromoNotificationEvent"
     enum="EasyUnlockPromoNotificationEvent">
-  <owner>isherman@chromium.org</owner>
   <owner>hansberry@chromium.org</owner>
   <summary>
     Measures user interactions with the Smart Lock promo notification.
@@ -26924,7 +26905,6 @@
     Deprecated 02/2015; replaced by EasyUnlock.AuthEvent.SignIn.
   </obsolete>
   <owner>hansberry@chromium.org</owner>
-  <owner>xiyuan@google.com</owner>
   <summary>
     Measures the use of Easy sign-in: records whether an Easy sign-in login
     succeeded or failed; or if a password fallback was used, the reason why.
@@ -26934,8 +26914,7 @@
 </histogram>
 
 <histogram name="EasyUnlock.StartupTimeFromSuspend" units="ms">
-  <owner>joshwoodward@google.com</owner>
-  <owner>tengs@chromium.org</owner>
+  <owner>hansberry@chromium.com</owner>
   <summary>
     The time it takes after resuming from a suspended state (ie. opening the
     Chromebook lid) to when a remote device is connected and a request is made.
@@ -26947,7 +26926,6 @@
 </histogram>
 
 <histogram name="EasyUnlock.TrialRun.Events" enum="EasyUnlockTrialRunEvents">
-  <owner>isherman@chromium.org</owner>
   <owner>hansberry@chromium.org</owner>
   <summary>
     Records when the Easy Unlock trial run is launched, and when the user
@@ -46211,6 +46189,18 @@
   </summary>
 </histogram>
 
+<histogram name="Media.Audio.Bitstream" enum="BooleanSupported"
+    expires_after="2019-07-31">
+<!-- Name completed by histogram_suffixes name="BitstreamAudioFormats" -->
+
+  <owner>dalecurtis@chromium.org</owner>
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    Records whether the given bitstream audio output format is supported.
+    Recorded when the browser or audio process AudioManager is constructed.
+  </summary>
+</histogram>
+
 <histogram name="Media.Audio.Capture.CallbackError" enum="BooleanError">
   <obsolete>
     Deprecated as of 02/2017.
@@ -91246,7 +91236,7 @@
 </histogram>
 
 <histogram name="PushMessaging.DeliveryStatus" enum="PushDeliveryStatus">
-  <owner>peter@google.com</owner>
+  <owner>peter@chromium.org</owner>
   <summary>
     When a Service Worker receives a push message, this records whether the
     overall operation was successful, or otherwise the type of error
@@ -91256,7 +91246,7 @@
 
 <histogram name="PushMessaging.DeliveryStatus.FindServiceWorker"
     enum="ServiceWorkerStatusCode">
-  <owner>peter@google.com</owner>
+  <owner>peter@chromium.org</owner>
   <summary>
     When attempting to deliver a push message to a Service Worker, this records
     the result of finding the Service Worker registration given its ID and
@@ -91266,7 +91256,7 @@
 
 <histogram name="PushMessaging.DeliveryStatus.ServiceWorkerEvent"
     enum="ServiceWorkerStatusCode">
-  <owner>peter@google.com</owner>
+  <owner>peter@chromium.org</owner>
   <summary>
     When a Service Worker receives a push message, this records the precise
     result received from the Service Worker code.
@@ -91275,7 +91265,7 @@
 
 <histogram name="PushMessaging.GetRegistrationStatus"
     enum="PushGetRegistrationStatus">
-  <owner>peter@google.com</owner>
+  <owner>peter@chromium.org</owner>
   <summary>
     When a webpage asks for details about its current push messaging
     registration, this records whether the request is successful, or otherwise
@@ -91306,7 +91296,7 @@
 
 <histogram name="PushMessaging.RegistrationStatus"
     enum="PushRegistrationStatus">
-  <owner>peter@google.com</owner>
+  <owner>peter@chromium.org</owner>
   <summary>
     When a webpage registers for push messaging, this records whether the
     request is successful, or otherwise the type of error encountered.
@@ -91354,7 +91344,7 @@
 </histogram>
 
 <histogram name="PushMessaging.UnregistrationGCMResult" enum="GCMClientResult">
-  <owner>peter@google.com</owner>
+  <owner>peter@chromium.org</owner>
   <summary>
     When unregistering a legacy non-InstanceID push messaging subscription, this
     records the result returned by the GCMDriver (note that exceeding the
@@ -91363,7 +91353,7 @@
 </histogram>
 
 <histogram name="PushMessaging.UnregistrationIIDResult" enum="InstanceIDResult">
-  <owner>peter@google.com</owner>
+  <owner>peter@chromium.org</owner>
   <summary>
     When unregistering an InstanceID push messaging subscription, this records
     the result returned from deleting the InstanceID (note that exceeding the
@@ -91373,7 +91363,7 @@
 
 <histogram name="PushMessaging.UnregistrationReason"
     enum="PushUnregistrationReason">
-  <owner>peter@google.com</owner>
+  <owner>peter@chromium.org</owner>
   <summary>
     When unregistering a website from push messaging, this records the reason
     why it is being unregistered.
@@ -91382,7 +91372,7 @@
 
 <histogram name="PushMessaging.UnregistrationStatus"
     enum="PushUnregistrationStatus">
-  <owner>peter@google.com</owner>
+  <owner>peter@chromium.org</owner>
   <summary>
     When unregistering a website from push messaging, this records whether the
     request is successful, or otherwise the type of error encountered.
@@ -91390,7 +91380,7 @@
 </histogram>
 
 <histogram name="PushMessaging.UserVisibleStatus" enum="PushUserVisibleStatus">
-  <owner>peter@google.com</owner>
+  <owner>peter@chromium.org</owner>
   <summary>
     When a Service Worker receives a push message, this records whether it
     showed user-visible UX (like a notification), or whether we showed a forced
@@ -110255,6 +110245,38 @@
   </summary>
 </histogram>
 
+<histogram
+    name="SmartLock.Performance.AuthenticationToReceiveUnlockableRemoteStatus.Duration.Unlock"
+    units="ms" expires_after="2020-02-01">
+  <owner>hansberry@chromium.org</owner>
+  <summary>
+    The duration of time between when Smart Lock successfully establishes a
+    secure channel connection to the host device, and receives an
+    &quot;authenticated&quot; remote status from it (i.e., the Smart Lock icon
+    becomes green).
+  </summary>
+</histogram>
+
+<histogram
+    name="SmartLock.Performance.StartScanToReceiveUnlockableRemoteStatus.Duration.Unlock"
+    units="ms" expires_after="2020-02-01">
+  <owner>hansberry@chromium.org</owner>
+  <summary>
+    The duration of time between when Smart Lock begins to try to find the host
+    device, and receives an &quot;authenticated&quot; remote status from it,
+    which allows the device to be unlocked (i.e., the Smart Lock icon becomes
+    green).
+
+    See
+    MultiDevice.SecureChannel.BLE.Performance.StartScanToAuthenticationDuration.Background
+    and SmartLock.AuthenticationToReceiveUnlockableRemoteStatus.Unlock.Duration
+    for breakdowns of this metric.
+
+    See SmartLock.GetRemoteStatus.Unlock for the success rate of fetching the
+    remote status from the host.
+  </summary>
+</histogram>
+
 <histogram name="SmartLock.ToggleFeature" enum="BooleanEnabled">
   <owner>jhawkins@chromium.org</owner>
   <summary>
@@ -111189,7 +111211,7 @@
 </histogram>
 
 <histogram name="Stability.Android.ProcessedMinidumps"
-    enum="AndroidProcessedMinidumps" expires_after="M74">
+    enum="AndroidProcessedMinidumps" expires_after="M76">
   <owner>mheikal@chromium.org</owner>
   <owner>smaier@chromium.org</owner>
   <owner>wnwen@chromium.org</owner>
@@ -133017,6 +133039,15 @@
   <affected-histogram name="WebRTC.Stun.BatchSuccessPercent.UnknownNAT"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="BitstreamAudioFormats" separator=".">
+  <suffix name="AC3" label="Dolby Digital / AC3"/>
+  <suffix name="DTS" label="DTS"/>
+  <suffix name="DTS-HD" label="DTS-HD"/>
+  <suffix name="EAC3" label="Dolby Digital Plus / EAC3"/>
+  <suffix name="TrueHD" label="Dolby TrueHD"/>
+  <affected-histogram name="Media.Audio.Bitstream"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="BlinkCanvasDrawImageSizeType" separator=".">
   <suffix name="Canvas.CPU"/>
   <suffix name="Canvas.GPU"/>
diff --git a/tools/translation/upload_screenshots.py b/tools/translation/upload_screenshots.py
index 355d484..0e2d430 100755
--- a/tools/translation/upload_screenshots.py
+++ b/tools/translation/upload_screenshots.py
@@ -154,7 +154,12 @@
                                  os.path.join(src_path,
                                               TRANSLATION_EXPECTATIONS_PATH))
   if not screenshots:
-    print 'No screenshots found, exiting.'
+    print ("No screenshots found.\n\n"
+           "- Screenshots must be located in the correct directory.\n"
+           "  E.g. For IDS_HELLO_WORLD message in path/to/file.grd, save the "
+           "screenshot at path/to/file_grd/IDS_HELLO_WORLD.png.\n"
+           "- If you added a new, uncommitted .grd file, `git add` it so that "
+           "this script can pick up its screenshot directory.")
     exit(0)
 
   print 'Found %d updated screenshot(s): ' % len(screenshots)
diff --git a/ui/accelerated_widget_mac/ca_renderer_layer_tree.h b/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
index a4e7fe3..42e274c 100644
--- a/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
+++ b/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
@@ -81,6 +81,10 @@
     bool AddContentLayer(CARendererLayerTree* tree,
                          const CARendererLayerParams& params);
 
+    // Workaround for https://crbug.com/923427. Only allow any
+    // AVSampleBufferDisplayLayer if there is exactly one video quad.
+    void EnforceOnlyOneAVLayer();
+
     // Allocate CALayers for this layer and its children, and set their
     // properties appropriately. Re-use the CALayers from |old_layer| if
     // possible. If re-using a CALayer from |old_layer|, reset its |ca_layer|
@@ -92,7 +96,7 @@
 
     // Return true if the CALayer tree is just a video layer on a black or
     // transparent background, false otherwise.
-    bool WantsFullcreenLowPowerBackdrop();
+    bool WantsFullcreenLowPowerBackdrop() const;
 
     std::vector<ClipAndSortingLayer> clip_and_sorting_layers;
     base::scoped_nsobject<CALayer> ca_layer;
diff --git a/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm b/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
index 1c5988fe..c9b20cf4 100644
--- a/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
+++ b/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
@@ -238,7 +238,7 @@
   scale_factor_ = scale_factor;
 }
 
-bool CARendererLayerTree::RootLayer::WantsFullcreenLowPowerBackdrop() {
+bool CARendererLayerTree::RootLayer::WantsFullcreenLowPowerBackdrop() const {
   bool found_video_layer = false;
   for (auto& clip_layer : clip_and_sorting_layers) {
     for (auto& transform_layer : clip_layer.transform_layers) {
@@ -271,6 +271,28 @@
   return found_video_layer;
 }
 
+void CARendererLayerTree::RootLayer::EnforceOnlyOneAVLayer() {
+  size_t video_layer_count = 0;
+  for (auto& clip_layer : clip_and_sorting_layers) {
+    for (auto& transform_layer : clip_layer.transform_layers) {
+      for (auto& content_layer : transform_layer.content_layers) {
+        if (content_layer.use_av_layer)
+          video_layer_count += 1;
+      }
+    }
+  }
+  if (video_layer_count <= 1)
+    return;
+  for (auto& clip_layer : clip_and_sorting_layers) {
+    for (auto& transform_layer : clip_layer.transform_layers) {
+      for (auto& content_layer : transform_layer.content_layers) {
+        if (content_layer.use_av_layer)
+          content_layer.use_av_layer = false;
+      }
+    }
+  }
+}
+
 id CARendererLayerTree::ContentsForSolidColorForTesting(SkColor color) {
   return SolidColorContents::Get(color)->GetContents();
 }
@@ -566,6 +588,8 @@
     DLOG(ERROR) << "CARendererLayerTree root layer not attached to tree.";
   }
 
+  EnforceOnlyOneAVLayer();
+
   if (WantsFullcreenLowPowerBackdrop()) {
     const gfx::RectF bg_rect(
         ScaleSize(gfx::SizeF(pixel_size), 1 / scale_factor));
diff --git a/ui/aura/env.cc b/ui/aura/env.cc
index fd82e8f..cbb9935 100644
--- a/ui/aura/env.cc
+++ b/ui/aura/env.cc
@@ -325,6 +325,9 @@
   if (mode_ == Mode::MUS) {
     EnableMusOSExchangeDataProvider();
     EnableMusOverrideInputInjector();
+    // Remote clients should not throttle, only the window-service should
+    // throttle (which corresponds to Mode::LOCAL).
+    throttle_input_on_resize_ = false;
     return;
   }
 
diff --git a/ui/aura/window_tree_host.cc b/ui/aura/window_tree_host.cc
index 7c2b6f99..b3db18d 100644
--- a/ui/aura/window_tree_host.cc
+++ b/ui/aura/window_tree_host.cc
@@ -540,7 +540,7 @@
   dispatcher()->OnCursorMovedToRootLocation(root_location);
 }
 
-void WindowTreeHost::OnCompositingDidCommit(ui::Compositor* compositor) {
+void WindowTreeHost::OnCompositingEnded(ui::Compositor* compositor) {
   if (!holding_pointer_moves_)
     return;
 
diff --git a/ui/aura/window_tree_host.h b/ui/aura/window_tree_host.h
index ccaeef8..5a33164 100644
--- a/ui/aura/window_tree_host.h
+++ b/ui/aura/window_tree_host.h
@@ -341,7 +341,7 @@
                             const gfx::Point& host_location);
 
   // Overrided from CompositorObserver:
-  void OnCompositingDidCommit(ui::Compositor* compositor) override;
+  void OnCompositingEnded(ui::Compositor* compositor) override;
   void OnCompositingChildResizing(ui::Compositor* compositor) override;
   void OnCompositingShuttingDown(ui::Compositor* compositor) override;
 
diff --git a/ui/aura/window_tree_host_unittest.cc b/ui/aura/window_tree_host_unittest.cc
index abbe0b8..9404b14 100644
--- a/ui/aura/window_tree_host_unittest.cc
+++ b/ui/aura/window_tree_host_unittest.cc
@@ -59,8 +59,8 @@
   // effect of prioritizing the resize event above other operations in aura.
   EXPECT_TRUE(dispatcher_api.HoldingPointerMoves());
 
-  // Wait for a CompositorFrame to be submitted.
-  ui::DrawWaiterForTest::WaitForCompositingStarted(host()->compositor());
+  // Wait for a CompositorFrame to be activated.
+  ui::DrawWaiterForTest::WaitForCompositingEnded(host()->compositor());
 
   // Pointer moves should be routed normally after commit.
   EXPECT_FALSE(dispatcher_api.HoldingPointerMoves());
diff --git a/ui/base/glib/glib_signal.h b/ui/base/glib/glib_signal.h
index 23630f47..a0eec52c7 100644
--- a/ui/base/glib/glib_signal.h
+++ b/ui/base/glib/glib_signal.h
@@ -20,135 +20,129 @@
 // the headers and the implementations shouldn't be filled with "context->"
 // de-references.
 
-#define CHROMEG_CALLBACK_0(CLASS, RETURN, METHOD, SENDER)           \
-  static RETURN METHOD ## Thunk(SENDER sender, gpointer userdata) { \
-    return reinterpret_cast<CLASS*>(userdata)->METHOD(sender);      \
-  }                                                                 \
-                                                                    \
-  RETURN METHOD(SENDER);
+#define CHROMEG_CALLBACK_0(CLASS, RETURN, METHOD, SENDER)         \
+  static RETURN METHOD##Thunk(SENDER sender, gpointer userdata) { \
+    return reinterpret_cast<CLASS*>(userdata)->METHOD(sender);    \
+  }                                                               \
+                                                                  \
+  RETURN METHOD(SENDER)
 
-#define CHROMEG_CALLBACK_1(CLASS, RETURN, METHOD, SENDER, ARG1)     \
-  static RETURN METHOD ## Thunk(SENDER sender, ARG1 one,            \
-                                gpointer userdata) {                \
-    return reinterpret_cast<CLASS*>(userdata)->METHOD(sender, one); \
-  }                                                                 \
-                                                                    \
-  RETURN METHOD(SENDER, ARG1);
+#define CHROMEG_CALLBACK_1(CLASS, RETURN, METHOD, SENDER, ARG1)             \
+  static RETURN METHOD##Thunk(SENDER sender, ARG1 one, gpointer userdata) { \
+    return reinterpret_cast<CLASS*>(userdata)->METHOD(sender, one);         \
+  }                                                                         \
+                                                                            \
+  RETURN METHOD(SENDER, ARG1)
 
 #define CHROMEG_CALLBACK_2(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2)    \
-  static RETURN METHOD ## Thunk(SENDER sender, ARG1 one, ARG2 two,       \
-                                gpointer userdata) {                     \
+  static RETURN METHOD##Thunk(SENDER sender, ARG1 one, ARG2 two,         \
+                              gpointer userdata) {                       \
     return reinterpret_cast<CLASS*>(userdata)->METHOD(sender, one, two); \
   }                                                                      \
                                                                          \
-  RETURN METHOD(SENDER, ARG1, ARG2);
+  RETURN METHOD(SENDER, ARG1, ARG2)
 
-#define CHROMEG_CALLBACK_3(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2, ARG3) \
-  static RETURN METHOD ## Thunk(SENDER sender, ARG1 one, ARG2 two,          \
-                                ARG3 three, gpointer userdata) {            \
-    return reinterpret_cast<CLASS*>(userdata)->                             \
-        METHOD(sender, one, two, three);                                    \
+#define CHROMEG_CALLBACK_3(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2, ARG3)  \
+  static RETURN METHOD##Thunk(SENDER sender, ARG1 one, ARG2 two, ARG3 three, \
+                              gpointer userdata) {                           \
+    return reinterpret_cast<CLASS*>(userdata)->METHOD(sender, one, two,      \
+                                                      three);                \
+  }                                                                          \
+                                                                             \
+  RETURN METHOD(SENDER, ARG1, ARG2, ARG3)
+
+#define CHROMEG_CALLBACK_4(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2, ARG3,    \
+                           ARG4)                                               \
+  static RETURN METHOD##Thunk(SENDER sender, ARG1 one, ARG2 two, ARG3 three,   \
+                              ARG4 four, gpointer userdata) {                  \
+    return reinterpret_cast<CLASS*>(userdata)->METHOD(sender, one, two, three, \
+                                                      four);                   \
+  }                                                                            \
+                                                                               \
+  RETURN METHOD(SENDER, ARG1, ARG2, ARG3, ARG4)
+
+#define CHROMEG_CALLBACK_5(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2, ARG3,    \
+                           ARG4, ARG5)                                         \
+  static RETURN METHOD##Thunk(SENDER sender, ARG1 one, ARG2 two, ARG3 three,   \
+                              ARG4 four, ARG5 five, gpointer userdata) {       \
+    return reinterpret_cast<CLASS*>(userdata)->METHOD(sender, one, two, three, \
+                                                      four, five);             \
+  }                                                                            \
+                                                                               \
+  RETURN METHOD(SENDER, ARG1, ARG2, ARG3, ARG4, ARG5)
+
+#define CHROMEG_CALLBACK_6(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2, ARG3,    \
+                           ARG4, ARG5, ARG6)                                   \
+  static RETURN METHOD##Thunk(SENDER sender, ARG1 one, ARG2 two, ARG3 three,   \
+                              ARG4 four, ARG5 five, ARG6 six,                  \
+                              gpointer userdata) {                             \
+    return reinterpret_cast<CLASS*>(userdata)->METHOD(sender, one, two, three, \
+                                                      four, five, six);        \
+  }                                                                            \
+                                                                               \
+  RETURN METHOD(SENDER, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6)
+
+#define CHROMEG_VIRTUAL_CALLBACK_0(CLASS, RETURN, METHOD, SENDER) \
+  static RETURN METHOD##Thunk(SENDER sender, gpointer userdata) { \
+    return reinterpret_cast<CLASS*>(userdata)->METHOD(sender);    \
+  }                                                               \
+                                                                  \
+  virtual RETURN METHOD(SENDER)
+
+#define CHROMEG_VIRTUAL_CALLBACK_1(CLASS, RETURN, METHOD, SENDER, ARG1)     \
+  static RETURN METHOD##Thunk(SENDER sender, ARG1 one, gpointer userdata) { \
+    return reinterpret_cast<CLASS*>(userdata)->METHOD(sender, one);         \
   }                                                                         \
                                                                             \
-  RETURN METHOD(SENDER, ARG1, ARG2, ARG3);
-
-#define CHROMEG_CALLBACK_4(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2, ARG3, \
-                           ARG4)                                            \
-  static RETURN METHOD ## Thunk(SENDER sender, ARG1 one, ARG2 two,          \
-                                ARG3 three, ARG4 four,                      \
-                                gpointer userdata) {                        \
-    return reinterpret_cast<CLASS*>(userdata)->                             \
-        METHOD(sender, one, two, three, four);                              \
-  }                                                                         \
-                                                                            \
-  RETURN METHOD(SENDER, ARG1, ARG2, ARG3, ARG4);
-
-#define CHROMEG_CALLBACK_5(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2, ARG3, \
-                           ARG4, ARG5)                                      \
-  static RETURN METHOD ## Thunk(SENDER sender, ARG1 one, ARG2 two,          \
-                                ARG3 three, ARG4 four, ARG5 five,           \
-                                gpointer userdata) {                        \
-    return reinterpret_cast<CLASS*>(userdata)->                             \
-        METHOD(sender, one, two, three, four, five);                        \
-  }                                                                         \
-                                                                            \
-  RETURN METHOD(SENDER, ARG1, ARG2, ARG3, ARG4, ARG5);
-
-#define CHROMEG_CALLBACK_6(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2, ARG3, \
-                           ARG4, ARG5, ARG6)                                \
-  static RETURN METHOD ## Thunk(SENDER sender, ARG1 one, ARG2 two,          \
-                                ARG3 three, ARG4 four, ARG5 five,           \
-                                ARG6 six, gpointer userdata) {              \
-    return reinterpret_cast<CLASS*>(userdata)->                             \
-        METHOD(sender, one, two, three, four, five, six);                   \
-  }                                                                         \
-                                                                            \
-  RETURN METHOD(SENDER, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
-
-#define CHROMEG_VIRTUAL_CALLBACK_0(CLASS, RETURN, METHOD, SENDER)   \
-  static RETURN METHOD ## Thunk(SENDER sender, gpointer userdata) { \
-    return reinterpret_cast<CLASS*>(userdata)->METHOD(sender);      \
-  }                                                                 \
-                                                                    \
-  virtual RETURN METHOD(SENDER);
-
-#define CHROMEG_VIRTUAL_CALLBACK_1(CLASS, RETURN, METHOD, SENDER, ARG1) \
-  static RETURN METHOD ## Thunk(SENDER sender, ARG1 one,                \
-                                gpointer userdata) {                    \
-    return reinterpret_cast<CLASS*>(userdata)->METHOD(sender, one);     \
-  }                                                                     \
-                                                                        \
-  virtual RETURN METHOD(SENDER, ARG1);
+  virtual RETURN METHOD(SENDER, ARG1)
 
 #define CHROMEG_VIRTUAL_CALLBACK_2(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2) \
-  static RETURN METHOD ## Thunk(SENDER sender, ARG1 one, ARG2 two,            \
-                                gpointer userdata) {                          \
+  static RETURN METHOD##Thunk(SENDER sender, ARG1 one, ARG2 two,              \
+                              gpointer userdata) {                            \
     return reinterpret_cast<CLASS*>(userdata)->METHOD(sender, one, two);      \
   }                                                                           \
                                                                               \
-  virtual RETURN METHOD(SENDER, ARG1, ARG2);
+  virtual RETURN METHOD(SENDER, ARG1, ARG2)
 
 #define CHROMEG_VIRTUAL_CALLBACK_3(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2, \
                                    ARG3)                                      \
-  static RETURN METHOD ## Thunk(SENDER sender, ARG1 one, ARG2 two,            \
-                                ARG3 three, gpointer userdata) {              \
-    return reinterpret_cast<CLASS*>(userdata)->                               \
-        METHOD(sender, one, two, three);                                      \
+  static RETURN METHOD##Thunk(SENDER sender, ARG1 one, ARG2 two, ARG3 three,  \
+                              gpointer userdata) {                            \
+    return reinterpret_cast<CLASS*>(userdata)->METHOD(sender, one, two,       \
+                                                      three);                 \
   }                                                                           \
                                                                               \
-  virtual RETURN METHOD(SENDER, ARG1, ARG2, ARG3);
+  virtual RETURN METHOD(SENDER, ARG1, ARG2, ARG3)
 
-#define CHROMEG_VIRTUAL_CALLBACK_4(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2, \
-                                   ARG3, ARG4)                                \
-  static RETURN METHOD ## Thunk(SENDER sender, ARG1 one, ARG2 two,            \
-                                ARG3 three, ARG4 four,                        \
-                                gpointer userdata) {                          \
-    return reinterpret_cast<CLASS*>(userdata)->                               \
-        METHOD(sender, one, two, three, four);                                \
-  }                                                                           \
-                                                                              \
-  virtual RETURN METHOD(SENDER, ARG1, ARG2, ARG3, ARG4);
+#define CHROMEG_VIRTUAL_CALLBACK_4(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2,  \
+                                   ARG3, ARG4)                                 \
+  static RETURN METHOD##Thunk(SENDER sender, ARG1 one, ARG2 two, ARG3 three,   \
+                              ARG4 four, gpointer userdata) {                  \
+    return reinterpret_cast<CLASS*>(userdata)->METHOD(sender, one, two, three, \
+                                                      four);                   \
+  }                                                                            \
+                                                                               \
+  virtual RETURN METHOD(SENDER, ARG1, ARG2, ARG3, ARG4)
 
-#define CHROMEG_VIRTUAL_CALLBACK_5(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2, \
-                                   ARG3,  ARG4, ARG5)                         \
-  static RETURN METHOD ## Thunk(SENDER sender, ARG1 one, ARG2 two,            \
-                                ARG3 three, ARG4 four, ARG5 five,             \
-                                gpointer userdata) {                          \
-    return reinterpret_cast<CLASS*>(userdata)->                               \
-        METHOD(sender, one, two, three, four, five);                          \
-  }                                                                           \
-                                                                              \
-  virtual RETURN METHOD(SENDER, ARG1, ARG2, ARG3, ARG4, ARG5);
+#define CHROMEG_VIRTUAL_CALLBACK_5(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2,  \
+                                   ARG3, ARG4, ARG5)                           \
+  static RETURN METHOD##Thunk(SENDER sender, ARG1 one, ARG2 two, ARG3 three,   \
+                              ARG4 four, ARG5 five, gpointer userdata) {       \
+    return reinterpret_cast<CLASS*>(userdata)->METHOD(sender, one, two, three, \
+                                                      four, five);             \
+  }                                                                            \
+                                                                               \
+  virtual RETURN METHOD(SENDER, ARG1, ARG2, ARG3, ARG4, ARG5)
 
-#define CHROMEG_VIRTUAL_CALLBACK_6(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2, \
-                                   ARG3, ARG4, ARG5, ARG6)                    \
-  static RETURN METHOD ## Thunk(SENDER sender, ARG1 one, ARG2 two,            \
-                                ARG3 three, ARG4 four, ARG5 five,             \
-                                ARG6 six, gpointer userdata) {                \
-    return reinterpret_cast<CLASS*>(userdata)->                               \
-        METHOD(sender, one, two, three, four, five, six);                     \
-  }                                                                           \
-                                                                              \
-  virtual RETURN METHOD(SENDER, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+#define CHROMEG_VIRTUAL_CALLBACK_6(CLASS, RETURN, METHOD, SENDER, ARG1, ARG2,  \
+                                   ARG3, ARG4, ARG5, ARG6)                     \
+  static RETURN METHOD##Thunk(SENDER sender, ARG1 one, ARG2 two, ARG3 three,   \
+                              ARG4 four, ARG5 five, ARG6 six,                  \
+                              gpointer userdata) {                             \
+    return reinterpret_cast<CLASS*>(userdata)->METHOD(sender, one, two, three, \
+                                                      four, five, six);        \
+  }                                                                            \
+                                                                               \
+  virtual RETURN METHOD(SENDER, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6)
 
 #endif
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index f9227d7..83d1ef4 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -192,6 +192,7 @@
     "event_modifiers.cc",
     "event_processor.cc",
     "event_rewriter.cc",
+    "event_rewriter_continuation.h",
     "event_source.cc",
     "event_target.cc",
     "event_utils.cc",
diff --git a/ui/events/event_rewriter.cc b/ui/events/event_rewriter.cc
index d9efe7e..d3752be 100644
--- a/ui/events/event_rewriter.cc
+++ b/ui/events/event_rewriter.cc
@@ -4,13 +4,99 @@
 
 #include "ui/events/event_rewriter.h"
 
+#include <utility>
+
+#include "ui/events/event_rewriter_continuation.h"
 #include "ui/events/event_source.h"
 
 namespace ui {
 
+namespace {
+
+ui::EventDispatchDetails DispatcherDestroyed() {
+  ui::EventDispatchDetails details;
+  details.dispatcher_destroyed = true;
+  return details;
+}
+
+}  // anonymous namespace
+
+// Temporary fallback implementation, in terms of the old API,
+// factored out of EventSource::SendEventToSinkFromRewriter().
+// TODO(kpschoedel): Remove along with old API.
+EventDispatchDetails EventRewriter::RewriteEvent(
+    const Event& event,
+    const Continuation continuation) {
+  std::unique_ptr<Event> rewritten_event;
+  EventRewriteStatus status = RewriteEvent(event, &rewritten_event);
+  if (status == EVENT_REWRITE_DISCARD) {
+    CHECK(!rewritten_event);
+    return continuation->DiscardEvent();
+  }
+  if (status == EVENT_REWRITE_CONTINUE) {
+    CHECK(!rewritten_event);
+    return continuation->SendEvent(&event);
+  }
+  CHECK(rewritten_event);
+  EventDispatchDetails details =
+      continuation->SendEventFinally(rewritten_event.get());
+  while (status == EVENT_REWRITE_DISPATCH_ANOTHER) {
+    if (details.dispatcher_destroyed)
+      return details;
+    std::unique_ptr<Event> new_event;
+    status = NextDispatchEvent(*rewritten_event, &new_event);
+    if (status == EVENT_REWRITE_DISCARD)
+      return continuation->DiscardEvent();
+    CHECK_NE(EVENT_REWRITE_CONTINUE, status);
+    CHECK(new_event);
+    details = continuation->SendEventFinally(new_event.get());
+    rewritten_event = std::move(new_event);
+  }
+  return details;
+}
+
+// Temporary default implementation of the old API, so that subclasses'
+// implementations can be removed.
+// TODO(kpschoedel): Remove old API.
+EventRewriteStatus EventRewriter::RewriteEvent(
+    const Event& event,
+    std::unique_ptr<Event>* rewritten_event) {
+  NOTREACHED();
+  return EVENT_REWRITE_DISCARD;
+}
+
+// Temporary default implementation of the old API, so that subclasses'
+// implementations can be removed.
+// TODO(kpschoedel): Remove old API.
+EventRewriteStatus EventRewriter::NextDispatchEvent(
+    const Event& last_event,
+    std::unique_ptr<Event>* new_event) {
+  NOTREACHED();
+  return EVENT_REWRITE_DISCARD;
+}
+
+// TODO(kpschoedel): Remove old API.
 EventDispatchDetails EventRewriter::SendEventToEventSource(EventSource* source,
                                                            Event* event) const {
   return source->SendEventToSinkFromRewriter(event, this);
 }
 
+EventDispatchDetails EventRewriter::SendEvent(const Continuation continuation,
+                                              const Event* event) {
+  return continuation ? continuation->SendEvent(event) : DispatcherDestroyed();
+}
+
+EventDispatchDetails EventRewriter::SendEventFinally(
+    const Continuation continuation,
+    const Event* event) {
+  return continuation ? continuation->SendEventFinally(event)
+                      : DispatcherDestroyed();
+}
+
+EventDispatchDetails EventRewriter::DiscardEvent(
+    const Continuation continuation) {
+  return continuation ? continuation->DiscardEvent()
+                      : DispatcherDestroyed();
+}
+
 }  // namespace ui
diff --git a/ui/events/event_rewriter.h b/ui/events/event_rewriter.h
index a096aa9..61a675ac 100644
--- a/ui/events/event_rewriter.h
+++ b/ui/events/event_rewriter.h
@@ -8,28 +8,47 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "ui/events/event_dispatcher.h"
 #include "ui/events/events_export.h"
 
 namespace ui {
 
 class Event;
-class EventSource;
+class EventRewriterContinuation;
+class EventSource;  // TODO(kpschoedel): Remove with old API.
 
 // Return status of EventRewriter operations; see that class below.
+// TODO(kpschoedel): Remove old API.
 enum EventRewriteStatus {
   // Nothing was done; no rewritten event returned. Pass the original
   // event to later rewriters, or send it to the EventSink if this
   // was the final rewriter.
+  //
+  // TODO(kpschoedel): Replace old API uses of
+  //    return EVENT_REWRITE_CONTINUE;
+  // with new API
+  //    return SendEvent(continuation, &incoming_event);
   EVENT_REWRITE_CONTINUE,
 
   // The event has been rewritten. Send the rewritten event to the
   // EventSink instead of the original event (without sending
   // either to any later rewriters).
+  //
+  // TODO(kpschoedel): Replace old API uses of
+  //    *rewritten_event = std::move(replacement_event);
+  //    return EVENT_REWRITE_REWRITTEN;
+  // with new API
+  //    return SendEventFinally(continuation, replacement_event);
   EVENT_REWRITE_REWRITTEN,
 
   // The event should be discarded, neither passing it to any later
   // rewriters nor sending it to the EventSink.
+  //
+  // TODO(kpschoedel): Replace old API uses of
+  //    return EVENT_REWRITE_DISCARD;
+  // with new API
+  //    return DiscardEvent(continuation);
   EVENT_REWRITE_DISCARD,
 
   // The event has been rewritten. As for EVENT_REWRITE_REWRITTEN,
@@ -38,6 +57,15 @@
   // In addition the rewriter has one or more additional new events
   // to be retrieved using |NextDispatchEvent()| and sent to the
   // EventSink.
+  //
+  // TODO(kpschoedel): Replace old API uses of
+  //    *rewritten_event = std::move(new_event_1);
+  //    // record new_event_2 … new_event_N
+  //    return EVENT_REWRITE_DISPATCH_ANOTHER;
+  // with new API
+  //    details = SendEventFinally(new_event_1);
+  //    â‹®
+  //    return SendEventFinally(new_event_N);
   EVENT_REWRITE_DISPATCH_ANOTHER,
 };
 
@@ -45,17 +73,62 @@
 // before being dispatched from EventSource to EventSink.
 class EVENTS_EXPORT EventRewriter {
  public:
+  // Copyable opaque type, to be used only as an argument to SendEvent(),
+  // SendEventFinally(), or DiscardEvent(). The current implementation is
+  // a WeakPtr because some EventRewriters outlive their registration and
+  // can try to send events through an absent source (e.g. from a timer).
+  using Continuation = base::WeakPtr<EventRewriterContinuation>;
+
   EventRewriter() = default;
   virtual ~EventRewriter() = default;
 
+  // Potentially rewrites (replaces) an event, possibly with multiple events,
+  // or causes it to be discarded.
+  //
+  // To accept the supplied event without change,
+  //    return SendEvent(continuation, &event)
+  //
+  // To replace the supplied event with a new event, call either
+  //    return SendEvent(continuation, new_event)
+  // or
+  //    return SendEventFinally(continuation, new_event)
+  // depending on whether or not |new_event| should be provided to any
+  // later rewriters. These functions can be called more than once to
+  // replace an incoming event with multiple new events; when doing so,
+  // check |details.dispatcher_destroyed| after each call.
+  //
+  // To discard the incoming event without replacement,
+  //    return DiscardEvent()
+  //
+  // In the common case of one event at a time, the EventDispatchDetails
+  // from the above calls can and should be returned directly by RewriteEvent().
+  // When a rewriter generates multiple events synchronously, it should
+  // typically bail and return on a non-vacuous EventDispatchDetails.
+  // When a rewriter generates events asynchronously (e.g. from a timer)
+  // there is no opportunity to return the result directly, but a rewriter
+  // can consider retaining it for the next call.
+  //
+  // The supplied WeakPtr<Continuation> can be saved in order to respond
+  // asynchronously, e.g. after a double-click timeout. Normally, with
+  // EventRewriters subordinate to EventSources, the Continuation lives as
+  // long as the EventRewriter remains registered. If the continuation is not
+  // valid, the Send functions will return with |details.dispatcher_destroyed|.
+  //
+  // Design note: We need to pass the continuation state explicitly because
+  // Ash registers some EventRewriter instances with multiple EventSources.
+  //
+  virtual EventDispatchDetails RewriteEvent(const Event& event,
+                                            const Continuation continuation);
+
   // Potentially rewrites (replaces) an event, or requests it be discarded.
   // or discards an event. If the rewriter wants to rewrite an event, and
   // dispatch another event once the rewritten event is dispatched, it should
   // return EVENT_REWRITE_DISPATCH_ANOTHER, and return the next event to
   // dispatch from |NextDispatchEvent()|.
+  // TODO(kpschoedel): Remove old API.
   virtual EventRewriteStatus RewriteEvent(
       const Event& event,
-      std::unique_ptr<Event>* rewritten_event) = 0;
+      std::unique_ptr<Event>* rewritten_event);
 
   // Supplies an additional event to be dispatched. It is only valid to
   // call this after the immediately previous call to |RewriteEvent()|
@@ -63,13 +136,28 @@
   // Should only return either EVENT_REWRITE_REWRITTEN or
   // EVENT_REWRITE_DISPATCH_ANOTHER; otherwise the previous call should not
   // have returned EVENT_REWRITE_DISPATCH_ANOTHER.
+  // TODO(kpschoedel): Remove old API.
   virtual EventRewriteStatus NextDispatchEvent(
       const Event& last_event,
-      std::unique_ptr<Event>* new_event) = 0;
+      std::unique_ptr<Event>* new_event);
 
  protected:
+  // Forwards an event, through any subsequent rewriters.
+  static EventDispatchDetails SendEvent(const Continuation continuation,
+                                        const Event* event) WARN_UNUSED_RESULT;
+
+  // Forwards an event, skipping any subsequent rewriters.
+  static EventDispatchDetails SendEventFinally(const Continuation continuation,
+                                               const Event* event)
+      WARN_UNUSED_RESULT;
+
+  // Discards an event, so that it will not be passed to the sink.
+  static EventDispatchDetails DiscardEvent(const Continuation continuation)
+      WARN_UNUSED_RESULT;
+
   // A helper that calls a protected EventSource function, which sends the event
   // to subsequent event rewriters on the source and onto its event sink.
+  // TODO(kpschoedel): Replace with SendEvent(continuation, event).
   EventDispatchDetails SendEventToEventSource(EventSource* source,
                                               Event* event) const;
 
diff --git a/ui/events/event_rewriter_continuation.h b/ui/events/event_rewriter_continuation.h
new file mode 100644
index 0000000..0a06a9d4
--- /dev/null
+++ b/ui/events/event_rewriter_continuation.h
@@ -0,0 +1,35 @@
+// 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_EVENTS_EVENT_REWRITER_CONTINUATION_H_
+#define UI_EVENTS_EVENT_REWRITER_CONTINUATION_H_
+
+namespace ui {
+
+struct EventDispatchDetails;
+
+// Used to forward events from an EventRewriter. This is expected to be used
+// only by cooperation between EventSource and EventRewriter. The methods are
+// implemented by a subclass in EventSource, and called only via the
+// corresponding EventRewriter functions (which validate the continuation).
+class EventRewriterContinuation {
+ public:
+  EventRewriterContinuation() = default;
+  virtual ~EventRewriterContinuation() = default;
+
+  // Send an event to the sink, via any later rewriters.
+  virtual EventDispatchDetails SendEvent(const Event* event)
+      WARN_UNUSED_RESULT = 0;
+
+  // Send an event directly to the sink, bypassing any later rewriters.
+  virtual EventDispatchDetails SendEventFinally(const Event* event)
+      WARN_UNUSED_RESULT = 0;
+
+  // Discard an event, bypassing any later rewriters.
+  virtual EventDispatchDetails DiscardEvent() WARN_UNUSED_RESULT = 0;
+};
+
+}  // namespace ui
+
+#endif  // UI_EVENTS_EVENT_REWRITER_CONTINUATION_H_
diff --git a/ui/events/event_rewriter_unittest.cc b/ui/events/event_rewriter_unittest.cc
index 90c5d26..67b1a0d 100644
--- a/ui/events/event_rewriter_unittest.cc
+++ b/ui/events/event_rewriter_unittest.cc
@@ -85,9 +85,9 @@
 // same event type; it is used to test simple rewriting, and rewriter addition,
 // removal, and sequencing. Consequently EVENT_REWRITE_DISPATCH_ANOTHER is not
 // supported here (calls to NextDispatchEvent() would continue indefinitely).
-class TestConstantEventRewriter : public EventRewriter {
+class TestConstantEventRewriterOld : public EventRewriter {
  public:
-  TestConstantEventRewriter(EventRewriteStatus status, EventType type)
+  TestConstantEventRewriterOld(EventRewriteStatus status, EventType type)
       : status_(status), type_(type) {
     CHECK_NE(EVENT_REWRITE_DISPATCH_ANOTHER, status);
   }
@@ -113,9 +113,9 @@
 
 // This EventRewriter runs a simple state machine; it is used to test
 // EVENT_REWRITE_DISPATCH_ANOTHER.
-class TestStateMachineEventRewriter : public EventRewriter {
+class TestStateMachineEventRewriterOld : public EventRewriter {
  public:
-  TestStateMachineEventRewriter() : last_rewritten_event_(0), state_(0) {}
+  TestStateMachineEventRewriterOld() : last_rewritten_event_(0), state_(0) {}
   void AddRule(int from_state, EventType from_type,
                int to_state, EventType to_type, EventRewriteStatus to_status) {
     RewriteResult r = {to_state, to_type, to_status};
@@ -160,27 +160,108 @@
   int state_;
 };
 
+// This EventRewriter always accepts the original event. It is used to test
+// simple rewriting, and rewriter addition, removal, and sequencing.
+class TestAlwaysAcceptEventRewriter : public EventRewriter {
+ public:
+  TestAlwaysAcceptEventRewriter() {}
+  EventDispatchDetails RewriteEvent(const Event& event,
+                                    const Continuation continuation) override {
+    return SendEvent(continuation, &event);
+  }
+};
+
+// This EventRewriter always rewrites with the same event type; it is used
+// to test simple rewriting, and rewriter addition, removal, and sequencing.
+class TestConstantEventRewriter : public EventRewriter {
+ public:
+  explicit TestConstantEventRewriter(EventType type) : type_(type) {}
+  EventDispatchDetails RewriteEvent(const Event& event,
+                                    const Continuation continuation) override {
+    std::unique_ptr<Event> replacement_event = CreateEventForType(type_);
+    return SendEventFinally(continuation, replacement_event.get());
+  }
+
+ private:
+  EventType type_;
+};
+
+// This EventRewriter runs a simple state machine; it is used to test
+// EVENT_REWRITE_DISPATCH_ANOTHER.
+class TestStateMachineEventRewriter : public EventRewriter {
+ public:
+  enum RewriteAction { ACCEPT, DISCARD, REPLACE };
+  enum StateAction { RETURN, PROCEED };
+  TestStateMachineEventRewriter() : state_(0) {}
+  void AddRule(int from_state,
+               EventType from_type,
+               int to_state,
+               EventType to_type,
+               RewriteAction rewrite_action,
+               StateAction state_action) {
+    RewriteResult r = {to_state, to_type, rewrite_action, state_action};
+    rules_.insert({RewriteCase(from_state, from_type), r});
+  }
+  EventDispatchDetails RewriteEvent(const Event& event,
+                                    const Continuation continuation) override {
+    for (;;) {
+      RewriteRules::iterator find =
+          rules_.find(RewriteCase(state_, event.type()));
+      if (find == rules_.end())
+        return SendEvent(continuation, &event);
+      state_ = find->second.state;
+      EventDispatchDetails details;
+      switch (find->second.rewrite_action) {
+        case ACCEPT:
+          details = SendEvent(continuation, &event);
+          break;
+        case DISCARD:
+          break;
+        case REPLACE:
+          details = SendEventFinally(
+              continuation, CreateEventForType(find->second.type).get());
+          break;
+      }
+      if (details.dispatcher_destroyed || find->second.state_action == RETURN)
+        return details;
+    }
+    NOTREACHED();
+  }
+
+ private:
+  typedef std::pair<int, EventType> RewriteCase;
+  struct RewriteResult {
+    int state;
+    EventType type;
+    RewriteAction rewrite_action;
+    StateAction state_action;
+  };
+  typedef std::map<RewriteCase, RewriteResult> RewriteRules;
+  RewriteRules rules_;
+  int state_;
+};
+
 }  // namespace
 
-TEST(EventRewriterTest, EventRewriting) {
+TEST(EventRewriterTest, EventRewritingOld) {
   // TestEventRewriter r0 always rewrites events to ET_CANCEL_MODE;
   // it is placed at the beginning of the chain and later removed,
   // to verify that rewriter removal works.
-  TestConstantEventRewriter r0(EVENT_REWRITE_REWRITTEN, ET_CANCEL_MODE);
+  TestConstantEventRewriterOld r0(EVENT_REWRITE_REWRITTEN, ET_CANCEL_MODE);
 
   // TestEventRewriter r1 always returns EVENT_REWRITE_CONTINUE;
-  // it is placed at the beginning of the chain to verify that a
-  // later rewriter sees the events.
-  TestConstantEventRewriter r1(EVENT_REWRITE_CONTINUE, ET_UNKNOWN);
+  // it is at the beginning of the chain (once r0 is removed)
+  // to verify that a later rewriter sees the events.
+  TestConstantEventRewriterOld r1(EVENT_REWRITE_CONTINUE, ET_UNKNOWN);
 
   // TestEventRewriter r2 has a state machine, primarily to test
   // |EVENT_REWRITE_DISPATCH_ANOTHER|.
-  TestStateMachineEventRewriter r2;
+  TestStateMachineEventRewriterOld r2;
 
   // TestEventRewriter r3 always rewrites events to ET_CANCEL_MODE;
   // it is placed at the end of the chain to verify that previously
   // rewritten events are not passed further down the chain.
-  TestConstantEventRewriter r3(EVENT_REWRITE_REWRITTEN, ET_CANCEL_MODE);
+  TestConstantEventRewriterOld r3(EVENT_REWRITE_REWRITTEN, ET_CANCEL_MODE);
 
   TestEventRewriteProcessor p;
   TestEventRewriteSource s(&p);
@@ -196,6 +277,12 @@
   p.CheckAllReceived();
 
   // Remove r0, and verify that it's gone and that events make it through.
+  // - r0 is removed, so the resulting event should NOT be ET_CANCEL_MODE.
+  // - r2 should rewrite ET_SCROLL_FLING_START to ET_SCROLL_FLING_CANCEL,
+  //   and skip subsequent rewriters, so the resulting event should be
+  //   ET_SCROLL_FLING_CANCEL.
+  // - r3 should be skipped after r2 returns, so the resulting event
+  //   should NOT be ET_CANCEL_MODE.
   s.AddEventRewriter(&r3);
   s.RemoveEventRewriter(&r0);
   r2.AddRule(0, ET_SCROLL_FLING_START,
@@ -223,9 +310,8 @@
   p.AddExpectedEvent(ET_MOUSE_PRESSED);
   s.Send(ET_MOUSE_PRESSED);
 
-  // Removing rewriters r1 and r3 shouldn't affect r2.
+  // Removing rewriter r1 shouldn't affect r2.
   s.RemoveEventRewriter(&r1);
-  s.RemoveEventRewriter(&r3);
 
   // Continue with the state-based rewriting.
   p.AddExpectedEvent(ET_MOUSE_RELEASED);
@@ -234,4 +320,89 @@
   p.CheckAllReceived();
 }
 
+TEST(EventRewriterTest, EventRewriting) {
+  // TestEventRewriter r0 always rewrites events to ET_CANCEL_MODE;
+  // it is placed at the beginning of the chain and later removed,
+  // to verify that rewriter removal works.
+  TestConstantEventRewriter r0(ET_CANCEL_MODE);
+
+  // TestEventRewriter r1 always returns EVENT_REWRITE_CONTINUE;
+  // it is at the beginning of the chain (once r0 is removed)
+  // to verify that a later rewriter sees the events.
+  TestAlwaysAcceptEventRewriter r1;
+
+  // TestEventRewriter r2 has a state machine, primarily to test
+  // |EVENT_REWRITE_DISPATCH_ANOTHER|.
+  TestStateMachineEventRewriter r2;
+
+  // TestEventRewriter r3 always rewrites events to ET_CANCEL_MODE;
+  // it is placed at the end of the chain to verify that previously
+  // rewritten events are not passed further down the chain.
+  TestConstantEventRewriter r3(ET_CANCEL_MODE);
+
+  TestEventRewriteProcessor p;
+  TestEventRewriteSource s(&p);
+  s.AddEventRewriter(&r0);
+  s.AddEventRewriter(&r1);
+  s.AddEventRewriter(&r2);
+
+  // These events should be rewritten by r0 to ET_CANCEL_MODE.
+  p.AddExpectedEvent(ET_CANCEL_MODE);
+  s.Send(ET_MOUSE_DRAGGED);
+  p.AddExpectedEvent(ET_CANCEL_MODE);
+  s.Send(ET_MOUSE_PRESSED);
+  p.CheckAllReceived();
+
+  // Remove r0, and verify that it's gone and that events make it through.
+  // - r0 is removed, so the resulting event should NOT be ET_CANCEL_MODE.
+  // - r2 should rewrite ET_SCROLL_FLING_START to ET_SCROLL_FLING_CANCEL,
+  //   and skip subsequent rewriters, so the resulting event should be
+  //   ET_SCROLL_FLING_CANCEL.
+  // - r3 should be skipped after r2 returns, so the resulting event
+  //   should NOT be ET_CANCEL_MODE.
+  s.AddEventRewriter(&r3);
+  s.RemoveEventRewriter(&r0);
+  r2.AddRule(0, ET_SCROLL_FLING_START, 0, ET_SCROLL_FLING_CANCEL,
+             TestStateMachineEventRewriter::REPLACE,
+             TestStateMachineEventRewriter::RETURN);
+  p.AddExpectedEvent(ET_SCROLL_FLING_CANCEL);
+  s.Send(ET_SCROLL_FLING_START);
+  p.CheckAllReceived();
+  s.RemoveEventRewriter(&r3);
+
+  // Verify replacing an event with multiple events using a state machine
+  // (that happens to be analogous to sticky keys).
+  r2.AddRule(0, ET_KEY_PRESSED, 1, ET_UNKNOWN,
+             TestStateMachineEventRewriter::ACCEPT,
+             TestStateMachineEventRewriter::RETURN);
+  r2.AddRule(1, ET_MOUSE_PRESSED, 0, ET_UNKNOWN,
+             TestStateMachineEventRewriter::ACCEPT,
+             TestStateMachineEventRewriter::RETURN);
+  r2.AddRule(1, ET_KEY_RELEASED, 2, ET_UNKNOWN,
+             TestStateMachineEventRewriter::DISCARD,
+             TestStateMachineEventRewriter::RETURN);
+  r2.AddRule(2, ET_MOUSE_RELEASED, 3, ET_MOUSE_RELEASED,
+             TestStateMachineEventRewriter::REPLACE,
+             TestStateMachineEventRewriter::PROCEED);
+  r2.AddRule(3, ET_MOUSE_RELEASED, 0, ET_KEY_RELEASED,
+             TestStateMachineEventRewriter::REPLACE,
+             TestStateMachineEventRewriter::RETURN);
+  p.AddExpectedEvent(ET_KEY_PRESSED);
+  s.Send(ET_KEY_PRESSED);   // state 0 ET_KEY_PRESSED -> 1 ACCEPT ET_KEY_PRESSED
+  s.Send(ET_KEY_RELEASED);  // state 1 ET_KEY_RELEASED -> 2 DISCARD
+  p.AddExpectedEvent(ET_MOUSE_PRESSED);
+  s.Send(ET_MOUSE_PRESSED);  // no matching rule; pass event through.
+
+  // Removing rewriter r1 shouldn't affect r2.
+  s.RemoveEventRewriter(&r1);
+
+  // Continue with the state-based rewriting.
+  p.AddExpectedEvent(ET_MOUSE_RELEASED);
+  p.AddExpectedEvent(ET_KEY_RELEASED);
+  s.Send(
+      ET_MOUSE_RELEASED);  // 2 ET_MOUSE_RELEASED -> 3 PROCEED ET_MOUSE_RELEASED
+                           // 3 ET_MOUSE_RELEASED -> 0 REPLACE ET_KEY_RELEASED
+  p.CheckAllReceived();
+}
+
 }  // namespace ui
diff --git a/ui/events/event_source.cc b/ui/events/event_source.cc
index 85a6f40..59a6220 100644
--- a/ui/events/event_source.cc
+++ b/ui/events/event_source.cc
@@ -4,13 +4,11 @@
 
 #include "ui/events/event_source.h"
 
-#include <algorithm>
-
-#include "base/stl_util.h"
-#include "ui/events/event_rewriter.h"
+#include "ui/events/event_rewriter_continuation.h"
 #include "ui/events/event_sink.h"
 
 namespace ui {
+
 namespace {
 
 bool IsLocatedEventWithDifferentLocations(const Event& event) {
@@ -23,23 +21,89 @@
 
 }  // namespace
 
+class EventSource::EventRewriterContinuationImpl
+    : public EventRewriterContinuation {
+ public:
+  // Constructs an EventRewriterContinuationImpl at the end of the source's
+  // rewriter list.
+  static void Create(EventSource* const source, EventRewriter* rewriter) {
+    DCHECK(source);
+    DCHECK(rewriter);
+    DCHECK(source->FindContinuation(rewriter) == source->rewriter_list_.end());
+    source->rewriter_list_.push_back(
+        std::make_unique<EventRewriterContinuationImpl>(source, rewriter));
+    EventRewriterList::iterator it = source->rewriter_list_.end();
+    --it;
+    CHECK((*it)->rewriter() == rewriter);
+    (*it)->self_ = it;
+  }
+
+  EventRewriterContinuationImpl(EventSource* const source,
+                                EventRewriter* rewriter)
+      : source_(source),
+        rewriter_(rewriter),
+        self_(source->rewriter_list_.end()),
+        weak_ptr_factory_(this) {}
+  ~EventRewriterContinuationImpl() override {}
+
+  EventRewriter* rewriter() const { return rewriter_; }
+
+  base::WeakPtr<EventRewriterContinuationImpl> GetWeakPtr() {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
+  // EventRewriterContinuation overrides:
+  EventDispatchDetails SendEvent(const Event* event) override {
+    EventRewriterList::iterator next = self_;
+    ++next;
+    if (next == source_->rewriter_list_.end())
+      return SendEventFinally(event);
+    return (*next)->rewriter_->RewriteEvent(*event, (*next)->GetWeakPtr());
+  }
+
+  EventDispatchDetails SendEventFinally(const Event* event) override {
+    return source_->DeliverEventToSink(const_cast<Event*>(event));
+  }
+
+  EventDispatchDetails DiscardEvent() override {
+    ui::EventDispatchDetails details;
+    details.event_discarded = true;
+    return details;
+  }
+
+ private:
+  EventSource* const source_;
+  EventRewriter* rewriter_;
+  EventRewriterList::iterator self_;
+
+  base::WeakPtrFactory<EventRewriterContinuationImpl> weak_ptr_factory_;
+  DISALLOW_COPY_AND_ASSIGN(EventRewriterContinuationImpl);
+};
+
 EventSource::EventSource() {}
 
 EventSource::~EventSource() {}
 
 void EventSource::AddEventRewriter(EventRewriter* rewriter) {
-  DCHECK(rewriter);
-  DCHECK(!base::ContainsValue(rewriter_list_, rewriter));
-  rewriter_list_.push_back(rewriter);
+  EventRewriterContinuationImpl::Create(this, rewriter);
 }
 
 void EventSource::RemoveEventRewriter(EventRewriter* rewriter) {
-  auto find = std::find(rewriter_list_.begin(), rewriter_list_.end(), rewriter);
-  if (find != rewriter_list_.end())
-    rewriter_list_.erase(find);
+  EventRewriterList::iterator it = FindContinuation(rewriter);
+  if (it == rewriter_list_.end()) {
+    // We need to tolerate attempting to remove an unregistered
+    // EventRewriter, because many unit tests currently do so:
+    // the rewriter gets added to the current root window source
+    // on construction, and removed from the current root window
+    // source on destruction, but the root window changes in
+    // between.
+    LOG(WARNING) << "EventRewriter not registered";
+    return;
+  }
+  rewriter_list_.erase(it);
 }
 
-EventDispatchDetails EventSource::SendEventToSink(Event* event) {
+EventDispatchDetails EventSource::SendEventToSink(const Event* event) {
   return SendEventToSinkFromRewriter(event, nullptr);
 }
 
@@ -50,62 +114,39 @@
 }
 
 EventDispatchDetails EventSource::SendEventToSinkFromRewriter(
-    Event* event,
+    const Event* event,
     const EventRewriter* rewriter) {
   std::unique_ptr<ui::Event> event_for_rewriting_ptr;
-  Event* event_for_rewriting = event;
+  const Event* event_for_rewriting = event;
   if (!rewriter_list_.empty() && IsLocatedEventWithDifferentLocations(*event)) {
     // EventRewriters don't expect an event with differing location and
     // root-location (because they don't honor the target). Provide such an
-    // event for rewriters.
+    // event.
     event_for_rewriting_ptr = ui::Event::Clone(*event);
     event_for_rewriting_ptr->AsLocatedEvent()->set_location_f(
         event_for_rewriting_ptr->AsLocatedEvent()->root_location_f());
     event_for_rewriting = event_for_rewriting_ptr.get();
   }
-  std::unique_ptr<Event> rewritten_event;
-  EventRewriteStatus status = EVENT_REWRITE_CONTINUE;
-  EventRewriterList::const_iterator it = rewriter_list_.begin(),
-                                    end = rewriter_list_.end();
-  // If a rewriter reposted |event|, only send it to subsequent rewriters.
-  bool send_to_rewriter = rewriter == nullptr;
-  for (; it != end; ++it) {
-    if (!send_to_rewriter) {
-      send_to_rewriter |= (*it == rewriter);
-      continue;
-    }
-    status = (*it)->RewriteEvent(*event_for_rewriting, &rewritten_event);
-    if (status == EVENT_REWRITE_DISCARD) {
-      CHECK(!rewritten_event);
-      EventDispatchDetails details;
-      details.event_discarded = true;
-      return details;
-    }
-    if (status == EVENT_REWRITE_CONTINUE) {
-      CHECK(!rewritten_event);
-      continue;
-    }
-    break;
+  EventRewriterList::iterator it = rewriter_list_.begin();
+  if (rewriter) {
+    // If a rewriter reposted |event|, only send it to subsequent rewriters.
+    it = FindContinuation(rewriter);
+    CHECK(it != rewriter_list_.end());
+    ++it;
   }
-  CHECK((it == end && !rewritten_event) || rewritten_event);
-  EventDispatchDetails details =
-      DeliverEventToSink(rewritten_event ? rewritten_event.get() : event);
-  if (details.dispatcher_destroyed)
-    return details;
+  if (it == rewriter_list_.end())
+    return DeliverEventToSink(const_cast<Event*>(event));
+  return (*it)->rewriter()->RewriteEvent(*event_for_rewriting,
+                                         (*it)->GetWeakPtr());
+}
 
-  while (status == EVENT_REWRITE_DISPATCH_ANOTHER) {
-    std::unique_ptr<Event> new_event;
-    status = (*it)->NextDispatchEvent(*rewritten_event, &new_event);
-    if (status == EVENT_REWRITE_DISCARD)
-      return EventDispatchDetails();
-    CHECK_NE(EVENT_REWRITE_CONTINUE, status);
-    CHECK(new_event);
-    details = DeliverEventToSink(new_event.get());
-    if (details.dispatcher_destroyed)
-      return details;
-    rewritten_event = std::move(new_event);
-  }
-  return EventDispatchDetails();
+EventSource::EventRewriterList::iterator EventSource::FindContinuation(
+    const EventRewriter* rewriter) {
+  auto it = find_if(
+      rewriter_list_.begin(), rewriter_list_.end(),
+      [rewriter](const std::unique_ptr<EventRewriterContinuationImpl>& p)
+          -> bool { return p->rewriter() == rewriter; });
+  return it;
 }
 
 }  // namespace ui
diff --git a/ui/events/event_source.h b/ui/events/event_source.h
index ad84e60..675b345 100644
--- a/ui/events/event_source.h
+++ b/ui/events/event_source.h
@@ -5,17 +5,19 @@
 #ifndef UI_EVENTS_EVENT_SOURCE_H_
 #define UI_EVENTS_EVENT_SOURCE_H_
 
+#include <list>
+#include <memory>
 #include <vector>
 
 #include "base/macros.h"
 #include "ui/events/event_dispatcher.h"
+#include "ui/events/event_rewriter.h"
 #include "ui/events/events_export.h"
 
 namespace ui {
 
 class Event;
 class EventSink;
-class EventRewriter;
 
 // EventSource receives events from the native platform (e.g. X11, win32 etc.)
 // and sends the events to an EventSink.
@@ -34,7 +36,7 @@
   void RemoveEventRewriter(EventRewriter* rewriter);
 
   // Sends the event through all rewriters and onto the source's EventSink.
-  EventDispatchDetails SendEventToSink(Event* event);
+  EventDispatchDetails SendEventToSink(const Event* event);
 
   // Send the event to the sink after rewriting; subclass overrides may queue
   // events before delivery, i.e. for the WindowService.
@@ -44,20 +46,34 @@
   // Sends the event through the rewriters and onto the source's EventSink.
   // If |rewriter| is valid, |event| is only sent to the subsequent rewriters.
   // This is used for asynchronous reposting of events processed by |rewriter|.
+  // TODO(kpschoedel): Remove along with old EventRewriter API.
   EventDispatchDetails SendEventToSinkFromRewriter(
-      Event* event,
+      const Event* event,
       const EventRewriter* rewriter);
 
  private:
-  friend class EventRewriter;
-  friend class EventSourceTestApi;
+  // Implementation of EventRewriterContinuation. No details need to be
+  // visible outside of event_source.cc.
+  class EventRewriterContinuationImpl;
 
-  typedef std::vector<EventRewriter*> EventRewriterList;
+  // It's sufficient to have one EventRewriterContinuationImpl for each
+  // registered EventRewriter, so a list of them also serves as a list
+  // of registered rewriters.
+  typedef std::list<std::unique_ptr<EventRewriterContinuationImpl>>
+      EventRewriterList;
+
+  // Returns the EventRewriterContinuation for a given EventRewriter,
+  // or |rewriter_list_.end()| if the rewriter is not registered.
+  EventRewriterList::iterator FindContinuation(const EventRewriter* rewriter);
+
   EventRewriterList rewriter_list_;
 
+  friend class EventRewriter;  // TODO(kpschoedel): Remove along with old API.
+  friend class EventSourceTestApi;
+
   DISALLOW_COPY_AND_ASSIGN(EventSource);
 };
 
 }  // namespace ui
 
-#endif // UI_EVENTS_EVENT_SOURCE_H_
+#endif  // UI_EVENTS_EVENT_SOURCE_H_
diff --git a/ui/events/test/test_event_rewriter.cc b/ui/events/test/test_event_rewriter.cc
index 3351a6c..a5bd81e 100644
--- a/ui/events/test/test_event_rewriter.cc
+++ b/ui/events/test/test_event_rewriter.cc
@@ -13,17 +13,11 @@
 
 TestEventRewriter::~TestEventRewriter() = default;
 
-ui::EventRewriteStatus TestEventRewriter::RewriteEvent(
+ui::EventDispatchDetails TestEventRewriter::RewriteEvent(
     const ui::Event& event,
-    std::unique_ptr<ui::Event>* new_event) {
+    const Continuation continuation) {
   ++events_seen_;
-  return ui::EVENT_REWRITE_CONTINUE;
-}
-
-ui::EventRewriteStatus TestEventRewriter::NextDispatchEvent(
-    const ui::Event& last_event,
-    std::unique_ptr<ui::Event>* new_event) {
-  return ui::EVENT_REWRITE_CONTINUE;
+  return SendEvent(continuation, &event);
 }
 
 }  // namespace test
diff --git a/ui/events/test/test_event_rewriter.h b/ui/events/test/test_event_rewriter.h
index 86512c88..bb25e041 100644
--- a/ui/events/test/test_event_rewriter.h
+++ b/ui/events/test/test_event_rewriter.h
@@ -21,12 +21,9 @@
   int events_seen() const { return events_seen_; }
 
   // ui::EventRewriter:
-  ui::EventRewriteStatus RewriteEvent(
+  ui::EventDispatchDetails RewriteEvent(
       const ui::Event& event,
-      std::unique_ptr<ui::Event>* new_event) override;
-  ui::EventRewriteStatus NextDispatchEvent(
-      const ui::Event& last_event,
-      std::unique_ptr<ui::Event>* new_event) override;
+      const Continuation continuation) override;
 
  private:
   int events_seen_ = 0;
diff --git a/ui/ozone/common/egl_util.cc b/ui/ozone/common/egl_util.cc
index 1e1679c..7336356 100644
--- a/ui/ozone/common/egl_util.cc
+++ b/ui/ozone/common/egl_util.cc
@@ -20,50 +20,53 @@
     FILE_PATH_LITERAL("libEGL.dll");
 const base::FilePath::CharType kDefaultGlesSoname[] =
     FILE_PATH_LITERAL("libGLESv2.dll");
-#if BUILDFLAG(ENABLE_SWIFTSHADER)
-const base::FilePath::CharType kGLESv2SwiftShaderLibraryName[] =
-    FILE_PATH_LITERAL("libGLESv2.dll");
-const base::FilePath::CharType kEGLSwiftShaderLibraryName[] =
-    FILE_PATH_LITERAL("libEGL.dll");
-#endif  // BUILDFLAG(ENABLE_SWIFTSHADER)
-
-#else
+#elif defined(OS_FUCHSIA)
+const base::FilePath::CharType kDefaultEglSoname[] =
+    FILE_PATH_LITERAL("libEGL.so");
+const base::FilePath::CharType kDefaultGlesSoname[] =
+    FILE_PATH_LITERAL("libGLESv2.so");
+#else   // !defined(OS_WIN) && !defined(OS_FUCHSIA)
 const base::FilePath::CharType kDefaultEglSoname[] =
     FILE_PATH_LITERAL("libEGL.so.1");
 const base::FilePath::CharType kDefaultGlesSoname[] =
     FILE_PATH_LITERAL("libGLESv2.so.2");
+#endif  // !defined(OS_WIN) && !defined(OS_FUCHSIA)
+
 #if BUILDFLAG(ENABLE_SWIFTSHADER)
+#if defined(OS_WIN)
 const base::FilePath::CharType kGLESv2SwiftShaderLibraryName[] =
-#if defined(OS_FUCHSIA)
-    FILE_PATH_LITERAL("libswiftshader_libGLESv2.so");
-#else
-    FILE_PATH_LITERAL("libGLESv2.so");
-#endif  // OS_FUCHSIA
+    FILE_PATH_LITERAL("libGLESv2.dll");
 const base::FilePath::CharType kEGLSwiftShaderLibraryName[] =
-#if defined(OS_FUCHSIA)
+    FILE_PATH_LITERAL("libEGL.dll");
+#elif defined(OS_FUCHSIA)
+const base::FilePath::CharType kGLESv2SwiftShaderLibraryName[] =
+    FILE_PATH_LITERAL("libswiftshader_libGLESv2.so");
+const base::FilePath::CharType kEGLSwiftShaderLibraryName[] =
     FILE_PATH_LITERAL("libswiftshader_libEGL.so");
-#else
+#else   // !defined(OS_WIN) && !defined(OS_FUCHSIA)
+const base::FilePath::CharType kGLESv2SwiftShaderLibraryName[] =
+    FILE_PATH_LITERAL("libGLESv2.so");
+const base::FilePath::CharType kEGLSwiftShaderLibraryName[] =
     FILE_PATH_LITERAL("libEGL.so");
-#endif  // OS_FUCHSIA
-
+#endif  // !defined(OS_WIN) && !defined(OS_FUCHSIA)
 #endif  // BUILDFLAG(ENABLE_SWIFTSHADER)
 
-#endif  // defined(OS_WIN)
-
 bool LoadEGLGLES2Bindings(const base::FilePath& egl_library_path,
                           const base::FilePath& gles_library_path) {
   base::NativeLibraryLoadError error;
   base::NativeLibrary gles_library =
       base::LoadNativeLibrary(gles_library_path, &error);
   if (!gles_library) {
-    LOG(ERROR) << "Failed to load GLES library: " << error.ToString();
+    LOG(ERROR) << "Failed to load GLES library: " << gles_library_path << ": "
+               << error.ToString();
     return false;
   }
 
   base::NativeLibrary egl_library =
       base::LoadNativeLibrary(base::FilePath(egl_library_path), &error);
   if (!egl_library) {
-    LOG(ERROR) << "Failed to load EGL library: " << error.ToString();
+    LOG(ERROR) << "Failed to load EGL library: " << egl_library_path << ": "
+               << error.ToString();
     base::UnloadNativeLibrary(gles_library);
     return false;
   }
diff --git a/ui/ozone/platform/drm/host/drm_overlay_manager_host.cc b/ui/ozone/platform/drm/host/drm_overlay_manager_host.cc
index b8a6b3793..a451980 100644
--- a/ui/ozone/platform/drm/host/drm_overlay_manager_host.cc
+++ b/ui/ozone/platform/drm/host/drm_overlay_manager_host.cc
@@ -66,7 +66,6 @@
   }
 
   size_t size = candidates->size();
-  base::AutoLock lock(cache_lock_);
   auto iter = cache_.Get(result_candidates);
   if (iter == cache_.end()) {
     // We can skip GPU side validation in case all candidates are invalid.
@@ -104,7 +103,6 @@
 }
 
 void DrmOverlayManagerHost::ResetCache() {
-  base::AutoLock lock(cache_lock_);
   cache_.Clear();
 }
 
@@ -126,7 +124,6 @@
   TRACE_EVENT_ASYNC_END0("hwoverlays",
                          "DrmOverlayManagerHost::SendOverlayValidationRequest",
                          this);
-  base::AutoLock lock(cache_lock_);
   auto iter = cache_.Peek(candidates);
   if (iter != cache_.end()) {
     iter->second.status = returns;
diff --git a/ui/ozone/platform/drm/host/drm_overlay_manager_host.h b/ui/ozone/platform/drm/host/drm_overlay_manager_host.h
index 84b82c6..848562c 100644
--- a/ui/ozone/platform/drm/host/drm_overlay_manager_host.h
+++ b/ui/ozone/platform/drm/host/drm_overlay_manager_host.h
@@ -11,7 +11,6 @@
 
 #include "base/containers/mru_cache.h"
 #include "base/macros.h"
-#include "base/synchronization/lock.h"
 #include "ui/ozone/platform/drm/common/drm_overlay_manager.h"
 #include "ui/ozone/platform/drm/host/gpu_thread_adapter.h"
 #include "ui/ozone/public/overlay_candidates_ozone.h"
@@ -74,12 +73,6 @@
   // for validation and/or validated.
   base::MRUCache<OverlaySurfaceCandidateList, OverlayValidationCacheValue>
       cache_;
-  // The cache can be accessed from multiple threads in some cases (e.g. with
-  // mus, it can be accessed from the UI thread, and the window-service
-  // thread.)
-  // TODO(rjkroege): In the future (with --enable-viz), this code will not need
-  // the lock, but will require farther refactoring.
-  base::Lock cache_lock_;
 
   DISALLOW_COPY_AND_ASSIGN(DrmOverlayManagerHost);
 };
diff --git a/ui/ozone/platform/scenic/scenic_window.cc b/ui/ozone/platform/scenic/scenic_window.cc
index 9f7c1aa..60537dc 100644
--- a/ui/ozone/platform/scenic/scenic_window.cc
+++ b/ui/ozone/platform/scenic/scenic_window.cc
@@ -29,8 +29,9 @@
       delegate_(delegate),
       window_id_(manager_->AddWindow(this)),
       event_dispatcher_(this),
+      view_listener_binding_(this),
       scenic_session_(manager_->GetScenic()),
-      view_(&scenic_session_, std::move(view_token), "chromium window"),
+      parent_node_(&scenic_session_),
       node_(&scenic_session_),
       input_node_(&scenic_session_),
       render_node_(&scenic_session_) {
@@ -39,9 +40,14 @@
   scenic_session_.set_event_handler(
       fit::bind_member(this, &ScenicWindow::OnScenicEvents));
 
+  // Import parent node and create event pair to pass to the ViewManager.
+  zx::eventpair parent_export_token;
+  parent_node_.BindAsRequest(&parent_export_token);
+
   // Subscribe to metrics events from the parent node. These events are used to
   // get the device pixel ratio for the screen.
-  view_.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask);
+  parent_node_.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask);
+  parent_node_.AddChild(node_);
 
   // Add input shape.
   input_node_.SetShape(scenic::Rectangle(&scenic_session_, 1.f, 1.f));
@@ -52,6 +58,15 @@
   render_node_.SetHitTestBehavior(fuchsia::ui::gfx::HitTestBehavior::kSuppress);
   node_.AddChild(render_node_);
 
+  // Create the view.
+  manager_->GetViewManager()->CreateView2(
+      view_.NewRequest(), std::move(view_token),
+      view_listener_binding_.NewBinding(), std::move(parent_export_token),
+      "Chromium");
+  view_.set_error_handler(fit::bind_member(this, &ScenicWindow::OnViewError));
+  view_listener_binding_.set_error_handler(
+      fit::bind_member(this, &ScenicWindow::OnViewError));
+
   // Call Present() to ensure that the scenic session commands are processed,
   // which is necessary to receive metrics event from Scenic.
   scenic_session_.Present(
@@ -89,7 +104,7 @@
 }
 
 void ScenicWindow::Show() {
-  view_.AddChild(node_);
+  parent_node_.AddChild(node_);
 }
 
 void ScenicWindow::Hide() {
@@ -190,6 +205,18 @@
   delegate_->OnBoundsChanged(size_rect);
 }
 
+void ScenicWindow::OnPropertiesChanged(
+    fuchsia::ui::viewsv1::ViewProperties properties,
+    OnPropertiesChangedCallback callback) {
+  if (properties.view_layout) {
+    size_dips_.SetSize(properties.view_layout->size.width,
+                       properties.view_layout->size.height);
+    if (device_pixel_ratio_ > 0.0)
+      UpdateSize();
+  }
+
+  callback();
+}
 
 void ScenicWindow::OnScenicError(zx_status_t status) {
   LOG(ERROR) << "scenic::Session failed with code " << status << ".";
@@ -200,52 +227,38 @@
     std::vector<fuchsia::ui::scenic::Event> events) {
   for (const auto& event : events) {
     if (event.is_gfx()) {
-      if (event.gfx().is_metrics()) {
-        if (event.gfx().metrics().node_id != node_.id())
-          continue;
-        OnViewMetrics(event.gfx().metrics().metrics);
-      } else if (event.gfx().is_view_properties_changed()) {
-        if (event.gfx().view_properties_changed().view_id != view_.id())
-          continue;
-        OnViewProperties(event.gfx().view_properties_changed().properties);
-      }
+      if (!event.gfx().is_metrics())
+        continue;
+
+      auto& metrics = event.gfx().metrics();
+      if (metrics.node_id != parent_node_.id())
+        continue;
+
+      device_pixel_ratio_ =
+          std::max(metrics.metrics.scale_x, metrics.metrics.scale_y);
+
+      ScenicScreen* screen = manager_->screen();
+      if (screen)
+        screen->OnWindowMetrics(window_id_, device_pixel_ratio_);
+
+      if (!size_dips_.IsEmpty())
+        UpdateSize();
     } else if (event.is_input()) {
-      OnInputEvent(event.input());
+      auto& input_event = event.input();
+      if (input_event.is_focus()) {
+        delegate_->OnActivationChanged(input_event.focus().focused);
+      } else {
+        // Scenic doesn't care if the input event was handled, so ignore the
+        // "handled" status.
+        ignore_result(event_dispatcher_.ProcessEvent(input_event));
+      }
     }
   }
 }
 
-void ScenicWindow::OnViewMetrics(const fuchsia::ui::gfx::Metrics& metrics) {
-  device_pixel_ratio_ = std::max(metrics.scale_x, metrics.scale_y);
-
-  ScenicScreen* screen = manager_->screen();
-  if (screen)
-    screen->OnWindowMetrics(window_id_, device_pixel_ratio_);
-
-  if (!size_dips_.IsEmpty())
-    UpdateSize();
-}
-
-void ScenicWindow::OnViewProperties(
-    const fuchsia::ui::gfx::ViewProperties& properties) {
-  float width = properties.bounding_box.max.x - properties.bounding_box.min.x -
-                properties.inset_from_min.x - properties.inset_from_max.x;
-  float height = properties.bounding_box.max.y - properties.bounding_box.min.y -
-                 properties.inset_from_min.y - properties.inset_from_max.y;
-
-  size_dips_.SetSize(width, height);
-  if (device_pixel_ratio_ > 0.0)
-    UpdateSize();
-}
-
-void ScenicWindow::OnInputEvent(const fuchsia::ui::input::InputEvent& event) {
-  if (event.is_focus()) {
-    delegate_->OnActivationChanged(event.focus().focused);
-  } else {
-    // Scenic doesn't care if the input event was handled, so ignore the
-    // "handled" status.
-    ignore_result(event_dispatcher_.ProcessEvent(event));
-  }
+void ScenicWindow::OnViewError(zx_status_t status) {
+  VLOG(1) << "viewsv1::View connection was closed with code " << status << ".";
+  delegate_->OnClosed();
 }
 
 void ScenicWindow::DispatchEvent(ui::Event* event) {
diff --git a/ui/ozone/platform/scenic/scenic_window.h b/ui/ozone/platform/scenic/scenic_window.h
index ad02cbf..3ea813f 100644
--- a/ui/ozone/platform/scenic/scenic_window.h
+++ b/ui/ozone/platform/scenic/scenic_window.h
@@ -5,10 +5,9 @@
 #ifndef UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_H_
 #define UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_H_
 
-#include <fuchsia/ui/input/cpp/fidl.h>
+#include <fuchsia/ui/viewsv1/cpp/fidl.h>
 #include <lib/ui/scenic/cpp/resources.h>
 #include <lib/ui/scenic/cpp/session.h>
-#include <lib/zx/eventpair.h>
 #include <string>
 #include <vector>
 
@@ -28,6 +27,7 @@
 class PlatformWindowDelegate;
 
 class OZONE_EXPORT ScenicWindow : public PlatformWindow,
+                                  public fuchsia::ui::viewsv1::ViewListener,
                                   public InputEventDispatcherDelegate {
  public:
   // Both |window_manager| and |delegate| must outlive the ScenicWindow.
@@ -65,20 +65,21 @@
   gfx::Rect GetRestoredBoundsInPixels() const override;
 
  private:
+  // views::ViewListener interface.
+  void OnPropertiesChanged(fuchsia::ui::viewsv1::ViewProperties properties,
+                           OnPropertiesChangedCallback callback) override;
+
   // Callbacks for |scenic_session_|.
   void OnScenicError(zx_status_t status);
   void OnScenicEvents(std::vector<fuchsia::ui::scenic::Event> events);
 
-  // Called from OnScenicEvents() to handle view properties and metrics changes.
-  void OnViewProperties(const fuchsia::ui::gfx::ViewProperties& properties);
-  void OnViewMetrics(const fuchsia::ui::gfx::Metrics& metrics);
-
-  // Called from OnScenicEvents() to handle input events.
-  void OnInputEvent(const fuchsia::ui::input::InputEvent& event);
-
   // InputEventDispatcher::Delegate interface.
   void DispatchEvent(ui::Event* event) override;
 
+  // Error handler for |view_|. This error normally indicates the View was
+  // destroyed (e.g. dropping ViewOwner).
+  void OnViewError(zx_status_t status);
+
   void UpdateSize();
 
   ScenicWindowManager* const manager_;
@@ -88,13 +89,17 @@
   // Dispatches Scenic input events as Chrome ui::Events.
   InputEventDispatcher event_dispatcher_;
 
+  // Underlying View in the view_manager.
+  fuchsia::ui::viewsv1::ViewPtr view_;
+  fidl::Binding<fuchsia::ui::viewsv1::ViewListener> view_listener_binding_;
+
   // Scenic session used for all drawing operations in this View.
   scenic::Session scenic_session_;
 
-  // The view resource in |scenic_session_|.
-  scenic::View view_;
+  // Node in |scenic_session_| for the parent view.
+  scenic::ImportNode parent_node_;
 
-  // Entity node for the |view_|.
+  // Node in |scenic_session_| for the parent view.
   scenic::EntityNode node_;
 
   // Node in |scenic_session_| for receiving input that hits within our View.
diff --git a/ui/ozone/platform/scenic/scenic_window_manager.cc b/ui/ozone/platform/scenic/scenic_window_manager.cc
index aeabc0ee..c19d20d 100644
--- a/ui/ozone/platform/scenic/scenic_window_manager.cc
+++ b/ui/ozone/platform/scenic/scenic_window_manager.cc
@@ -20,6 +20,18 @@
   return screen;
 }
 
+fuchsia::ui::viewsv1::ViewManager* ScenicWindowManager::GetViewManager() {
+  if (!view_manager_) {
+    view_manager_ = base::fuchsia::ServiceDirectoryClient::ForCurrentProcess()
+                        ->ConnectToService<fuchsia::ui::viewsv1::ViewManager>();
+    view_manager_.set_error_handler([](zx_status_t status) {
+      ZX_LOG(FATAL, status) << " ViewManager lost.";
+    });
+  }
+
+  return view_manager_.get();
+}
+
 fuchsia::ui::scenic::Scenic* ScenicWindowManager::GetScenic() {
   if (!scenic_) {
     scenic_ = base::fuchsia::ServiceDirectoryClient::ForCurrentProcess()
diff --git a/ui/ozone/platform/scenic/scenic_window_manager.h b/ui/ozone/platform/scenic/scenic_window_manager.h
index d7ee9a7..e219ace 100644
--- a/ui/ozone/platform/scenic/scenic_window_manager.h
+++ b/ui/ozone/platform/scenic/scenic_window_manager.h
@@ -5,10 +5,11 @@
 #ifndef UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_MANAGER_H_
 #define UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_MANAGER_H_
 
-#include <fuchsia/ui/scenic/cpp/fidl.h>
 #include <stdint.h>
 #include <memory>
 
+#include <fuchsia/ui/viewsv1/cpp/fidl.h>
+
 #include "base/containers/id_map.h"
 #include "base/macros.h"
 #include "base/threading/thread_checker.h"
@@ -35,9 +36,10 @@
 
   std::unique_ptr<PlatformScreen> CreateScreen();
 
-  // Scenic interface that is used by ScenicWindow instances. The interface
-  // is initialized lazily on the first call and it don't change afterwards.
-  // ScenicWindowManager keeps the ownership.
+  // ViewManager and Scenic services that are used by ScenicWindow. Both
+  // interfaces are initialized lazily on the first call and they don't change
+  // afterwards. ScenicWindowManager keeps the ownership.
+  fuchsia::ui::viewsv1::ViewManager* GetViewManager();
   fuchsia::ui::scenic::Scenic* GetScenic();
 
   // Called by ScenicWindow when a new window instance is created. Returns
@@ -56,6 +58,7 @@
 
   base::WeakPtr<ScenicScreen> screen_;
 
+  fuchsia::ui::viewsv1::ViewManagerPtr view_manager_;
   fuchsia::ui::scenic::ScenicPtr scenic_;
 
   DISALLOW_COPY_AND_ASSIGN(ScenicWindowManager);
diff --git a/ui/views/mus/BUILD.gn b/ui/views/mus/BUILD.gn
index 9b1c8c3..25f5634f 100644
--- a/ui/views/mus/BUILD.gn
+++ b/ui/views/mus/BUILD.gn
@@ -52,8 +52,6 @@
     "//cc",
     "//mojo/public/cpp/bindings",
     "//net",
-    "//services/catalog/public/cpp",
-    "//services/catalog/public/mojom:constants",
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/mojom",
     "//services/ws/public/cpp",
diff --git a/ui/views/mus/DEPS b/ui/views/mus/DEPS
index 87ed198a..aba0de2 100644
--- a/ui/views/mus/DEPS
+++ b/ui/views/mus/DEPS
@@ -6,7 +6,6 @@
   "+mojo/converters",
   "+mojo/core/embedder",
   "+mojo/public",
-  "+services/catalog/public",
   "+services/service_manager/public",
   "+services/ws",
   "+skia",
diff --git a/ui/views/mus/aura_init.cc b/ui/views/mus/aura_init.cc
index 97747a0..f7d65b6 100644
--- a/ui/views/mus/aura_init.cc
+++ b/ui/views/mus/aura_init.cc
@@ -10,8 +10,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/path_service.h"
 #include "build/build_config.h"
-#include "services/catalog/public/cpp/resource_loader.h"
-#include "services/catalog/public/mojom/constants.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "ui/aura/env.h"
 #include "ui/base/ime/input_method_initializer.h"
@@ -54,47 +52,11 @@
   mus_params.use_accessibility_host = params.use_accessibility_host;
   mus_client_ = std::make_unique<MusClient>(mus_params);
   ui::MaterialDesignController::Initialize();
-  if (!InitializeResources(params))
-    return false;
+
+  DCHECK(ui::ResourceBundle::HasSharedInstance());
 
   ui::InitializeInputMethodForTesting();
   return true;
 }
 
-bool AuraInit::InitializeResources(const InitParams& params) {
-  // Resources may have already been initialized (e.g. when chrome with mash is
-  // used to launch the current app).
-  if (ui::ResourceBundle::HasSharedInstance())
-    return true;
-
-  std::set<std::string> resource_paths({params.resource_file});
-  if (!params.resource_file_200.empty())
-    resource_paths.insert(params.resource_file_200);
-
-  catalog::ResourceLoader loader;
-  filesystem::mojom::DirectoryPtr directory;
-  params.connector->BindInterface(catalog::mojom::kServiceName, &directory);
-  // TODO(jonross): if this proves useful in resolving the crash of
-  // mash_unittests then switch AuraInit to have an Init method, returning a
-  // bool for success. Then update all callsites to use this to determine the
-  // shutdown of their ServiceContext.
-  // One cause of failure is that the peer has closed, but we have not been
-  // notified yet. It is not possible to complete initialization, so exit now.
-  // Calling services will shutdown ServiceContext as appropriate.
-  if (!loader.OpenFiles(std::move(directory), resource_paths))
-    return false;
-  if (params.register_path_provider)
-    ui::RegisterPathProvider();
-  base::File pak_file = loader.TakeFile(params.resource_file);
-  base::File pak_file_2 = pak_file.Duplicate();
-  ui::ResourceBundle::InitSharedInstanceWithPakFileRegion(
-      std::move(pak_file), base::MemoryMappedFile::Region::kWholeFile);
-  ui::ResourceBundle::GetSharedInstance().AddDataPackFromFile(
-      std::move(pak_file_2), ui::SCALE_FACTOR_100P);
-  if (!params.resource_file_200.empty())
-    ui::ResourceBundle::GetSharedInstance().AddDataPackFromFile(
-        loader.TakeFile(params.resource_file_200), ui::SCALE_FACTOR_200P);
-  return true;
-}
-
 }  // namespace views
diff --git a/ui/views/mus/aura_init.h b/ui/views/mus/aura_init.h
index dad4d1f..c1f83a6 100644
--- a/ui/views/mus/aura_init.h
+++ b/ui/views/mus/aura_init.h
@@ -67,9 +67,6 @@
   // services should shutdown.
   bool Init(const InitParams& params);
 
-  // Returns true on success.
-  bool InitializeResources(const InitParams& params);
-
   std::unique_ptr<aura::Env> env_;
   std::unique_ptr<MusClient> mus_client_;
   std::unique_ptr<ViewsDelegate> views_delegate_;